FreeDATA/modem/state_manager.py

178 lines
6.1 KiB
Python
Raw Normal View History

import time
2023-11-12 18:56:15 +00:00
import ujson as json
import threading
import numpy as np
2023-11-22 17:05:31 +00:00
class StateManager:
def __init__(self, statequeue):
# state related settings
self.statequeue = statequeue
2023-11-14 18:26:11 +00:00
self.newstate = None
self.last = time.time()
# modem related states
# not every state is needed to publish, yet
# TODO can we reduce them?
self.channel_busy_slot = [False, False, False, False, False]
2023-12-30 20:47:16 +00:00
self.channel_busy_event = threading.Event()
self.channel_busy_condition_traffic = threading.Event()
self.channel_busy_condition_codec2 = threading.Event()
2023-11-12 18:56:15 +00:00
self.is_modem_running = False
self.is_modem_busy = False
2023-11-12 22:22:53 +00:00
self.is_beacon_running = False
2023-11-13 19:26:27 +00:00
self.is_arq_state = False
self.is_arq_session = False
# If true, any wait() call is blocking
self.transmitting_event = threading.Event()
self.setTransmitting(False)
2023-11-13 17:11:55 +00:00
self.audio_dbfs = 0
self.dxcallsign: bytes = b"ZZ9YY-0"
self.dxgrid: bytes = b"------"
2023-12-01 15:39:52 +00:00
self.heard_stations = [] # TODO remove it... heard stations list == deprecated
self.activities_list = {}
2023-11-12 22:22:53 +00:00
2023-12-05 14:40:04 +00:00
self.arq_iss_sessions = {}
self.arq_irs_sessions = {}
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
2023-11-18 22:50:40 +00:00
# Set rig control status regardless or rig control method
self.radio_status = False
2023-11-17 21:35:52 +00:00
def sendState (self):
currentState = self.get_state_event(False)
2023-11-17 21:35:52 +00:00
self.statequeue.put(currentState)
return currentState
def sendStateUpdate (self):
self.statequeue.put(self.newstate)
2023-11-12 22:22:53 +00:00
def set(self, key, value):
setattr(self, key, value)
2023-11-18 22:50:40 +00:00
#print(f"State ==> Setting {key} to value {value}")
2023-11-14 18:26:11 +00:00
# only process data if changed
new_state = self.get_state_event(True)
if new_state != self.newstate:
2023-11-14 18:26:11 +00:00
self.newstate = new_state
self.sendStateUpdate()
2023-11-28 22:29:01 +00:00
def set_channel_slot_busy(self, array):
for i in range(0,len(array),1):
if not array[i] == self.channel_busy_slot[i]:
self.channel_busy_slot = array
self.newstate = self.get_state_event(True)
self.sendStateUpdate()
continue
def get_state_event(self, isChangedState):
2023-11-17 21:35:52 +00:00
msgtype = "state-change"
if (not isChangedState):
msgtype = "state"
return {
2023-11-17 21:35:52 +00:00
"freedata-message": msgtype,
2023-11-12 18:56:15 +00:00
"is_modem_running": self.is_modem_running,
2023-11-12 22:22:53 +00:00
"is_beacon_running": self.is_beacon_running,
2023-11-18 22:50:40 +00:00
"radio_status": self.radio_status,
"radio_frequency": self.radio_frequency,
2023-11-26 18:54:28 +00:00
"radio_mode": self.radio_mode,
2023-11-28 22:29:01 +00:00
"channel_busy_slot": self.channel_busy_slot,
2023-11-28 22:46:55 +00:00
"audio_dbfs": self.audio_dbfs,
2023-12-01 15:39:52 +00:00
"activities": self.activities_list,
}
# .wait() blocks until the event is set
def isTransmitting(self):
return not self.transmitting_event.is_set()
# .wait() blocks until the event is set
def setTransmitting(self, transmitting: bool):
if transmitting:
self.transmitting_event.clear()
else:
self.transmitting_event.set()
def waitForTransmission(self):
self.transmitting_event.wait()
2023-12-30 21:44:18 +00:00
def waitForChannelBusy(self):
self.channel_busy_event.wait(2)
2023-12-05 14:40:04 +00:00
def register_arq_iss_session(self, session):
if session.id in self.arq_iss_sessions:
raise RuntimeError(f"ARQ ISS Session '{session.id}' already exists!")
self.arq_iss_sessions[session.id] = session
2023-12-12 19:46:22 +00:00
def register_arq_irs_session(self, session):
2023-12-05 14:40:04 +00:00
if session.id in self.arq_irs_sessions:
raise RuntimeError(f"ARQ IRS Session '{session.id}' already exists!")
self.arq_irs_sessions[session.id] = session
def get_arq_iss_session(self, id):
if id not in self.arq_iss_sessions:
2023-12-24 12:27:24 +00:00
#raise RuntimeError(f"ARQ ISS Session '{id}' not found!")
# DJ2LS: WIP We need to find a better way of handling this
2023-12-24 12:29:54 +00:00
pass
2023-12-05 18:12:21 +00:00
return self.arq_iss_sessions[id]
2023-12-05 14:40:04 +00:00
def get_arq_irs_session(self, id):
if id not in self.arq_irs_sessions:
2023-12-24 12:27:24 +00:00
#raise RuntimeError(f"ARQ IRS Session '{id}' not found!")
# DJ2LS: WIP We need to find a better way of handling this
2023-12-24 12:29:54 +00:00
pass
2023-12-05 18:12:21 +00:00
return self.arq_irs_sessions[id]
2023-12-05 14:40:04 +00:00
def remove_arq_iss_session(self, id):
if id not in self.arq_iss_sessions:
raise RuntimeError(f"ARQ ISS Session '{id}' not found!")
del self.arq_iss_sessions[id]
def remove_arq_irs_session(self, id):
if id not in self.arq_irs_sessions:
raise RuntimeError(f"ARQ ISS Session '{id}' not found!")
del self.arq_irs_sessions[id]
2023-12-01 15:39:52 +00:00
def add_activity(self, activity_data):
# Generate a random 8-byte string as hex
activity_id = np.random.bytes(8).hex()
# if timestamp not provided, add it here
if 'timestamp' not in activity_data:
activity_data['timestamp'] = int(time.time())
# if frequency not provided, add it here
if 'frequency' not in activity_data:
activity_data['frequency'] = self.radio_frequency
self.activities_list[activity_id] = activity_data
self.sendStateUpdate()
2023-12-30 20:47:16 +00:00
def calculate_channel_busy_state(self):
if self.channel_busy_condition_traffic.is_set() and self.channel_busy_condition_codec2.is_set():
self.channel_busy_event.set()
else:
self.channel_busy_event = threading.Event()
def set_channel_busy_condition_traffic(self, busy):
if not busy:
self.channel_busy_condition_traffic.set()
else:
self.channel_busy_condition_traffic = threading.Event()
self.calculate_channel_busy_state()
def set_channel_busy_condition_codec2(self, traffic):
if not traffic:
self.channel_busy_condition_codec2.set()
else:
self.channel_busy_condition_codec2 = threading.Event()
self.calculate_channel_busy_state()