Beter error detection in encoding LoRa RX frames

master
marcel 2 years ago
parent e4d02adc55
commit 118d7f4009
  1. 64
      RPi-LoRa-KISS-TNC/KissHelper.py

@ -29,6 +29,7 @@
# Changes by PE1RXF
#
# 2022-01-23: - in encode_address() added correct handling of has_been_repeated flag '*'
# 2022-01-28: - in encode_kiss() and encode_address(): better exeption handling for corrupted or mal-formatted APRS frames
#
import struct
@ -56,12 +57,23 @@ def encode_address(s, final):
# print("Message has been repeated")
ssid = ssid[:-1]
encoded_ssid |= 0b10000000
encoded_ssid |= (int(ssid) << 1) | 0b01100000 | (0b00000001 if final else 0)
# If SSID was not pressent (and we added the default -0 to it), the has_been_repeated flag could be at the end of the call, so check that as well
# Also, there is a lot of bad software around (including this code) and ignorance of the specifications (are there any specs for LoRa APRS?), so always check for the has_been_repeated flag
if call[-1] == 42:
call = call[:-1]
encoded_ssid |= 0b10000000
# SSID should now be one or two postions long and contain a number (idealy between 0 and 15).
if len(ssid) == 1 and ssid[0] > 47 and ssid[0] < 58:
encoded_ssid |= (int(ssid) << 1) | 0b01100000 | (0b00000001 if final else 0)
elif len(ssid) == 2 and ssid[0] > 47 and ssid[0] < 58 and ssid[1] > 47 and ssid[2] < 58:
encoded_ssid |= (int(ssid) << 1) | 0b01100000 | (0b00000001 if final else 0)
else:
return None
return encoded_call + [encoded_ssid]
def decode_address(data, cursor):
(a1, a2, a3, a4, a5, a6, a7) = struct.unpack("<BBBBBBB", data[cursor:cursor + 7])
hrr = a7 >> 5
@ -74,22 +86,56 @@ def decode_address(data, cursor):
call = addr
return (call, hrr, ext)
########################################################################
# Encode string from LoRa radio to AX.25 over KISS
#
# We must make no assumptions as the incomming frame could be carbage.
# So make sure we think of everthing in order to prevent crashes.
#
# The original code from Thomas Kottek did a good job encoding propper APRS frames.
# But when the frames where not what they should be, the program could crash.
#
########################################################################
def encode_kiss(frame):
# Ugly frame disassembling
# First check: do we have a semi column (seperator path field and data field)
# Note that we could still be wrong: for example when the field seperator is corrupted and we now find a semi column from, lets say, an internet address in the data field...
if not b":" in frame:
return None
# Split the frame in a path field and a data field
path = frame.split(b":")[0]
data_field = frame[frame.find(b":") + 1:]
# The source address is always followed by a greather than sign, so lets see if its there.
# There is always a change that there is another greather than sign because the frame could be corrupted...
if not b">" in path:
return None
# Split the path into a source address and a digi-path array (because digis should be seperated by commas, but again, corruption....)
src_addr = path.split(b">")[0]
digis = path[path.find(b">") + 1:].split(b",")
# destination address
packet = encode_address(digis.pop(0).upper(), False)
return_value = encode_address(digis.pop(0).upper(), False)
if return_value is None:
return None
packet = return_value
# source address
packet += encode_address(path.split(b">")[0].upper(), len(digis) == 0)
return_value = encode_address(src_addr.upper(), len(digis) == 0)
if return_value is None:
return None
packet += return_value
# digipeaters
for digi in digis:
final_addr = digis.index(digi) == len(digis) - 1
packet += encode_address(digi.upper(), final_addr)
return_value = encode_address(digi.upper(), final_addr)
if return_value is None:
return None
packet += return_value
# control field
packet += [0x03] # This is an UI frame
# protocol ID

Loading…
Cancel
Save