Skip to content

Robust packet reading #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 21, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion adafruit_bluefruit_connect/location_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class LocationPacket(Packet):
PACKET_LENGTH = struct.calcsize(_FMT_PARSE)
# _FMT_CONSTRUCT doesn't include the trailing checksum byte.
_FMT_CONSTRUCT = '<2sfff'
PACKET_LENGTH = struct.calcsize(_FMT_CONSTRUCT)
_TYPE_HEADER = b'!L'

def __init__(self, latitude, longitude, altitude):
Expand Down
31 changes: 22 additions & 9 deletions adafruit_bluefruit_connect/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ def from_bytes(cls, packet):
"""
if len(packet) < 3:
raise ValueError("Packet too short")
header = packet[0:2]
packet_class = cls._type_to_class.get(header, None)
packet_class = cls._type_to_class.get(packet[0:2], None)
if not packet_class:
raise ValueError("Unknown packet header '{}'".format(header))
raise ValueError("Unregistered packet type {}".format(header))

# In case this was called from a subclass, make sure the parsed
# type matches up with the current class.
Expand All @@ -103,14 +102,28 @@ def from_stream(cls, stream):
:param stream stream: an input stream that provides standard stream read operations,
such as ``ble.UARTServer`` or ``busio.UART``.
"""
header = stream.read(2)
if len(header) != 2 or header[0] != ord(b'!'):
# Remove any other junk already read.
stream.reset_input_buffer()
return None
# Loop looking for a b'!' packet start. If the buffer has overflowed,
# or there's been some other problem, we may need to skip some characters
# to get to a packet start.
while True:
start = stream.read(1)
if not start:
# Timeout: nothing read.
return None
if start == b'!':
# Found start of packet.
packet_type = stream.read(1)
if not packet_type:
# Timeout: nothing more read.
return None
else:
break;
# Didn't find a packet start. Loop and try again.

header = start + packet_type
packet_class = cls._type_to_class.get(header, None)
if not packet_class:
raise ValueError("Unknown packet header {}".format(header))
raise ValueError("Unregistered packet type {}".format(header))
packet = header + stream.read(packet_class.PACKET_LENGTH - 2)
return cls.from_bytes(packet)

Expand Down