and another global has been eliminated..

This commit is contained in:
DJ2LS 2023-11-17 23:33:30 +01:00
parent 108851fb78
commit 07e6c33e89
8 changed files with 87 additions and 94 deletions

View file

@ -41,13 +41,13 @@ class DATA:
def __init__(self, config, event_queue, states) -> None:
self.states = states
self.stats = stats.stats()
self.stats = stats.stats(config, event_queue, states)
self.event_queue = event_queue
self.mycallsign = config['STATION']['mycall']
self.ssid_list = config['STATION']['ssid_list']
self.mycallsign_crc = b''
self.mycallsign_crc = helpers.get_crc_24(self.mycallsign)
self.mygrid = config['STATION']['mygrid']
self.enable_fsk = config['MODEM']['enable_fsk']
self.respond_to_cq = config['MODEM']['respond_to_cq']

View file

@ -11,7 +11,6 @@ import requests
import threading
import ujson as json
import structlog
from global_instances import HamlibParam, Modem
log = structlog.get_logger("explorer")
@ -34,21 +33,21 @@ class explorer():
def push(self):
frequency = 0 if HamlibParam.hamlib_frequency is None else HamlibParam.hamlib_frequency
frequency = 0 if self.states.radio_frequency is None else self.states.radio_frequency
band = "USB"
callsign = str(self.config['STATION']['mycall'])
gridsquare = str(self.config['STATION']['mygrid'])
version = str(Modem.version)
version = str(self.states.modem_version)
bandwidth = str(self.config['MODEM']['enable_low_bandwidth_mode'])
beacon = str(self.states.is_beacon_running)
strength = str(HamlibParam.hamlib_strength)
strength = str(self.states.radio_strength)
log.info("[EXPLORER] publish", frequency=frequency, band=band, callsign=callsign, gridsquare=gridsquare, version=version, bandwidth=bandwidth)
headers = {"Content-Type": "application/json"}
station_data = {'callsign': callsign, 'gridsquare': gridsquare, 'frequency': frequency, 'strength': strength, 'band': band, 'version': version, 'bandwidth': bandwidth, 'beacon': beacon, "lastheard": []}
for i in Modem.heard_stations:
for i in self.states.heard_stations:
try:
callsign = str(i[0], "UTF-8")
grid = str(i[1], "UTF-8")

View file

@ -1,19 +0,0 @@
# global_instances.py
from deprecated_static import Daemon, ARQ, AudioParam, Beacon, Channel, HamlibParam, ModemParam, Station, Statistics, TCIParam, Modem, MeshParam
# Initialize instances with appropriate default values
# Create single instances of each dataclass
Daemon = Daemon(modemprocess=None, rigctldprocess=None)
ARQ = ARQ()
AudioParam = AudioParam()
Beacon = Beacon()
Channel = Channel()
HamlibParam = HamlibParam()
ModemParam = ModemParam()
Station = Station()
Statistics = Statistics()
TCIParam = TCIParam()
Modem = Modem()
MeshParam = MeshParam()

View file

@ -6,10 +6,10 @@
HF mesh networking prototype and testing module
import time
MeshParam.routing_table = [['AA1AA', 'direct', 0, 1.0, 25, time.time(), ], ['AA1AA', 'AA2BB', 1, 3.1, 10, time.time(), ],
self.states.mesh_routing_table = [['AA1AA', 'direct', 0, 1.0, 25, time.time(), ], ['AA1AA', 'AA2BB', 1, 3.1, 10, time.time(), ],
['AA3CC', 'AA2BB', 5, -4.5, -3, time.time(), ]]
print(MeshParam.routing_table)
print(self.states.mesh_routing_table)
print("---------------------------------")
@ -51,10 +51,13 @@ import structlog
from queues import MESH_RECEIVED_QUEUE, MESH_QUEUE_TRANSMIT, MESH_SIGNALLING_TABLE
class MeshRouter():
def __init__(self):
def __init__(self, config, event_queue, states):
self.log = structlog.get_logger("RF")
self.mycallsign = config['STATION']['mycall']
self.mycallsign_crc = helpers.get_crc_24(self.mycallsign)
self.transmission_time_list = [
60, 90, 120, 180, 180, 180, 180, 180, 180, 360, 360, 360, 360, 360, 360,
60, 90, 120, 180, 180, 180, 180, 180, 180, 360, 360, 360, 360, 360, 360,
@ -113,7 +116,7 @@ class MeshRouter():
heard stations format:
[dxcallsign,dxgrid,int(time.time()),datatype,snr,offset,frequency]
Modem.heard_stations.append(
self.states.heard_stations.append(
[
dxcallsign,
dxgrid,
@ -134,7 +137,7 @@ class MeshRouter():
frequency_position = 6
try:
for item in Modem.heard_stations:
for item in self.states.heard_stations:
#print("-----------")
#print(item)
#print(item[snr_position])
@ -156,21 +159,21 @@ class MeshRouter():
def add_router_to_routing_table(self, new_router):
try:
# destination callsign # router callsign # hops # rx snr # route quality # timestamp
for _, item in enumerate(MeshParam.routing_table):
for _, item in enumerate(self.states.mesh_routing_table):
# update routing entry if exists
if new_router[0] in item[0] and new_router[1] in item[1]:
#print(f"UPDATE {MeshParam.routing_table[_]} >>> {new_router}")
self.log.info(f"[MESH] [ROUTING TABLE] [UPDATE]: {MeshParam.routing_table[_]} >>> ",
#print(f"UPDATE {self.states.mesh_routing_table[_]} >>> {new_router}")
self.log.info(f"[MESH] [ROUTING TABLE] [UPDATE]: {self.states.mesh_routing_table[_]} >>> ",
update=new_router)
MeshParam.routing_table[_] = new_router
self.states.mesh_routing_table[_] = new_router
# add new routing entry if not exists
if new_router not in MeshParam.routing_table:
if new_router not in self.states.mesh_routing_table:
#print(f"INSERT {new_router} >>> ROUTING TABLE")
self.log.info("[MESH] [ROUTING TABLE] [INSERT]:", insert=new_router)
MeshParam.routing_table.append(new_router)
self.states.mesh_routing_table.append(new_router)
except Exception as e:
self.log.warning("[MESH] error adding data to routing table", e=e, router=new_router)
@ -181,7 +184,7 @@ class MeshRouter():
modem.RECEIVE_DATAC4 = True
threading.Event().wait(1)
if not ARQ.arq_state and not ModemParam.channel_busy:
if not self.states.arq_state and not self.states.channel_busy:
try:
# wait some time until sending routing table
@ -193,7 +196,7 @@ class MeshRouter():
#[b'DJ2LS-0', 'direct', 0, 9.6, 9.6, 1684912305]
mesh_broadcast_frame_header = bytearray(4)
mesh_broadcast_frame_header[:1] = bytes([FRAME_TYPE.MESH_BROADCAST.value])
mesh_broadcast_frame_header[1:4] = helpers.get_crc_24(Station.mycallsign)
mesh_broadcast_frame_header[1:4] = helpers.get_crc_24(self.mycallsign)
# callsign(6), router(6), hops(1), path_score(1) == 14 ==> 14 28 42 ==> 3 mesh routing entries
# callsign_crc(3), router_crc(3), hops(1), path_score(1) == 8 --> 6
@ -204,15 +207,15 @@ class MeshRouter():
# Iterate over the route subarrays and add the selected entries to the result bytearray
index = 0
for route_id, route in enumerate(MeshParam.routing_table):
for route_id, route in enumerate(self.states.mesh_routing_table):
# the value 5 is the length of crc24 + hops + score
dxcall = MeshParam.routing_table[route_id][0]
# router = MeshParam.routing_table[i][1]
hops = MeshParam.routing_table[route_id][2]
# snr = MeshParam.routing_table[i][3]
route_score = np.clip(MeshParam.routing_table[route_id][4], 0, 254)
# timestamp = MeshParam.routing_table[i][5]
dxcall = self.states.mesh_routing_table[route_id][0]
# router = self.states.mesh_routing_table[i][1]
hops = self.states.mesh_routing_table[route_id][2]
# snr = self.states.mesh_routing_table[i][3]
route_score = np.clip(self.states.mesh_routing_table[route_id][4], 0, 254)
# timestamp = self.states.mesh_routing_table[i][5]
result[index:index + 5] = dxcall + bytes([hops]) + bytes([route_score])
index += 5
@ -225,13 +228,13 @@ class MeshRouter():
#print(len(_))
frame_list.append(mesh_broadcast_frame_header + _)
Modem.transmitting = True
self.states.set("is_transmitting", True)
c2_mode = FREEDV_MODE.datac4.value
self.log.info("[MESH] broadcasting routing table", frame_list=frame_list, frames=len(split_result))
modem.MODEM_TRANSMIT_QUEUE.put([c2_mode, 1, 0, frame_list])
# Wait while transmitting
while Modem.transmitting:
while self.states.is_transmitting:
threading.Event().wait(0.01)
except Exception as e:
self.log.warning("[MESH] broadcasting routing table", e=e)
@ -239,9 +242,12 @@ class MeshRouter():
def mesh_rx_dispatcher(self):
while True:
data_in = MESH_RECEIVED_QUEUE.get()
data = MESH_RECEIVED_QUEUE.get()
data_in = data[0]
snr = data[1]
if int.from_bytes(data_in[:1], "big") in [FRAME_TYPE.MESH_BROADCAST.value]:
self.received_routing_table(data_in[:-2])
self.received_routing_table(data_in[:-2], snr)
elif int.from_bytes(data_in[:1], "big") in [FRAME_TYPE.MESH_SIGNALLING_PING.value]:
self.received_mesh_ping(data_in[:-2])
elif int.from_bytes(data_in[:1], "big") in [FRAME_TYPE.MESH_SIGNALLING_PING_ACK.value]:
@ -273,7 +279,7 @@ class MeshRouter():
threading.Event().wait(1.0)
for entry in MESH_SIGNALLING_TABLE:
# if in arq state, interrupt dispatcher
if ARQ.arq_state or ARQ.arq_session:
if self.states.arq_state or self.states.arq_session:
break
#print(entry)
@ -293,7 +299,7 @@ class MeshRouter():
entry[5] += 1
self.log.info("[MESH] [TX] Ping", destination=entry[1], origin=entry[2])
channel_busy_timeout = time.time() + 5
while ModemParam.channel_busy and time.time() < channel_busy_timeout:
while self.states.channel_busy and time.time() < channel_busy_timeout:
threading.Event().wait(0.01)
self.transmit_mesh_signalling_ping(bytes.fromhex(entry[1]), bytes.fromhex(entry[2]))
#print("...")
@ -306,14 +312,14 @@ class MeshRouter():
entry[5] += 1
self.log.info("[MESH] [TX] Ping ACK", destination=entry[1], origin=entry[2])
channel_busy_timeout = time.time() + 5
while ModemParam.channel_busy and time.time() < channel_busy_timeout:
while self.states.channel_busy and time.time() < channel_busy_timeout:
threading.Event().wait(0.01)
self.transmit_mesh_signalling_ping_ack(bytes.fromhex(entry[1]), bytes.fromhex(entry[2]))
else:
pass
def received_routing_table(self, data_in):
def received_routing_table(self, data_in, snr):
try:
print("data received........")
print(data_in)
@ -327,7 +333,7 @@ class MeshRouter():
callsign_checksum = payload[i:i + 3] # First 3 bytes of the information (callsign_checksum)
hops = int.from_bytes(payload[i+3:i + 4], "big") # Fourth byte of the information (hops)
score = int.from_bytes(payload[i+4:i + 5], "big") # Fifth byte of the information (score)
snr = int(ModemParam.snr)
snr = int(snr)
score = self.calculate_new_avg_score(score, self.calculate_score_by_snr(snr))
timestamp = int(time.time())
@ -335,7 +341,7 @@ class MeshRouter():
_use_case1 = callsign_checksum.startswith(b'\x00')
# use case 2: add new router to table only if not own callsign
_use_case2 = callsign_checksum not in [helpers.get_crc_24(Station.mycallsign)]
_use_case2 = callsign_checksum not in [helpers.get_crc_24(self.mycallsign)]
# use case 3: increment hop if router not direct
if router not in [helpers.get_crc_24(b'direct')] and hops == 0:
@ -343,9 +349,9 @@ class MeshRouter():
# use case 4: if callsign is directly available skip route for only keeping shortest way in db
_use_case4 = False
for _, call in enumerate(MeshParam.routing_table):
for _, call in enumerate(self.states.mesh_routing_table):
# check if callsign already in routing table and is direct connection
if callsign_checksum in [MeshParam.routing_table[_][0]] and MeshParam.routing_table[_][1] in [helpers.get_crc_24(b'direct')]:
if callsign_checksum in [self.states.mesh_routing_table[_][0]] and self.states.mesh_routing_table[_][1] in [helpers.get_crc_24(b'direct')]:
_use_case4 = True
# use case N: calculate score
@ -364,8 +370,8 @@ class MeshRouter():
self.add_router_to_routing_table(new_router)
print("-------------------------")
for _, item in enumerate(MeshParam.routing_table):
print(MeshParam.routing_table[_])
for _, item in enumerate(self.states.mesh_routing_table):
print(self.states.mesh_routing_table[_])
print("-------------------------")
except Exception as e:
self.log.warning("[MESH] error processing received routing broadcast", e=e)
@ -388,21 +394,21 @@ class MeshRouter():
def received_mesh_ping(self, data_in):
destination = data_in[1:4].hex()
origin = data_in[4:7].hex()
if destination == Station.mycallsign_crc.hex():
self.log.info("[MESH] [RX] [PING] [REQ]", destination=destination, origin=origin, mycall=Station.mycallsign_crc.hex())
if destination == self.mycallsign_crc.hex():
self.log.info("[MESH] [RX] [PING] [REQ]", destination=destination, origin=origin, mycall=self.mycallsign_crc.hex())
# use case 1: set status to acknowleding if we are the receiver of a PING
self.add_mesh_ping_to_signalling_table(destination, origin, frametype="PING-ACK", status="acknowledging")
channel_busy_timeout = time.time() + 5
while ModemParam.channel_busy and time.time() < channel_busy_timeout:
while self.states.channel_busy and time.time() < channel_busy_timeout:
threading.Event().wait(0.01)
# dxcallsign_crc = Station.mycallsign_crc
# dxcallsign_crc = self.mycallsign_crc
self.transmit_mesh_signalling_ping_ack(bytes.fromhex(destination), bytes.fromhex(origin))
elif origin == Station.mycallsign_crc.hex():
elif origin == self.mycallsign_crc.hex():
pass
else:
self.log.info("[MESH] [RX] [PING] [REQ]", destination=destination, origin=origin, mycall=Station.mycallsign_crc.hex())
self.log.info("[MESH] [RX] [PING] [REQ]", destination=destination, origin=origin, mycall=self.mycallsign_crc.hex())
# lookup if entry is already in database - if so, udpate and exit
for item in MESH_SIGNALLING_TABLE:
if item[1] == destination and item[5] >= self.signalling_max_attempts:
@ -429,17 +435,17 @@ class MeshRouter():
attempt = 0
if destination == Station.mycallsign_crc.hex():
#self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, origin=origin, mycall=Station.mycallsign_crc.hex())
if destination == self.mycallsign_crc.hex():
#self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, origin=origin, mycall=self.mycallsign_crc.hex())
#self.add_mesh_ping_ack_to_signalling_table(destination, origin, status="sending_ack")
pass
elif origin == Station.mycallsign_crc.hex():
self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, origin=origin, mycall=Station.mycallsign_crc.hex())
elif origin == self.mycallsign_crc.hex():
self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, origin=origin, mycall=self.mycallsign_crc.hex())
self.add_mesh_ping_ack_to_signalling_table(destination, origin, status="acknowledged")
else:
#status = "forwarding"
#self.add_mesh_ping_ack_to_signalling_table(destination, status)
self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, mycall=Station.mycallsign_crc.hex())
self.log.info("[MESH] [RX] [PING] [ACK]", destination=destination, mycall=self.mycallsign_crc.hex())
for item in MESH_SIGNALLING_TABLE:
if item[1] == destination and item[2] == origin and item[5] >= self.signalling_max_attempts:
# use case 2: set status to forwarded if we are not the receiver of a PING and out of retries
@ -544,11 +550,11 @@ class MeshRouter():
# Set the TRANSMITTING flag before adding an object to the transmit queue
# TODO This is not that nice, we could improve this somehow
Modem.transmitting = True
self.states.set("is_transmitting", True)
modem.MODEM_TRANSMIT_QUEUE.put([c2_mode, copies, repeat_delay, frame_to_tx])
# Wait while transmitting
while Modem.transmitting:
while self.states.is_transmitting:
threading.Event().wait(0.01)
@ -560,7 +566,7 @@ class MeshRouter():
ping_frame[:1] = frame_type
ping_frame[1:4] = destination
ping_frame[4:7] = origin
ping_frame[7:13] = helpers.callsign_to_bytes(Station.mycallsign)
ping_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign)
self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.sig0.value)
@ -573,6 +579,6 @@ class MeshRouter():
ping_frame[:1] = frame_type
ping_frame[1:4] = destination
ping_frame[4:7] = origin
#ping_frame[7:13] = helpers.callsign_to_bytes(Station.mycallsign)
#ping_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign)
self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.sig0.value)

