Reading from COM port into a text file in python - python-2.7

I have a list of commands saved in text file ('command.log') which I want to run against a unit connected to 'COM5' and save the response for each command in a text file ('output.log'). The script gets stuck on the first command and I could get it to run the remaining commands. Any help will be appreciated.
import serial
def cu():
ser = serial.Serial(
port='COM5',
timeout=None,
baudrate=115200,
parity='N',
stopbits=1,
bytesize=8
)
ser.flushInput()
ser.flushOutput()
## ser.write('/sl/app_config/status \r \n') #sample command
fw = open('output.log','w')
with open('data\command.log') as f:
for line in f:
ser.write(line + '\r\n')
out = ''
while out != '/>':
out += ser.readline()
fw.write(out)
print(out)
fw.close()
ser.close()
print "Finished ... "
cu()

The bytes problem
First of all, you're misusing the serial.readline function: it returns a bytes object, and you act like it was a str object, by doing out += ser.readline(): a TypeError will be raised. Instead, you must write out += str(ser.readline(), 'utf-8'), which first converts the bytes into a str.
How to check when the transmission is ended ?
Now, the problem lays in the out != '/>' condition: I think you want to test if the message sent by the device is finished, and this message ends with '/<'. But, in the while loop, you do out += [...], so in the end of the message, out is like '<here the message>/>', which is totally different from '/>'. However, you're lucky: there is the str.endswith function! So, you must replace while out != '\>' by while not out.endswith('\>'.
WWhatWhat'sWhat's theWhat's the f*** ?
Also, in your loop, you write the whole message, if it's not already ended, in each turn. This will give you, in output.log, something like <<me<mess<messag<messag<message>/>. Instead, I think you want to print only the received characters. This can be achieved using a temporary variable.
Another issue
And, you're using the serial.readline function: accordingly to the docstrings,
The line terminator is always b'\n'
It's not compatible with you're code: you want your out to finish with "\>", instead, you must use only serial.read, which returns all the received characters.
Haaaa... the end ! \o/
Finally, your while loop will look as follows:
# Check if the message is already finished
while not out.endswith('/>'):
# Save the last received characters
# A `bytes` object is encoded in 'utf-8'
received_chars = str(ser.read(), 'utf-8')
# Add them to `out`
out += received_chars
# Log them
fw.write(received_chars)
# Print them, without ending with a new line, more "user-friendly"
print(received_chars, end='')
# Finally, print a new line for clarity
print()

Related

Continuing the loop

Ok so I have code that is supposed to run through a txt file and ping the Ip's if the ping is equal to 0 its does an 'nslookup' on it and then it's supposed to continue but after it does the first one in the terminal it's left on a > as if waiting for input. In other instances, my code runs through the txt file fine but once I added in the 'nslookup' it stops after the first one and waits for input.
Is there a way to make it continue to cycle through the txt file till it gets to the end?
Heres the code I'm using I know there are other ways to do a look up on an Ip address but I'm trying to use 'nslookup' in this case unless its impossible.
import os
with open('test.txt','r') as f:
for line in f:
response = os.system("ping -c 1 " + line)
if response == 0:
print os.system('nslookup')
else:
print(line, "is down!")
that's simply because you forgot to pass the argument to nslookup
When you don't pass any argument, the program starts in interactive mode with its own shell.
L:\so>nslookup
Default server : mydomain.server.com
Address: 128.1.34.82
>
But using os.system won't make you able to get the output of the command. For that you would need
output = subprocess.check_output(['nslookup',line.strip()])
print(output) # or do something else with it
instead of your os.system command

python run external program and print output by character

How can I print out the output of an external command by characters or at least by lines?
This code prints it in one block after the command returns.
import subprocess as sub
output, errors = sub.Popen(command, stdout=sub.PIPE, stderr=sub.PIPE, shell=True).communicate()
print output + errors
You can access to the standart output stream as
p = sub.Popen("cmd", stdout=sub.PIPE, stderr=sub.PIPE)
print(p.stdout.readline()) # This read a line
You can perform any operation o the file streams.
When you use readline in a standart output of a proccess the main thread of the app wait for that proccess to write some thing on the ouput. When that process write to the output you program continue.
You must know that before read a line from the proceess you need to call flush() on the stream. Because the streams have a cache time before the real values are written to it.
You can see this post, this is a good explanation of how this work on python
http://www.cyberciti.biz/faq/python-execute-unix-linux-command-examples/
import subprocess
p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
while True:
out = p.stderr.read(1)
if out == '' and p.poll() != None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
It prints out the output of the cmd character by character.

