Added support for fragmenting packets

Packets larger the HW_MTU will be fragmented on transmit and reassembled
on receive.
This commit is contained in:
Chad Attermann 2024-03-07 15:15:44 -07:00
parent ec3ce575f6
commit 1b6db308c9

View File

@ -1,8 +1,8 @@
from .Interface import Interface from .Interface import Interface
from pubsub import pub from pubsub import pub
import time import os
import sys import struct
import RNS import RNS
try: try:
@ -11,6 +11,9 @@ try:
class MeshtasticInterface(Interface): class MeshtasticInterface(Interface):
FLAG_SPLIT = 0x01
SEQ_UNSET = 0xFF
@staticmethod @staticmethod
def onReceive(packet, interface): def onReceive(packet, interface):
if packet['decoded']['portnum'] == "PRIVATE_APP": if packet['decoded']['portnum'] == "PRIVATE_APP":
@ -38,6 +41,10 @@ try:
self.bitrate = 5469 self.bitrate = 5469
self.bitrate_kbps = 5.47 self.bitrate_kbps = 5.47
self.buffer = None
self.sequence = 0xFF
self.ready = False
self.interface = None self.interface = None
try: try:
@ -62,20 +69,106 @@ try:
RNS.log("Initialized Meshtastic interface!", RNS.LOG_DEBUG) RNS.log("Initialized Meshtastic interface!", RNS.LOG_DEBUG)
def processIncoming(self, data): def processIncoming(self, data):
RNS.log("Received Meshtastic packet "+RNS.prettyhexrep(data), RNS.LOG_DEBUG) RNS.log("Received Meshtastic packet of "+str(len(data))+" bytes: "+RNS.prettyhexrep(data), RNS.LOG_DEBUG)
self.rxb += len(data) self.rxb += len(data)
self.owner.inbound(data, self)
# check for fragmented packet
header = data[0]
split = (header & self.FLAG_SPLIT) == self.FLAG_SPLIT
sequence = header >> 1
RNS.log("incoming sequence: "+str(sequence), RNS.LOG_DEBUG)
if split and self.sequence == self.SEQ_UNSET:
# This is the first part of a split
# packet, so we set the self.sequence variable
# and add the data to the buffer.
self.buffer = data[1:]
self.sequence = sequence
#last_rssi = LoRa.packetRssi();
#last_snr_raw = LoRa.packetSnrRaw();
elif split and self.sequence == sequence:
# This is subsequent part of a split
# packet, so we add it to the buffer.
self.buffer += data[1:]
#last_rssi = (last_rssi+LoRa.packetRssi())/2;
#last_snr_raw = (last_snr_raw+LoRa.packetSnrRaw())/2;
elif not split and self.sequence == sequence:
# This is not a split packet but it carries
# the last sequence id, so it must be the
# last part of a split packet.
self.buffer += data[1:]
self.sequence = self.SEQ_UNSET
#last_rssi = LoRa.packetRssi();
#last_snr_raw = LoRa.packetSnrRaw();
# pass the buffer on to RNS
RNS.log("Received Reticulum packet of "+str(len(self.buffer))+" bytes over Meshtastic interface", RNS.LOG_DEBUG)
self.owner.inbound(self.buffer, self)
self.buffer = None
elif split and self.sequence != sequence:
# This split packet does not carry the
# same sequence id, so we must assume
# that we are seeing the first part of
# a new split packet.
# If we already had part of a split
# packet in the buffer then we clear it.
if self.buffer != None:
RNS.log("Discarding incomplete buffer from previous split packet!", RNS.LOG_ERROR)
self.buffer = data[1:]
self.sequence = sequence
#last_rssi = LoRa.packetRssi();
#last_snr_raw = LoRa.packetSnrRaw();
elif not split:
# This is not a split packet, so we
# just read it whole
self.buffer = data[1:]
self.sequence = self.SEQ_UNSET
#last_rssi = LoRa.packetRssi();
#last_snr_raw = LoRa.packetSnrRaw();
# pass the buffer on to RNS
RNS.log("Received Reticulum packet of "+str(len(self.buffer))+" bytes over Meshtastic interface", RNS.LOG_DEBUG)
self.owner.inbound(self.buffer, self)
self.buffer = None
def processOutgoing(self, data): def processOutgoing(self, data):
if self.interface == None: if self.interface == None:
return return
RNS.log("Sending Meshtastic packet "+RNS.prettyhexrep(data), RNS.LOG_DEBUG) RNS.log("Sending Reticulum packet of "+str(len(data))+" bytes over Meshtastic interface", RNS.LOG_DEBUG)
try:
#self.interface.sendData(data) header = int.from_bytes(os.urandom(1), "big") & 0xFE
self.interface.sendData(data, portNum=256, channelIndex=self.channel) RNS.log("outgoing sequence: "+str(header >> 1), RNS.LOG_DEBUG)
self.txb += len(data) if len(data) > self.HW_MTU-1:
except Exception as e: header |= self.FLAG_SPLIT
RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
sent = 0
while sent < len(data):
size = len(data) - sent
if size > self.HW_MTU-1:
size = self.HW_MTU-1
# clear split flag for last part
if sent+size >= len(data):
header &= ~self.FLAG_SPLIT
buffer = struct.pack("!B", header) + data[sent:sent+size]
sent += size
RNS.log("Sending Meshtastic packet of "+str(len(buffer))+" bytes: "+RNS.prettyhexrep(buffer), RNS.LOG_DEBUG)
try:
#self.interface.sendData(buffer)
self.interface.sendData(buffer, portNum=256, channelIndex=self.channel)
self.txb += len(buffer)
except Exception as e:
RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
def __str__(self): def __str__(self):
if self.port == None: if self.port == None: