change frame reader for TCP

This commit is contained in:
Florent
2026-02-12 21:19:11 -04:00
parent 0e5d0dec2e
commit b8294cfb2f
2 changed files with 45 additions and 24 deletions

View File

@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "meshcore" name = "meshcore"
version = "2.2.8" version = "2.2.9"
authors = [ authors = [
{ name="Florent de Lamotte", email="florent@frizoncorrea.fr" }, { name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
{ name="Alex Wolden", email="awolden@gmail.com" }, { name="Alex Wolden", email="awolden@gmail.com" },

View File

@@ -18,12 +18,12 @@ class TCPConnection:
self.port = port self.port = port
self.transport = None self.transport = None
self.frame_started = False self.frame_started = False
self.frame_size = 0
self.header = b""
self.inframe = b""
self._disconnect_callback = None self._disconnect_callback = None
self._send_count = 0 self._send_count = 0
self._receive_count = 0 self._receive_count = 0
self.frame_expected_size = 0
self.header = b""
self.inframe = b""
class MCClientProtocol(asyncio.Protocol): class MCClientProtocol(asyncio.Protocol):
def __init__(self, cx): def __init__(self, cx):
@@ -68,28 +68,49 @@ class TCPConnection:
self.reader = reader self.reader = reader
def handle_rx(self, data: bytearray): def handle_rx(self, data: bytearray):
headerlen = len(self.header) if len(self.header) == 0: # did not find start of frame yet
framelen = len(self.inframe) # search start of frame (0x3e) in data
if not self.frame_started: # wait start of frame idx = data.find(b"\x3e")
if len(data) >= 3 - headerlen: if idx < 0: # no start of frame
self.header = self.header + data[: 3 - headerlen] return
self.frame_started = True self.header = data[0:1]
self.frame_size = int.from_bytes(self.header[1:], byteorder="little") data = data[1:]
self.handle_rx(data[3 - headerlen :])
else: if len(self.header) < 3: # header not complete yet
self.header = self.header + data while len(self.header) < 3 and len(data) > 0:
else: self.header = self.header + data[0:1]
if framelen + len(data) < self.frame_size: data = data[1:]
self.inframe = self.inframe + data if len(self.header) < 3: # still not complete
else: return
self.inframe = self.inframe + data[: self.frame_size - framelen]
if self.reader is not None: # get size and check
asyncio.create_task(self.reader.handle_rx(self.inframe)) self.frame_expected_size = int.from_bytes(self.header[1:], "little", signed=False)
self.frame_started = False if self.frame_expected_size > 300 : # invalid size
# reset inframe
self.header = b"" self.header = b""
self.inframe = b"" self.inframe = b""
if framelen + len(data) > self.frame_size: self.frame_expected_size = 0
self.handle_rx(data[self.frame_size - framelen :]) if len(data) > 0: # rerun handle_rx on remaining data
self.handle_rx(data)
return
upbound = self.frame_expected_size - len(self.inframe)
if len(data) < upbound :
self.inframe = self.inframe + data
# frame not complete, wait for next rx
return
self.inframe = self.inframe + data[0:upbound]
data = data[upbound:]
if self.reader is not None:
# feed meshcore reader
asyncio.create_task(self.reader.handle_rx(self.inframe))
# reset inframe
self.inframe = b""
self.header = b""
self.frame_expected_size = 0
if len(data) > 0: # rerun handle_rx on remaining data
self.handle_rx(data)
async def send(self, data): async def send(self, data):
if not self.transport: if not self.transport: