Compare commits

..

2 Commits

Author SHA1 Message Date
Tom Hensel
e4ab81d95a
Merge 3bbd43cc1b into 760ab981d0 2024-11-21 13:51:19 +01:00
gretel
3bbd43cc1b Fix KISS beacon frame formatting and add sync pattern
Two issues were resolved with KISS interface beacon transmissions:

1. Fixed frame length handling to meet minimum length requirements (15 bytes) for
   TNCs like Direwolf. Previously, raw beacon data was being sent directly,
   causing frame length errors:

```
<<< Data frame from KISS client application, channel 0, total length = 11
  000:  c0 00 44 4e 39 54 54 2d 31 35 c0                 ..FOOBAR-15.
Frame length 8 not in allowable range of 15 to 2123.
ERROR - Invalid KISS data frame from client app.
```

2. Added standard 0xAA 0xAA sync pattern to improve radio modem synchronization
   and compatibility with packet radio protocols like FX.25 and IL2P.

This ensures:
- Proper frame length for TNC compatibility
- Better bit synchronization with standard sync pattern
- Improved reception reliability
- Compatible with both KISS TNCs and packet radio protocols

```
<<< Data frame from KISS client application, channel 0, total length = 18
  000:  c0 00 aa aa 44 4e 39 54 54 2d 31 35 00 00 00 00  ....FOOBAR-15....
  010:  00 c0                                            ..
[0L 21:25:43 UTC] (Not AX.25)<0xaa><0xaa>FOOBAR-15<0x00><0x00><0x00><0x00><0x00>
IL2P frame, max_fec = 1, 49 encoded bytes total
  000:  f1 5e 48 87 b8 59 b7 a1 cc 24 57 d6 0b 36 7c f1  .^H..Y...$W..6|.
  010:  7c d5 af 85 db 12 99 80 9d b8 6b bb 6b 05 df 1e  |.........k.k...
  020:  69 0e d8 69 05 f6 ff c4 24 fa 58 f7 e7 f2 a4 df  i..i....$.X.....
  030:  a1                                               .
```
2024-11-19 20:55:16 +01:00
14 changed files with 49 additions and 60 deletions

View File

@ -80,7 +80,7 @@ class AX25KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None txtail = int(c["txtail"]) if "txtail" in c else None

View File

@ -85,7 +85,7 @@ class KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None txtail = int(c["txtail"]) if "txtail" in c else None
@ -97,7 +97,7 @@ class KISSInterface(Interface):
databits = int(c["databits"]) if "databits" in c else 8 databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N" parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1 stopbits = int(c["stopbits"]) if "stopbits" in c else 1
beacon_interval = int(c["beacon_interval"]) if "beacon_interval" in c and c["beacon_interval"] != None else None beacon_interval = int(c["beacon_interval"]) if "beacon_interval" in c else None
beacon_data = c["beacon_data"] if "beacon_data" in c else None beacon_data = c["beacon_data"] if "beacon_data" in c else None
self.HW_MTU = 564 self.HW_MTU = 564

View File

@ -343,24 +343,24 @@ class RNodeInterface(Interface):
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
allow_bluetooth = c.as_bool("allow_bluetooth") if "allow_bluetooth" in c else False allow_bluetooth = c["allow_bluetooth"]
target_device_name = c["target_device_name"] if "target_device_name" in c else None target_device_name = c["target_device_name"]
target_device_address = c["target_device_address"] if "target_device_address" in c else None target_device_address = c["target_device_address"]
ble_name = c["ble_name"] if "ble_name" in c else None ble_name = c["ble_name"]
ble_addr = c["ble_addr"] if "ble_addr" in c else None ble_addr = c["ble_addr"]
force_ble = c["force_ble"] if "force_ble" in c else False force_ble = c["force_ble"]
frequency = int(c["frequency"]) if "frequency" in c else 0 frequency = int(c["frequency"]) if "frequency" in c else None
bandwidth = int(c["bandwidth"]) if "bandwidth" in c else 0 bandwidth = int(c["bandwidth"]) if "bandwidth" in c else None
txpower = int(c["txpower"]) if "txpower" in c else 0 txpower = int(c["txpower"]) if "txpower" in c else None
sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else 0 sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
cr = int(c["codingrate"]) if "codingrate" in c else 0 cr = int(c["codingrate"]) if "codingrate" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False flow_control = c.as_bool("flow_control") if "flow_control" in c else False
id_interval = int(c["id_interval"]) if "id_interval" in c and c["id_interval"] != None else None id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None id_callsign = c["id_callsign"] if "id_callsign" in c else None
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c and c["airtime_limit_short"] != None else None st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c and c["airtime_limit_long"] != None else None lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
port = c["port"] if "port" in c else None port = c["port"] if "port" in c else None
import importlib import importlib

View File

@ -75,7 +75,7 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
port = c["port"] if "port" in c else None port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600 speed = int(c["speed"]) if "speed" in c else 9600

View File

