2023-11-29 21:53:50 +00:00
|
|
|
import helpers
|
|
|
|
from event_manager import EventManager
|
|
|
|
from state_manager import StateManager
|
|
|
|
from queue import Queue
|
|
|
|
import structlog
|
2023-11-29 23:15:16 +00:00
|
|
|
import time, uuid
|
|
|
|
from codec2 import FREEDV_MODE
|
2024-01-30 20:22:04 +00:00
|
|
|
from message_system_db_manager import DatabaseManager
|
2023-11-29 21:53:50 +00:00
|
|
|
|
2023-12-16 11:54:16 +00:00
|
|
|
TESTMODE = False
|
|
|
|
|
2023-11-29 21:53:50 +00:00
|
|
|
class FrameHandler():
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
def __init__(self, name: str, config, states: StateManager, event_manager: EventManager,
|
2023-12-15 23:51:57 +00:00
|
|
|
modem) -> None:
|
2023-11-29 21:53:50 +00:00
|
|
|
|
|
|
|
self.name = name
|
2023-11-29 23:15:16 +00:00
|
|
|
self.config = config
|
2023-11-29 21:53:50 +00:00
|
|
|
self.states = states
|
|
|
|
self.event_manager = event_manager
|
2023-12-15 23:51:57 +00:00
|
|
|
self.modem = modem
|
2023-11-29 21:53:50 +00:00
|
|
|
self.logger = structlog.get_logger("Frame Handler")
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
self.details = {
|
|
|
|
'frame' : None,
|
|
|
|
'snr' : 0,
|
2023-12-12 08:41:08 +00:00
|
|
|
'frequency_offset': 0,
|
2023-11-29 23:15:16 +00:00
|
|
|
'freedv_inst': None,
|
|
|
|
'bytes_per_frame': 0
|
|
|
|
}
|
|
|
|
|
2024-01-14 22:33:06 +00:00
|
|
|
def is_frame_for_me(self):
|
|
|
|
call_with_ssid = self.config['STATION']['mycall'] + "-" + str(self.config['STATION']['myssid'])
|
|
|
|
ft = self.details['frame']['frame_type']
|
2024-01-17 10:06:33 +00:00
|
|
|
valid = False
|
2024-01-14 22:33:06 +00:00
|
|
|
# Check for callsign checksum
|
|
|
|
if ft in ['ARQ_SESSION_OPEN', 'ARQ_SESSION_OPEN_ACK', 'PING', 'PING_ACK']:
|
|
|
|
valid, mycallsign = helpers.check_callsign(
|
|
|
|
call_with_ssid,
|
|
|
|
self.details["frame"]["destination_crc"],
|
|
|
|
self.config['STATION']['ssid_list'])
|
|
|
|
|
|
|
|
# Check for session id on IRS side
|
|
|
|
elif ft in ['ARQ_SESSION_INFO', 'ARQ_BURST_FRAME', 'ARQ_STOP']:
|
|
|
|
session_id = self.details['frame']['session_id']
|
|
|
|
if session_id in self.states.arq_irs_sessions:
|
|
|
|
valid = True
|
|
|
|
|
|
|
|
# Check for session id on ISS side
|
|
|
|
elif ft in ['ARQ_SESSION_INFO_ACK', 'ARQ_BURST_ACK', 'ARQ_STOP_ACK']:
|
|
|
|
session_id = self.details['frame']['session_id']
|
|
|
|
if session_id in self.states.arq_iss_sessions:
|
|
|
|
valid = True
|
|
|
|
else:
|
|
|
|
valid = False
|
|
|
|
|
|
|
|
if not valid:
|
|
|
|
self.logger.info(f"[Frame handler] {ft} received but not for us.")
|
|
|
|
|
|
|
|
return valid
|
|
|
|
|
|
|
|
def should_respond(self):
|
|
|
|
return self.is_frame_for_me()
|
|
|
|
|
2023-12-03 09:40:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
def add_to_activity_list(self):
|
|
|
|
frame = self.details['frame']
|
|
|
|
|
|
|
|
activity = {
|
|
|
|
"direction": "received",
|
|
|
|
"snr": self.details['snr'],
|
2023-12-12 08:41:08 +00:00
|
|
|
"frequency_offset": self.details['frequency_offset'],
|
2023-12-03 09:40:31 +00:00
|
|
|
"activity_type": frame["frame_type"]
|
|
|
|
}
|
|
|
|
if "origin" in frame:
|
|
|
|
activity["origin"] = frame["origin"]
|
|
|
|
|
|
|
|
if "destination" in frame:
|
|
|
|
activity["destination"] = frame["destination"]
|
|
|
|
|
|
|
|
if "gridsquare" in frame:
|
|
|
|
activity["gridsquare"] = frame["gridsquare"]
|
|
|
|
|
|
|
|
if "session_id" in frame:
|
|
|
|
activity["session_id"] = frame["session_id"]
|
|
|
|
|
|
|
|
self.states.add_activity(activity)
|
|
|
|
|
|
|
|
|
2023-11-29 21:53:50 +00:00
|
|
|
def add_to_heard_stations(self):
|
2023-11-29 23:15:16 +00:00
|
|
|
frame = self.details['frame']
|
2023-11-30 08:24:36 +00:00
|
|
|
|
|
|
|
if 'origin' not in frame:
|
|
|
|
return
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
dxgrid = frame['gridsquare'] if 'gridsquare' in frame else "------"
|
|
|
|
helpers.add_to_heard_stations(
|
|
|
|
frame['origin'],
|
|
|
|
dxgrid,
|
|
|
|
self.name,
|
|
|
|
self.details['snr'],
|
2023-12-12 08:41:08 +00:00
|
|
|
self.details['frequency_offset'],
|
2023-11-29 23:15:16 +00:00
|
|
|
self.states.radio_frequency,
|
|
|
|
self.states.heard_stations,
|
|
|
|
)
|
2023-11-29 21:53:50 +00:00
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
def make_event(self):
|
2024-01-30 20:22:04 +00:00
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
event = {
|
2024-01-05 14:10:46 +00:00
|
|
|
"type": "frame-handler",
|
2023-11-30 07:44:18 +00:00
|
|
|
"received": self.details['frame']['frame_type'],
|
2023-11-29 23:15:16 +00:00
|
|
|
"timestamp": int(time.time()),
|
|
|
|
"mycallsign": self.config['STATION']['mycall'],
|
2024-01-05 14:10:46 +00:00
|
|
|
"myssid": self.config['STATION']['myssid'],
|
2023-11-29 23:15:16 +00:00
|
|
|
"snr": str(self.details['snr']),
|
2024-01-05 14:10:46 +00:00
|
|
|
}
|
2023-11-29 23:15:16 +00:00
|
|
|
if 'origin' in self.details['frame']:
|
|
|
|
event['dxcallsign'] = self.details['frame']['origin']
|
2024-01-30 20:22:04 +00:00
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
return event
|
2023-11-29 21:53:50 +00:00
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
def emit_event(self):
|
|
|
|
event_data = self.make_event()
|
2023-11-29 21:53:50 +00:00
|
|
|
self.event_manager.broadcast(event_data)
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
def get_tx_mode(self):
|
2023-12-28 20:49:31 +00:00
|
|
|
return FREEDV_MODE.signalling
|
2023-11-29 23:15:16 +00:00
|
|
|
|
2023-11-29 21:53:50 +00:00
|
|
|
def transmit(self, frame):
|
2023-12-16 11:54:16 +00:00
|
|
|
if not TESTMODE:
|
|
|
|
self.modem.transmit(self.get_tx_mode(), 1, 0, frame)
|
|
|
|
else:
|
|
|
|
self.event_manager.broadcast(frame)
|
2023-11-29 21:53:50 +00:00
|
|
|
|
|
|
|
def follow_protocol(self):
|
|
|
|
pass
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
def log(self):
|
2023-12-18 12:56:49 +00:00
|
|
|
self.logger.info(f"[Frame Handler] Handling frame {self.details['frame']['frame_type']}")
|
2023-11-29 21:53:50 +00:00
|
|
|
|
2023-12-12 08:41:08 +00:00
|
|
|
def handle(self, frame, snr, frequency_offset, freedv_inst, bytes_per_frame):
|
2023-11-29 23:15:16 +00:00
|
|
|
self.details['frame'] = frame
|
|
|
|
self.details['snr'] = snr
|
2023-12-12 08:41:08 +00:00
|
|
|
self.details['frequency_offset'] = frequency_offset
|
2023-11-29 23:15:16 +00:00
|
|
|
self.details['freedv_inst'] = freedv_inst
|
|
|
|
self.details['bytes_per_frame'] = bytes_per_frame
|
|
|
|
|
2024-02-08 12:15:46 +00:00
|
|
|
# look in database for a full callsign if only crc is present
|
|
|
|
if 'origin' not in frame and 'origin_crc' in frame:
|
|
|
|
self.details['frame']['origin'] = DatabaseManager(self.event_manager).get_callsign_by_checksum(frame['origin_crc'])
|
|
|
|
|
2023-11-29 23:15:16 +00:00
|
|
|
self.log()
|
2023-11-29 21:53:50 +00:00
|
|
|
self.add_to_heard_stations()
|
2023-12-03 09:40:31 +00:00
|
|
|
self.add_to_activity_list()
|
2024-01-06 14:43:16 +00:00
|
|
|
self.emit_event()
|
2023-11-29 21:53:50 +00:00
|
|
|
self.follow_protocol()
|