Added periodic ID option to RNode interface. Fixed RNode SNR stat indication.

This commit is contained in:
Mark Qvist 2020-05-21 14:17:14 +02:00
parent 0140cd6eba
commit 8c2cfb0349
2 changed files with 57 additions and 17 deletions

View File

@ -70,7 +70,9 @@ class RNodeInterface(Interface):
RSSI_OFFSET = 157 RSSI_OFFSET = 157
SNR_OFFSET = 128 SNR_OFFSET = 128
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False): CALLSIGN_MAX_LEN = 32
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, id_interval = None, id_callsign = None):
self.serial = None self.serial = None
self.owner = owner self.owner = owner
self.name = name self.name = name
@ -90,6 +92,8 @@ class RNodeInterface(Interface):
self.state = KISS.RADIO_STATE_OFF self.state = KISS.RADIO_STATE_OFF
self.bitrate = 0 self.bitrate = 0
self.last_id = 0
self.r_frequency = None self.r_frequency = None
self.r_bandwidth = None self.r_bandwidth = None
self.r_txpower = None self.r_txpower = None
@ -123,10 +127,22 @@ class RNodeInterface(Interface):
RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR)
self.validcfg = False self.validcfg = False
if (self.cr < 5 or self.sf > 8): if (self.cr < 5 or self.cr > 8):
RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR)
self.validcfg = False self.validcfg = False
if id_interval != None and id_callsign != None:
if (len(id_callsign.encode("utf-8")) <= RNodeInterface.CALLSIGN_MAX_LEN):
self.should_id = True
self.id_callsign = id_callsign
self.id_interval = id_interval
else:
RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR)
self.validcfg = False
else:
self.id_interval = None
self.id_callsign = None
if (not self.validcfg): if (not self.validcfg):
raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline")
@ -259,7 +275,7 @@ class RNodeInterface(Interface):
try: try:
self.bitrate = self.r_sf * ( (4.0/self.cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate = self.r_sf * ( (4.0/self.cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000
self.bitrate_kbps = round(self.bitrate/1000.0, 2) self.bitrate_kbps = round(self.bitrate/1000.0, 2)
RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_DEBUG) RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_INFO)
except: except:
self.bitrate = 0 self.bitrate = 0
@ -273,9 +289,17 @@ class RNodeInterface(Interface):
if self.flow_control: if self.flow_control:
self.interface_ready = False self.interface_ready = False
data = KISS.escape(data) frame = b""
frame = bytes([0xc0])+bytes([0x00])+data+bytes([0xc0])
if self.id_interval != None and self.id_callsign != None:
if self.last_id + self.id_interval < time.time():
self.last_id = time.time()
frame = bytes([0xc0])+bytes([0x00])+KISS.escape(self.id_callsign.encode("utf-8"))+bytes([0xc0])
data = KISS.escape(data)
frame += bytes([0xc0])+bytes([0x00])+data+bytes([0xc0])
written = self.serial.write(frame) written = self.serial.write(frame)
if written != len(frame): if written != len(frame):
raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data)))
else: else:
@ -408,7 +432,7 @@ class RNodeInterface(Interface):
elif (command == KISS.CMD_STAT_RSSI): elif (command == KISS.CMD_STAT_RSSI):
self.r_stat_rssi = byte-RNodeInterface.RSSI_OFFSET self.r_stat_rssi = byte-RNodeInterface.RSSI_OFFSET
elif (command == KISS.CMD_STAT_SNR): elif (command == KISS.CMD_STAT_SNR):
self.r_stat_snr = byte-RNodeInterface.SNR_OFFSET self.r_stat_snr = int.from_bytes(bytes([byte]), byteorder="big", signed=True) * 0.25
elif (command == KISS.CMD_RANDOM): elif (command == KISS.CMD_RANDOM):
self.r_random = byte self.r_random = byte
elif (command == KISS.CMD_ERROR): elif (command == KISS.CMD_ERROR):

View File

@ -248,8 +248,7 @@ class Reticulum:
txtail = int(c["txtail"]) if "txtail" in c else None txtail = int(c["txtail"]) if "txtail" in c else None
persistence = int(c["persistence"]) if "persistence" in c else None persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = (True if c["flow_control"] == "true" else False) if "flow_control" in c else False flow_control = c.as_bool("flow_control") if "flow_control" in c else False
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
databits = int(c["databits"]) if "databits" in c else 8 databits = int(c["databits"]) if "databits" in c else 8
@ -286,8 +285,7 @@ class Reticulum:
txtail = int(c["txtail"]) if "txtail" in c else None txtail = int(c["txtail"]) if "txtail" in c else None
persistence = int(c["persistence"]) if "persistence" in c else None persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = (True if c["flow_control"] == "true" else False) if "flow_control" in c else False flow_control = c.as_bool("flow_control") if "flow_control" in c else False
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
databits = int(c["databits"]) if "databits" in c else 8 databits = int(c["databits"]) if "databits" in c else 8
@ -330,7 +328,9 @@ class Reticulum:
txpower = int(c["txpower"]) if "txpower" in c else None txpower = int(c["txpower"]) if "txpower" in c else None
spreadingfactor = int(c["spreadingfactor"]) if "spreadingfactor" in c else None spreadingfactor = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
codingrate = int(c["codingrate"]) if "codingrate" in c else None codingrate = int(c["codingrate"]) if "codingrate" in c else None
flow_control = (True if c["flow_control"] == "true" else False) 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_callsign = c["id_callsign"] if "id_callsign" in c else None
port = c["port"] if "port" in c else None port = c["port"] if "port" in c else None
@ -341,11 +341,14 @@ class Reticulum:
RNS.Transport, RNS.Transport,
name, name,
port, port,
frequency, frequency = frequency,
bandwidth, bandwidth = bandwidth,
txpower, txpower = txpower,
spreadingfactor, sf = spreadingfactor,
flow_control cr = codingrate,
flow_control = flow_control,
id_interval = id_interval,
id_callsign = id_callsign
) )
if "outgoing" in c and c["outgoing"].lower() == "true": if "outgoing" in c and c["outgoing"].lower() == "true":
@ -355,7 +358,7 @@ class Reticulum:
RNS.Transport.interfaces.append(interface) RNS.Transport.interfaces.append(interface)
else: else:
RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_VERBOSE) RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_NOTICE)
except Exception as e: except Exception as e:
RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR)
@ -533,6 +536,19 @@ loglevel = 4
# fastest, and 8 the longest range. # fastest, and 8 the longest range.
codingrate = 5 codingrate = 5
# You can configure the RNode to send
# out identification on the channel with
# a set interval by configuring the
# following two parameters. The trans-
# ceiver will only ID before making an
# actual transmission, and if the set
# interval has elapsed since it's last
# ID. Interval is configured in seconds
# This option is commented out and not
# used by default.
# id_callsign = MYCALL-0
# id_interval = 600
# An example KISS modem interface. Useful for running # An example KISS modem interface. Useful for running
# Reticulum over packet radio hardware. # Reticulum over packet radio hardware.