Reputation: 11
I've been trying to cobble together a solution to this problem from various related threads but I can't seem to get them working together. A lot of the posts I find seem to be dealing with ascii/binary values, and my problem relates to translating hex values. I'm new to Python, and I've been struggling with the syntax.
System: Windows 10. Python 3.6. IDE is Spyder.
Issue: I'm communicating with a device over an RS232 serial port that only communicates in hex. I've managed to successfully send a command to the device using the pySerial module and receive a reply, but I can't figure out how to convert the reply into a parseable format for the next step in my workflow.
Code so far:
import serial
import sys
port = "COM3"
baud = 9600
bytesize=8
parity='N'
stopbits=1
timeout=10 # this timeout is large due to another problem I'm having, but
didn't want to complicate this post with.
# Commands
# open the serial port
ser = serial.Serial(port, baud, bytesize, parity, stopbits, timeout)
if ser.isOpen():
print(ser.name + ' is open...')
# Query. This sends an 'are you awake' message to the device.
ser.write(bytearray.fromhex("23 00 00 80 B0 00 00 01"))
The above command is being sent to the device as a "byte-like object" according to Python, which displays as the format: b'\x23\x00\x00\x80\xb0\x00\x00\x01'
print('Receiving...')
# wait for timeout before displaying what was read. The device returns a
variable number of bytes each time it communicates, and I haven't figured
out a way to handle that yet.
out = ser.read()
print(out)
ser.close()
print(port+' is closed.')
This is where my problem is. ser.read() returns another byte-like object. For example, from the above ser.write() command: b'\x13\x11'. These are in fact the values I'm expecting from this command (hex values of "13" and "11"), I just don't know how to handle them now.
What I want to do is parse out the long string of returned hex characters (when I send a non-query command this will be 250+ characters, delimited by "\x") into individual array elements that I can then manipulate/replace/convert back into decimal integer values. I'll eventually be wanting to convert these hex values into their decimal equivalents and writing those decimal values to a CSV text file, so that I can later plot the values.
I've tried (these are not sequential commands, it's a list of attempted commands):
out = ser.readline()
out.split("\x")
out.split("\")
out.split("\\")
out_string = out.decode("utf-8")
binascii.hexlify(out)
binascii.hexlify(bytearray(out))
...and others I can't remember.
Please, any help you can offer would be greatly appreciated. This feels like it should be a simple thing to do, and my poor computer is running out of memory with all the tabs I have open. Thank you in advance to anyone who replies.
Upvotes: 0
Views: 5217
Reputation: 355
Your out is a sequence of bytes. If you want to read out a specific number of bytes only you could just use
out = ser.read(n) # where n is the number of bytes you want e.g. n = 8
Your out should look something like this:
out = b'\x21\x45\xed\xca\xfe' # I chose random values here
So to get a list of int's you can do:
for b in out:
int_list.append(b)
or
int_list = [b for b in out]
If you want byte pairs you can do (not sure if this is the best way though):
for i in range(0,len(out),2): # loop to every second value
pair = out[i].to_bytes(1,'little')+out[i+1].to_bytes(1,'little') # the first argument refers to the number of bytes and the second to the endianess.
print(pair)
That produces the following for me:
>>> b = b'\x32\x34\xe8\x90\x32\xab'
>>> for i in range(0,len(out),2):
... pair = out[i].to_bytes(1,'little')+out[i+1].to_bytes(1,'little')
... print(pair)
...
b'24'
b'\xe8\x90'
b'2\xab'
if you search for specific error bytes e.g. e = b'\xff' you can do
if e in out:
do_substitute(e with your byte value)
Upvotes: 0