@ -88,7 +88,7 @@ class AutoInterface(Interface):
return socket.if_nametoindex(ifname) return socket.if_nametoindex(ifname)
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
group_id = c["group_id"] if "group_id" in c else None group_id = c["group_id"] if "group_id" in c else None
discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None
@ -97,7 +97,7 @@ class AutoInterface(Interface):
data_port = int(c["data_port"]) if "data_port" in c else None data_port = int(c["data_port"]) if "data_port" in c else None
allowed_interfaces = c.as_list("devices") if "devices" in c else None allowed_interfaces = c.as_list("devices") if "devices" in c else None
ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None
configured_bitrate = c["configured_bitrate"] if "configured_bitrate" in c else None configured_bitrate = c["configured_bitrate"]
from RNS.vendor.ifaddr import niwrapper from RNS.vendor.ifaddr import niwrapper
super().__init__() super().__init__()

View File

@ -834,14 +834,14 @@ class I2PInterface(Interface):
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
rns_storagepath = c["storagepath"] rns_storagepath = c["storagepath"]
peers = c.as_list("peers") if "peers" in c else None peers = c.as_list("peers") if "peers" in c else None
connectable = c.as_bool("connectable") if "connectable" in c else False connectable = c.as_bool("connectable") if "connectable" in c else False
ifac_size = c["ifac_size"] if "ifac_size" in c else None ifac_size = c["ifac_size"]
ifac_netname = c["ifac_netname"] if "ifac_netname" in c else None ifac_netname = c["ifac_netname"]
ifac_netkey = c["ifac_netkey"] if "ifac_netkey" in c else None ifac_netkey = c["ifac_netkey"]
self.HW_MTU = 1064 self.HW_MTU = 1064

View File

@ -24,7 +24,6 @@ import RNS
import time import time
import threading import threading
from collections import deque from collections import deque
from RNS.vendor.configobj import ConfigObj
class Interface: class Interface:
IN = False IN = False
@ -240,14 +239,3 @@ class Interface:
def detach(self): def detach(self):
pass pass
@staticmethod
def get_config_obj(config_in):
if type(config_in) == ConfigObj:
return config_in
else:
try:
return ConfigObj(config_in)
except Exception as e:
RNS.log(f"Could not parse supplied configuration data. The contained exception was: {e}", RNS.LOG_ERROR)
raise SystemError("Invalid configuration data supplied")

View File

@ -73,7 +73,7 @@ class KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None txtail = int(c["txtail"]) if "txtail" in c else None
@ -339,8 +339,9 @@ class KISSInterface(Interface):
RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG) RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG)
self.first_tx = None self.first_tx = None
# Pad to minimum length # Using standard HDLC flag or sync bytes
frame = bytearray(self.beacon_d) frame = bytearray([0xAA, 0xAA]) # Standard sync pattern
frame.extend(self.beacon_d)
while len(frame) < 15: while len(frame) < 15:
frame.append(0x00) frame.append(0x00)

View File

@ -54,7 +54,7 @@ class PipeInterface(Interface):
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
command = c["command"] if "command" in c else None command = c["command"] if "command" in c else None
respawn_delay = c.as_float("respawn_delay") if "respawn_delay" in c else None respawn_delay = c.as_float("respawn_delay") if "respawn_delay" in c else None

View File

@ -132,18 +132,18 @@ class RNodeInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
frequency = int(c["frequency"]) if "frequency" in c else 0 frequency = int(c["frequency"]) if "frequency" in c else None
bandwidth = int(c["bandwidth"]) if "bandwidth" in c else 0 bandwidth = int(c["bandwidth"]) if "bandwidth" in c else None
txpower = int(c["txpower"]) if "txpower" in c else 0 txpower = int(c["txpower"]) if "txpower" in c else None
sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else 0 sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
cr = int(c["codingrate"]) if "codingrate" in c else 0 cr = int(c["codingrate"]) if "codingrate" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False flow_control = c.as_bool("flow_control") if "flow_control" in c else False
id_interval = int(c["id_interval"]) if "id_interval" in c else None id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None id_callsign = c["id_callsign"] if "id_callsign" in c else None
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
force_ble = False force_ble = False
ble_name = None ble_name = None

View File

@ -188,7 +188,7 @@ class RNodeMultiInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
count = 0 count = 0

View File

@ -63,7 +63,7 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
port = c["port"] if "port" in c else None port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600 speed = int(c["speed"]) if "speed" in c else 9600

View File

@ -85,10 +85,10 @@ class TCPClientInterface(Interface):
def __init__(self, owner, configuration, connected_socket=None): def __init__(self, owner, configuration, connected_socket=None):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
target_ip = c["target_host"] if "target_host" in c else None target_ip = c["target_host"]
target_port = int(c["target_port"]) if "target_port" in c else None target_port = int(c["target_port"])
kiss_framing = False kiss_framing = False
if "kiss_framing" in c and c.as_bool("kiss_framing") == True: if "kiss_framing" in c and c.as_bool("kiss_framing") == True:
kiss_framing = True kiss_framing = True
@ -468,7 +468,7 @@ class TCPServerInterface(Interface):
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
device = c["device"] if "device" in c else None device = c["device"] if "device" in c else None
port = int(c["port"]) if "port" in c else None port = int(c["port"]) if "port" in c else None

View File

@ -48,7 +48,7 @@ class UDPInterface(Interface):
def __init__(self, owner, configuration): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration) c = configuration
name = c["name"] name = c["name"]
device = c["device"] if "device" in c else None device = c["device"] if "device" in c else None
port = int(c["port"]) if "port" in c else None port = int(c["port"]) if "port" in c else None