The following example reads data from the UART. In my case, the delimiter where packet starts with b '\x02' everything works, but the problem appears when b '\x02' appears in the packet and it is not the beginning of the packet because uart data often comes in one string. I will add that the packet that needs to be read always starts with b '\x02\x84' the only question is how to check if the first byte b '\x02’ followed by b '\x84' and if so then do a split.
Sample package consisting of several and with the problem:
\x02\x84"\x00\x19\x03\x00l\xe0\x02D\x00\x02\x84"\x00\x19\x03\x00l
I want to get two as handle_packet:
b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00'
b'\x84"\x00\x19\x03\x00l'
rx_buff = bytes()
while True:
recv = reader.read(-1)
if not recv:
continue
rx_buff += recv
packets = rx_buff.split(bytes(b'\x02'))
for packet in packets:
if not packet:
continue
msg = mod.handle_packet(packet)
if (msg):
get_response(msg)
rx_buff = (bytes() if mod.handle_packet(packet) else packet)
I spent a little more time reading. If you do it this way, your problem is going to be the first packet you split, because, I am assuming it doesn't follow the splitting pattern b'\x02\x84". If that is the case, you can just take the first of split_bytes and remove the first byte.
my_bytes = b'\x02\x84"\x00\x19\x03\x00l\xe0\x02D\x00\x02\x84"\x00\x19\x03\x00l'
split_bytes = my_bytes.split(b'\x02\x84"')
packets = []
for e in split_bytes:
if e != b'':
packets.append(b'\x84"' + e)
print(packets)
Yields:
[b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00', b'\x84"\x00\x19\x03\x00l']
Your desired packets:
[b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00', b'\x84"\x00\x19\x03\x00l']
If I am missing something, please point it out.
Related
I'm in a CTF competition and I'm stuck on a challenge where I have to retrieve a string from a socket, reverse it and get it back. The string changes too fast to do it manually. I'm able to get the string and reverse it but am failing at sending it back. I'm pretty sure I'm either trying to do something that's not possible or am just too inexperienced at Python/sockets/etc. to kung fu my way through.
Here's my code:
import socket
aliensocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
aliensocket.connect(('localhost', 10000))
aliensocket.send('GET_KEY'.encode())
key = aliensocket.recv(1024)
truncKey = str(key)[2:16]
revKey = truncKey[::-1]
print(truncKey)
print(revKey)
aliensocket.send(bytes(revKey.encode('UTF-8')))
print(aliensocket.recv(1024))
aliensocket.close()
And here is the output:
F9SIJINIK4DF7M
M7FD4KINIJIS9F
b'Server expects key to unlock or GET_KEY to retrieve the reversed key'
key is received as a byte string. The b'' wrapped around it when printed just indicates it is a byte string. It is not part of the string. .encode() turns a Unicode string into a byte string, but you can just mark a string as a byte string by prefixing with b.
Just do:
aliensocket.send(b'GET_KEY')
key = aliensocket.recv(1024)
revKey = truncKey[::-1]
print(truncKey) # or do truncKey.decode() if you don't want to see b''
print(revKey)
aliensocket.send(revKey)
data = ''
while True:
chunk = aliensocket.recv(1)
data +=chunk
if not chunk:
rev = data[::-1]
aliensocket.sendall(rev)
break
I am debugging packets sent from a device with pyserial. The packets have a specific terminator pattern to differentiate between packets of data. The pattern is a large number (0x3423fe67). I am able to receive bytes and concatenate them as they come in with the code below.
ser = serial.Serial(
ports="/dev/ttyUSB0",
baudrate=115200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
y = b''
while True:
bytes = ser.inWaiting()
if bytes > 0:
x = ser.read(bytes)
y += binascii.hexify(x)
print(y)
I can see the pattern I'm looking for but how do I grab the packet and terminator once I see the terminator. I tried indexing the bytes object but that returns strange values. Everything received before the terminator is part of the packet.
Here is code that accumulates packets in a list. The code can be used as a guide.
The serialData is data that would be received over the serial port as an example (i.e. ser.read() which would replace the for piece in x: loop). Note that an arbitrary number of bytes can be received, and the test variable n is only used to test the algorithm at arbitrary incoming received character lengths.
The term variable needed hexlify to match the hexlify on the incoming data.
import binascii
import re
term = binascii.hexlify(b'\x34\x23\xfe\x67')
serialData = b'packet0\x34\x23\xfe\x67packet1\x34\x23\xfe\x67'
n = 5
x = [serialData[i:i+n] for i in range(0, len(serialData), n)]
y = b''
packets = []
for piece in x:
y += binascii.hexlify(piece)
for i in re.finditer(term, y):
packets.append(y[:i.start()])
y = y[i.end():]
print('packets = ', packets)
hey am trying to pull image from web server using socket programming in python while going through python for everyone book there is example in networked programming chapter i copied the code from example urljpeg.py
import socket
import time
#HOST = 'data.pr4e.org'
#PORT = 80
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('data.pr4e.org', 80))
mysock.sendall(b'GET http://data.pr4e.org/cover3.jpg HTTP/1.0\r\n\r\n')
count = 0
picture = b""
while True:
data = mysock.recv(5120)
if len(data) < 1: break
# time .sleep(0.25)
count = count + len(data)
print( len(data),count)
picture = picture + data
mysock.close()
# look for the end of the header (2crlf)
pos = picture.find(b"r\n\r\n")
print("Header length ", pos)
print(picture[:pos].decode())
# skip pasr the header and save the picture data
picture = picture[pos+4:]
fhand = open("stuff.jpg","wb")
fhand.write(picture)
fhand.close()
The error message indicates that you are trying to decode data which is not utf-8. So why is this happening? Let's take a step back and look at what the code is doing:
# look for the end of the header (2crlf)
pos = picture.find(b"r\n\r\n")
print("Header length ", pos)
print(picture[:pos].decode())
We're trying to find a sequence of \r\n\r\n, i.e. CR LF CR LF in the data. This would be the empty line that separates the HTTP header (which should be in ASCII, which is a subset of UTF-8) from the actual image data. Then we try to decode everything up to that point as a string. So why does it fail? The program conveniently prints the header length, and in the bit you posted earlier we could see that this was -1, which means that the picture.find call did not find anything! Why not? Well, look carefully at what the code actually does:
# look for the end of the header (2crlf)
pos = picture.find(b"r\n\r\n")
It should be looking for \r\n\r\n, but it is actually looking for r\n\r\n!
Using a raspberry pi I am having issues reading data that is being transmitted serially. My code was working when I tested it on a different machine but isn't working now.
The baud rate is 9600 w/ no parity, 8 data bits, 1 stop bit and I want the program to handle a variable length of characters (Sometimes 100K+). The reading portion of the code is as follows:
ser = serial.Serial('/dev/ttyAMA0', 9600, parity = serial.PARITY_NONE, timeout=1)
While True:
data = ser.read(1)
bytesToRead = ser.inWaiting()
if bytesToRead:
data = data + ser.read(bytesToRead)
encodedData = data.encode('hex')
With this code, Shouldn't I be able to read all the characters as Hex as long as the baud/parity/etc match up with the transmitting system?
While True:
data = ser.read(1)
This waits for a single character to be read (times out after 1s due to the timeout specified in the Serial constructor) and stores it in data
bytesToRead = ser.inWaiting()
if bytesToRead:
data = data + ser.read(bytesToRead)
encodedData = data.encode('hex')
Now instantly check for any other characters in buffer - this will usually be zero. Due to the fact that you're running at 9600 baud, Python will usually see the characters come in one at a time. So your if bytesToRead statement will mostly be false as each incoming character is consumed by the above ser.read(1).
If you just want to process each character individually, you can do:
While True:
data = ser.read(1)
if data:
encodedData = data.encode('hex')
Or if you want to keep adding it to a buffer, use something like:
data = ''
While True:
bytesToRead = ser.inWaiting()
if bytesToRead:
data += ser.read(bytesToRead)
encodedData = data.encode('hex')
if encodedData.startswith('1234deadb33f`):
data = data[6:] # strip 6 chars from start of data
I send some data from an arduino using pySerial.
My Data looks like
bytearray(DST, SRC, STATUS, TYPE, CHANNEL, DATA..., SIZEOFDATA)
where sizeofData is a test that all bytes are received.
The problem is, every time when a byte is zero, my python program just stops reading there:
serial_port = serial.Serial("/dev/ttyUSB0")
while serial_port.isOpen():
response_header_str = serial_port.readline()
format = '>';
format += ('B'*len(response_header_str));
response_header = struct.unpack(format, response_header_str)
pprint(response_header)
serial_port.close()
For example, when I send bytearray(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) everything is fine. But when I send something like bytearray(1,2,3,4,0,1,2,3,4) I don't see everything beginning with the zero.
The problem is that I cannot avoid sending zeros as I am just sending the "memory dump" e.g. when I send a float value, there might be zero bytes.
how can I tell pyserial not to ignore zero bytes.
I've looked through the source of PySerial and the problem is in PySerial's implementation of FileLike.readline (in http://svn.code.sf.net/p/pyserial/code/trunk/pyserial/serial/serialutil.py). The offending function is:
def readline(self, size=None, eol=LF):
"""\
Read a line which is terminated with end-of-line (eol) character
('\n' by default) or until timeout.
"""
leneol = len(eol)
line = bytearray()
while True:
c = self.read(1)
if c:
line += c
if line[-leneol:] == eol:
break
if size is not None and len(line) >= size:
break
else:
break
return bytes(line)
With the obvious problem being the if c: line. When c == b'\x00' this evaluates to false, and the routine breaks out of the read loop. The easiest thing to do would be to reimplement this yourself as something like:
def readline(port, size=None, eol="\n"):
"""\
Read a line which is terminated with end-of-line (eol) character
('\n' by default) or until timeout.
"""
leneol = len(eol)
line = bytearray()
while True:
line += port.read(1)
if line[-leneol:] == eol:
break
if size is not None and len(line) >= size:
break
return bytes(line)
To clarify from your comments, this is a replacement for the Serial.readline method that will consume null-bytes and add them to the returned string until it hits the eol character, which we define here as "\n".
An example of using the new method, with a file-object substituted for the socket:
>>> # Create some example data terminated by a newline containing nulls.
>>> handle = open("test.dat", "wb")
>>> handle.write(b"hell\x00o, w\x00rld\n")
>>> handle.close()
>>>
>>> # Use our readline method to read it back in.
>>> handle = open("test.dat", "rb")
>>> readline(handle)
'hell\x00o, w\x00rld\n'
Hopefully this makes a little more sense.