View file

@ -27,6 +27,7 @@ from queues import DATA_QUEUE_RECEIVED, MODEM_RECEIVED_QUEUE, MODEM_TRANSMIT_QUE
AUDIO_RECEIVED_QUEUE, AUDIO_TRANSMIT_QUEUE, MESH_RECEIVED_QUEUE
import audio
import event_manager
from modem_frametypes import FRAME_TYPE
TESTMODE = False
RXCHANNEL = ""
@ -873,7 +874,7 @@ class RF:
self.log.debug(
"[MDM] [demod_audio] moving data to mesh dispatcher", nbytes=nbytes
)
MESH_RECEIVED_QUEUE.put(bytes(bytes_out))
MESH_RECEIVED_QUEUE.put([bytes(bytes_out), snr])
else:
self.log.debug(
@ -1305,9 +1306,9 @@ class RF:
if self.states.is_transmitting:
self.radio_alc = self.radio.get_alc()
threading.Event().wait(0.1)
# HamlibParam.hamlib_rf = self.radio.get_level()
self.states.set("radio_rf_power", self.radio.get_level())
# threading.Event().wait(0.1)
self.states.set("radio_rf_power", self.radio.get_strength())
self.states.set("radio_strength", self.radio.get_strength())
except Exception as e:
self.log.warning(

View file

@ -2,7 +2,6 @@
Hold queues used by more than one module to eliminate cyclic imports.
"""
import queue
from global_instances import ARQ
DATA_QUEUE_TRANSMIT = queue.Queue()
DATA_QUEUE_RECEIVED = queue.Queue()
@ -22,7 +21,8 @@ AUDIO_RECEIVED_QUEUE = queue.Queue()
AUDIO_TRANSMIT_QUEUE = queue.Queue()
# Initialize FIFO queue to finally store received data
RX_BUFFER = queue.Queue(maxsize=ARQ.rx_buffer_size)
# TODO Fix rx_buffer_size
RX_BUFFER = queue.Queue(maxsize=16)
# Commands we want to send to rigctld
RIGCTLD_COMMAND_QUEUE = queue.Queue()

View file

@ -3,6 +3,8 @@ import ujson as json
class STATES:
def __init__(self, statequeue):
self.modem_version = 0.0
# state related settings
self.statequeue = statequeue
self.newstate = None
@ -35,10 +37,13 @@ class STATES:
self.arq_speed_list = []
self.arq_seconds_until_timeout = 0
self.mesh_routing_table = []
self.radio_frequency = 0
self.radio_mode = None
self.radio_bandwidth = 0
self.radio_rf_power = 0
self.radio_strength = 0
def sendState (self):
currentState = self.getAsJSON(False)

View file

@ -10,42 +10,43 @@ Created on 05.11.23
import requests
import ujson as json
import structlog
from global_instances import ARQ, HamlibParam, Station, Modem
log = structlog.get_logger("stats")
class stats():
def __init__(self):
def __init__(self, config, event_queue, states):
self.explorer_url = "https://api.freedata.app/stats.php"
self.states = states
def push(self, frame_nack_counter, status, duration):
crcerror = status in ["crc_error", "wrong_crc"]
# get avg snr
try:
snr_raw = [item["snr"] for item in ARQ.speed_list]
snr_raw = [item["snr"] for item in self.states.arq_speed_list]
avg_snr = round(sum(snr_raw) / len(snr_raw), 2 )
except Exception:
avg_snr = 0
headers = {"Content-Type": "application/json"}
station_data = {
'callsign': str(Station.mycallsign, "utf-8"),
'dxcallsign': str(Station.dxcallsign, "utf-8"),
'gridsquare': str(Station.mygrid, "utf-8"),
'dxgridsquare': str(Station.dxgrid, "utf-8"),
'frequency': 0 if HamlibParam.hamlib_frequency is None else HamlibParam.hamlib_frequency,
'callsign': str(self.states.mycallsign, "utf-8"),
'dxcallsign': str(self.states.dxcallsign, "utf-8"),
'gridsquare': str(self.states.mygrid, "utf-8"),
'dxgridsquare': str(self.states.dxgrid, "utf-8"),
'frequency': 0 if self.states.radio_frequency is None else self.states.radio_frequency,
'avgstrength': 0,
'avgsnr': avg_snr,
'bytesperminute': ARQ.bytes_per_minute,
'filesize': ARQ.total_bytes,
'compressionfactor': ARQ.arq_compression_factor,
'bytesperminute': self.states.arq_bytes_per_minute,
'filesize': self.states.arq_total_bytes,
'compressionfactor': self.states.arq_compression_factor,
'nacks': frame_nack_counter,
'crcerror': crcerror,
'duration': duration,
'percentage': ARQ.arq_transmission_percent,
'percentage': self.states.arq_transmission_percent,
'status': status,
'version': Modem.version
'version': self.states.modem_version
}
station_data = json.dumps(station_data)