From d34cf68736b50b7d9d9b573ece620e9645458510 Mon Sep 17 00:00:00 2001 From: "jacob.eva" Date: Tue, 4 Jun 2024 08:27:55 +0100 Subject: [PATCH] Added dynamic config file support --- RNS/Interfaces/RNodeMultiInterface.py | 73 +++++++++++++++------------ RNS/Reticulum.py | 67 ++++++++++++++++-------- 2 files changed, 86 insertions(+), 54 deletions(-) diff --git a/RNS/Interfaces/RNodeMultiInterface.py b/RNS/Interfaces/RNodeMultiInterface.py index f7ab56e..265cc42 100644 --- a/RNS/Interfaces/RNodeMultiInterface.py +++ b/RNS/Interfaces/RNodeMultiInterface.py @@ -28,9 +28,6 @@ import time import math import RNS -# debug -import traceback - class KISS(): FEND = 0xC0 FESC = 0xDB @@ -172,6 +169,17 @@ class KISS(): case KISS.CMD_INT11_DATA: return 11 + def interface_type_to_str(interface_type): + match interface_type: + case KISS.SX1262: + return "SX1262" + case KISS.SX1276: + return "SX1276" + case KISS.SX1278: + return "SX1278" + case KISS.SX1280: + return "SX1280" + @staticmethod def escape(data): data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd])) @@ -191,6 +199,8 @@ class RNodeMultiInterface(Interface): RECONNECT_WAIT = 5 + MAX_SUBINTERFACES = 11 + def __init__(self, owner, name, port, subint_config, id_interval = None, id_callsign = None): if RNS.vendor.platformutils.is_android(): raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android") @@ -236,7 +246,7 @@ class RNodeMultiInterface(Interface): self.first_tx = None self.reconnect_w = RNodeMultiInterface.RECONNECT_WAIT - self.subinterfaces = [] + self.subinterfaces = [0] * RNodeMultiInterface.MAX_SUBINTERFACES self.subinterface_indexes = [] self.subinterface_types = [] self.subint_config = subint_config @@ -330,22 +340,31 @@ class RNodeMultiInterface(Interface): RNS.log("Serial port "+self.port+" is now open") RNS.log("Creating subinterfaces...", RNS.LOG_VERBOSE) - for subint in self.subinterface_indexes: + index = None + for subint in self.subint_config: + for subint_type in self.subinterface_types: + if subint[0] == subint_type: + index = self.subinterface_types.index(subint_type) + + # The interface type configured is not present on the RNode + if index is None: + raise ValueError("Interface type \""+subint[0]+"\" is not available on "+self.name) + # interface will add itself to the subinterfaces list automatically - interface = (RNodeSubInterface( + interface = RNodeSubInterface( RNS.Transport, self, - subint, - self.subinterface_types[subint], - frequency = self.subint_config[subint][0], - bandwidth = self.subint_config[subint][1], - txpower = self.subint_config[subint][2], - sf = self.subint_config[subint][3], - cr = self.subint_config[subint][4], - flow_control=self.subint_config[subint][5], - st_alock=self.subint_config[subint][6], - lt_alock=self.subint_config[subint][7] - )) + index, + subint[0], + frequency = subint[1], + bandwidth = subint[2], + txpower = subint[3], + sf = subint[4], + cr = subint[5], + flow_control=subint[6], + st_alock=subint[7], + lt_alock=subint[8] + ) interface.OUT = True interface.IN = self.IN @@ -816,7 +835,7 @@ class RNodeMultiInterface(Interface): if (len(command_buffer) == 2): # add the interface to the back of the lists self.subinterface_indexes.append(command_buffer[0]) - self.subinterface_types.append(command_buffer[1]) + self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1])) command_buffer = b"" else: @@ -904,7 +923,7 @@ class RNodeSubInterface(Interface): Q_SNR_MAX = 6 Q_SNR_STEP = 2 - def __init__(self, owner, parent_interface, index, subinterface_type, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, st_alock = None, lt_alock = None,): + def __init__(self, owner, parent_interface, index, interface_type, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, st_alock = None, lt_alock = None,): if RNS.vendor.platformutils.is_android(): raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android") @@ -959,21 +978,11 @@ class RNodeSubInterface(Interface): sel_cmd = KISS.CMD_SEL_INT0 data_cmd= KISS.CMD_INT0_DATA - match subinterface_type: - case KISS.SX1262: - subinterface = "SX1262" - case KISS.SX1276: - subinterface = "SX1276" - case KISS.SX1278: - subinterface = "SX1278" - case KISS.SX1280: - subinterface = "SX1280" - self.owner = owner self.index = index self.sel_cmd = sel_cmd self.data_cmd = data_cmd - self.subinterface= subinterface + self.interface_type= interface_type self.flow_control= flow_control self.speed = 115200 self.databits = 8 @@ -1028,7 +1037,7 @@ class RNodeSubInterface(Interface): self.parent_interface = parent_interface # add this interface to the subinterfaces array - self.parent_interface.subinterfaces.append(self) + self.parent_interface.subinterfaces.insert(index, self) self.validcfg = True if (self.frequency < RNodeSubInterface.FREQ_MIN or self.frequency > RNodeSubInterface.FREQ_MAX): @@ -1184,4 +1193,4 @@ class RNodeSubInterface(Interface): self.interface_ready = True def __str__(self): - return self.parent_interface.name+"["+self.subinterface+":"+str(self.index)+"]" + return self.parent_interface.name+"["+self.interface_type+":"+str(self.index)+"]" diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 21d8aaf..edd4adf 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -934,44 +934,67 @@ class Reticulum: if c["type"] == "RNodeMultiInterface": count = 0 + enabled_count = 0 + + # Count how many interfaces are in the file for subinterface in c: # if the retrieved entry is not a string, it must be a dictionary, which is what we want if not isinstance(c[subinterface], str): count += 1 - # create an array with a row for each subinterface - subint_config = [[0 for x in range(8)] for y in range(count)] - subint_index = 0 - + # Count how many interfaces are enabled to allow for appropriate matrix sizing for subinterface in c: # if the retrieved entry is not a string, it must be a dictionary, which is what we want if not isinstance(c[subinterface], str): subinterface_config = self.config["interfaces"][name][subinterface] + if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): + enabled_count += 1 - frequency = int(subinterface_config["frequency"]) if "frequency" in subinterface_config else None - subint_config[subint_index][0] = frequency - bandwidth = int(subinterface_config["bandwidth"]) if "bandwidth" in subinterface_config else None - subint_config[subint_index][1] = bandwidth - txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None - subint_config[subint_index][2] = txpower - spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None - subint_config[subint_index][3] = spreadingfactor - codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None - subint_config[subint_index][4] = codingrate - flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False - subint_config[subint_index][5] = flow_control - st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None - subint_config[subint_index][6] = st_alock - lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None - subint_config[subint_index][7] = lt_alock - subint_index += 1 + # Create an array with a row for each subinterface + subint_config = [[0 for x in range(9)] for y in range(enabled_count)] + subint_index = 0 + + for subinterface in c: + # If the retrieved entry is not a string, it must be a dictionary, which is what we want + if not isinstance(c[subinterface], str): + subinterface_config = self.config["interfaces"][name][subinterface] + if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): + subint_type = subinterface_config["type"] if "type" in subinterface_config else None + if subint_type is None: + raise ValueError("No type defined for "+name+" subinterface!") + + subint_config[subint_index][0] = subint_type + frequency = int(subinterface_config["frequency"]) if "frequency" in subinterface_config else None + subint_config[subint_index][1] = frequency + bandwidth = int(subinterface_config["bandwidth"]) if "bandwidth" in subinterface_config else None + subint_config[subint_index][2] = bandwidth + txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None + subint_config[subint_index][3] = txpower + spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None + subint_config[subint_index][4] = spreadingfactor + codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None + subint_config[subint_index][5] = codingrate + flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False + subint_config[subint_index][6] = flow_control + st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None + subint_config[subint_index][7] = st_alock + lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None + subint_config[subint_index][8] = lt_alock + subint_index += 1 + + # if no subinterfaces are defined + if count == 0: + raise ValueError("No subinterfaces configured for "+name) + # if no subinterfaces are enabled + elif enabled_count == 0: + raise ValueError("No subinterfaces enabled for "+name) 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 port = c["port"] if "port" in c else None if port == None: - raise ValueError("No port specified for RNodeMulti interface") + raise ValueError("No port specified for "+name) interface = RNodeMultiInterface.RNodeMultiInterface( RNS.Transport,