c++ macro for saving enum element names and values to file

Normally I try to avoid the use of macros, so I actually don't know how to use them beyond the very most basic ones, but I'm trying to do some meta-manipulation so I assume macros are needed.
I have an enum listing various log entries and their respective id, e.g.
enum LogID
{
LOG_ID_ITEM1=0,
LOG_ID_ITEM2,
LOG_ID_ITEM3=10,
...
}
which is used within my program when writing data to the log file. Note that they will not, in general, be in any order.
I do most of my log file post-processing in Matlab so I'd like to write the same variable names and values to a file for Matlab to load in. e.g., a file looking like
LOG_ID_ITEM1=0;
LOG_ID_ITEM2=1;
LOG_ID_ITEM3=10;
...
I have no idea how to go about doing this, but it seems like it shouldn't be too complicated. If it helps, I am using c++11.
edit:
For clarification, I'm not looking for the macro itself to write the file. I want a way to store the enum element names and values as strings and ints somehow so I can then use a regular c++ function to write everything to file. I'm thinking the macro might then be used to build up the strings and values into vectors? Does that work? If so, how?
I agree with Adam Burry that a separate script is likely best for this. Not sure which languages you're familiar with, but here's a quick Python script that'll do the job:
#!/usr/bin/python
'''Makes a .m file from an enum in a C++ source file.'''
from __future__ import print_function
import sys
import re
def parse_cmd_line():
'''Gets a filename from the first command line argument.'''
if len(sys.argv) != 2:
sys.stderr.write('Usage: enummaker [cppfilename]\n')
sys.exit(1)
return sys.argv[1]
def make_m_file(cpp_file, m_file):
'''Makes an .m file from enumerations in a .cpp file.'''
in_enum = False
enum_val = 0
lines = cpp_file.readlines()
for line in lines:
if in_enum:
# Currently processing an enumeration
if '}' in line:
# Encountered a closing brace, so stop
# processing and reset value counter
in_enum = False
enum_val = 0
else:
# No closing brace, so process line
if '=' in line:
# If a value is supplied, use it
ev_string = re.match(r'[^=]*=(\d+)', line)
enum_val = int(ev_string.group(1))
# Write output line to file
e_out = re.match(r'[^=\n,]+', line)
m_file.write(e_out.group(0).strip() + '=' +
str(enum_val) + ';\n')
enum_val += 1
else:
# Not currently processing an enum,
# so check for an enum definition
enumstart = re.match(r'enum \w+ {', line)
if enumstart:
in_enum = True
def main():
'''Main function.'''
# Get file names
cpp_name = parse_cmd_line()
m_name = cpp_name.replace('cpp', 'm')
print('Converting ' + cpp_name + ' to ' + m_name + '...')
# Open the files
try:
cpp_file = open(cpp_name, 'r')
except IOError:
print("Couldn't open " + cpp_name + ' for reading.')
sys.exit(1)
try:
m_file = open(m_name, 'w')
except IOError:
print("Couldn't open " + m_name + ' for writing.')
sys.exit(1)
# Translate the cpp file
make_m_file(cpp_file, m_file)
# Finish
print("Done.")
cpp_file.close()
m_file.close()
if __name__ == '__main__':
main()
Running ./enummaker.py testenum.cpp on the following file of that name:
/* Random code here */
enum LogID {
LOG_ID_ITEM1=0,
LOG_ID_ITEM2,
LOG_ID_ITEM3=10,
LOG_ID_ITEM4
};
/* More random code here */
enum Stuff {
STUFF_ONE,
STUFF_TWO,
STUFF_THREE=99,
STUFF_FOUR,
STUFF_FIVE
};
/* Yet more random code here */
produces a file testenum.m containing the following:
LOG_ID_ITEM1=0;
LOG_ID_ITEM2=1;
LOG_ID_ITEM3=10;
LOG_ID_ITEM4=11;
STUFF_ONE=0;
STUFF_TWO=1;
STUFF_THREE=99;
STUFF_FOUR=100;
STUFF_FIVE=101;
This script assumes that the closing brace of an enum block is always on a separate line, that the first identifier is defined on the line following the opening brace, that there are no blank lines between the braces, that enum appears at the start of a line, and that there is no space following the = and the number. Easy enough to modify the script to overcome these limitations. You could have your makefile run this automatically.
Have you considered "going the other way"? It usually makes more sense to maintain your data definitions in a (text) file, then as part of your build process you can generate a C++ header and include it. Python and mako is a good tool for doing this.

How to print the current line of source at breakpoint in GDB and nothing else?

I want to set a "rolling" breakpoint in gdb; there just print the current source line with some info; and then continue. I start with something like this:
break doSomething
commands
continue
end
This, on its own, prints out:
Breakpoint 1, doSomething () at myprog.c:55
55 void doSomething() {
I wanted to remove the "Breakpoint X ... at ..." message, which can be done with silent - and then printout just the source line; so I tried:
break doSomething
commands
silent
list
continue
end
This results with 10 lines of listing, like below
50 // some comments
...
55 void doSomething() {
...
59 // other comments
The problem is, saying list 1 will again give 10 lines, just starting from the first line; while doing list +0,+0 will indeed provide one line of source only - but the wrong line (in my case, it gives line 50).
So, then I realized that one can get and print the current program address by using the program counter $pc - and given that one can also list around a program address, I tried this:
break doSomething
commands
silent
#print $pc
list *$pc,+0
continue
end
This results with correct source line - but for some reason, again with an extra message, this time "ADDR is in X ..." :
0x8048fe0 is in doSomething (myprog.c:55).
55 void doSomething() {
Any ideas how to get only the source line to print?
As a sub-question - is it possible somehow to capture the output of the list command, and use it as an argument to printf in the gdb scripting dialect? (I'm pretty sure capturing gdb command output can be done through the python gdb scripting, though)...
Well, I think I got somewhere better with gdb's Python; now I can get the output to look like this (using gdb 7.3.50.20110806-cvs):
[ 56] 0x8048fe0 myprog.c:55 void doSomething() {
[ 56] 0x8049058 myprog.c:63 }
For the most part, I tried to use Symbol-Tables-In-Python to get to this (turns out there was an SO question about this, too: gdb find memory address of line number).
But, for some reason, when I use Symtab_and_line.line, which "Indicates the current line number for this object", it doesn't seem to change? In the above example, it is the first number in square brackets, and sits constantly at 56 (and is wrong in both cases). One would have hoped that the API would have had all that covered; and while the line number is there (albeit wrong?) - I couldn't find the string content of the respective source code line, as an object attribute, anywhere. On the other hand, when I use gdb.execute("list *$pc,+0") to query gdb directly about the current line as per OP, I get correct line numbers - but then, I have to additionally split and parse strings in Python :/
Still, better than nothing - here's the (Python embedded in gdb script) code; just throw it in your .gdbinit:
python
# example: these breakpoints do stop - but cannot change their
# stop method (which contains the "commands" for breakpoint in python)
#ax = gdb.Breakpoint("doSomething")
#print("hello", ax)
#print(dir(ax))
#print(ax.expression, ax.condition, ax.commands) # not writable!
#bx = gdb.Breakpoint("myprog.c:63")
# anything more than that - need to subclass:
class MyBreakpoint(gdb.Breakpoint):
def __init__(self, spec, command=""):
super(MyBreakpoint, self).__init__(spec, gdb.BP_BREAKPOINT,
internal = False)
self.command = command # not used
def stop(self):
# gdb.write - like print
# gdb.decode_line() - like gdb.find_pc_line(pc)
current_line = gdb.decode_line()
symtline = current_line[1][0]
#print(current_line, symtline.is_valid(), symtline.line , symtline.pc , symtline.symtab )
sysy = symtline.symtab
#print(sysy.filename, sysy.fullname(), sysy.is_valid() )
sysyo = sysy.objfile
#print(sysyo.filename, sysyo.is_valid(), sysyo.pretty_printers)
###print(gdb.solib_name()) # this breaks stuff??!
sourcefilename = sysy.filename
sourcefullpath = sysy.fullname()
sourcelinenum = symtline.line # somehow, it may be offset by 1, from what "list *$pc says"
listingline = gdb.execute("list *$pc,+0", to_string=True)
#print( "BREAK at %s:%d -- %s" % (sourcefilename, sourcelinenum, listingline) )
llsplit = listingline.split("\n")
listpreamble, gdbsourceline = llsplit[:2]
addr, noneed, noneed, funcname, fileloc = listpreamble.split(" ")[:5]
#linenum, sourceline = gdbsourceline.split("\t")[:2] # not using these - put gdb line verbatim
outline = "[% 4s] %s % 16s:%s" % (sourcelinenum, addr, sourcefilename[-16:], gdbsourceline)
print(outline)
return False # continue (do not stop inferior)
ax = MyBreakpoint("doSomething")
bx = MyBreakpoint("myprog.c:63")
end
run

How to replace string in multiple files in the folder?

I m trying to read two files and replace content of one file with content of other file in files present in folder which also has sub directories.
But its tell sub process not defined.
i'm new to python and shell script can anybody help me with this please?
import os
import sys
import os.path
f = open ( "file1.txt",'r')
g = open ( "file2.txt",'r')
text1=f.readlines()
text2=g.readlines()
i = 0;
for line in text1:
l = line.replace("\r\n", "")
t = text2[i].replace("\r\n", "")
args = "find . -name *.tml"
Path = subprocess.Popen( args , shell=True )
os.system(" sed -r -i 's/" + l + "/" + t + "/g' " + Path)
i = i + 1;
To specifically address your actual error, you need to import the subprocess module as you are making use of it (oddly) in your code:
import subprocess
After that, you will find more problems. I will try and keep it as simple as possible with my suggestions. Code first, then I will break it down. Keep in mind, there are more robust ways to accomplish this task. But I am doing my best to keep in mind your experience level and making it make your current approach as closely as possible.
import subprocess
import sys
# 1
results = subprocess.Popen("find . -name '*.tml'",
shell=True, stdout=subprocess.PIPE)
if results.wait() != 0:
print "error trying to find tml files"
sys.exit(1)
# 2
tml_files = []
for tml in results.stdout:
tml_files.append(tml.strip())
if not tml_files:
print "no tml files found"
sys.exit(0)
tml_string = " ".join(tml_files)
# 3
with open ("file1.txt") as f, open("file2.txt") as g:
while True:
# 4
f_line = f.readline()
if not f_line:
break
g_line = g.readline()
if not g_line:
break
f_line = f_line.strip()
g_line = g_line.strip()
if not f_line or not g_line:
continue
# 5
cmd = "sed -i -e 's/%s/%s/g' %s" % \
(f_line.strip(), g_line.strip(), tml_string)
ret = subprocess.Popen(cmd, shell=True).wait()
if ret != 0:
print "error doing string replacement"
sys.exit(1)
You do not need to read in your entire files at once. If they are large this could be a lot of memory. You can consume a line at a time, and you can also make use of what is called "context managers" when you open the files. This will ensure they close properly no matter what happens:
We start with a subprocess command that is run only once to find all your .tml files. Your version had the same command being run multiple times. If the search path is the same, then we only need it once. This checks the exit code of the command and quits if it failed.
We loop over stdout on the subprocess command, and add the stripped lines to a list. This is a more robust way of your replace("\r\n"). It removes whitespace. A "list comprehension" would be better suited here (down the line). If we didn't find any tml files, then we have no work to do, so we exit. Otherwise, we join them together in a space-separated string to be suitable for our command later.
This is called "context managers". You can open the file in a way that no matter what they will be closed properly. The file is open for the length of the context within that code block. We are going to loop forever, and break when appropriate.
We pull a line, one at a time, from each file. If either line is blank, we reached the end of the file and cannot do any more work, so we break out. We then strip the newlines, and if either string is empty (blank line) we still can't do any work, but we just continue to the next available line.
A modified version of your sed command. We construct the command string on each loop for the source and replacement strings, and tack on the tml file string. Bear in mind this is a very naive approach to the replacement. It really expects your replacement strings to be safe characters and not break the s///g sed format. But we run that with another subprocess command. The wait() simply waits for the return code, and we check it for an error. This approach replaces your os.system() version.
Hope this helps. Eventually you can improve this to do more checking and safe operations.