FreeDATA/modem/frame_dispatcher.py
2024-03-15 14:25:46 +01:00

113 lines
5.2 KiB
Python

"""
FRAME DISPATCHER - We are dispatching the received frames to the needed functions
"""
import threading
import structlog
from modem_frametypes import FRAME_TYPE as FR_TYPE
import event_manager
from data_frame_factory import DataFrameFactory
from frame_handler import FrameHandler
from frame_handler_ping import PingFrameHandler
from frame_handler_cq import CQFrameHandler
from frame_handler_arq_session import ARQFrameHandler
from frame_handler_p2p_connection import P2PConnectionFrameHandler
from frame_handler_beacon import BeaconFrameHandler
class DISPATCHER():
FRAME_HANDLER = {
FR_TYPE.ARQ_SESSION_OPEN_ACK.value: {"class": ARQFrameHandler, "name": "ARQ OPEN ACK"},
FR_TYPE.ARQ_SESSION_OPEN.value: {"class": ARQFrameHandler, "name": "ARQ Data Channel Open"},
FR_TYPE.ARQ_SESSION_INFO_ACK.value: {"class": ARQFrameHandler, "name": "ARQ INFO ACK"},
FR_TYPE.ARQ_SESSION_INFO.value: {"class": ARQFrameHandler, "name": "ARQ Data Channel Info"},
FR_TYPE.P2P_CONNECTION_CONNECT.value: {"class": P2PConnectionFrameHandler, "name": "P2P Connection CONNECT"},
FR_TYPE.P2P_CONNECTION_CONNECT_ACK.value: {"class": P2PConnectionFrameHandler, "name": "P2P Connection CONNECT ACK"},
FR_TYPE.P2P_CONNECTION_DISCONNECT.value: {"class": P2PConnectionFrameHandler, "name": "P2P Connection DISCONNECT"},
FR_TYPE.P2P_CONNECTION_DISCONNECT_ACK.value: {"class": P2PConnectionFrameHandler,
"name": "P2P Connection DISCONNECT ACK"},
FR_TYPE.P2P_CONNECTION_PAYLOAD.value: {"class": P2PConnectionFrameHandler,
"name": "P2P Connection PAYLOAD"},
FR_TYPE.P2P_CONNECTION_PAYLOAD_ACK.value: {"class": P2PConnectionFrameHandler,
"name": "P2P Connection PAYLOAD ACK"},
#FR_TYPE.ARQ_CONNECTION_HB.value: {"class": ARQFrameHandler, "name": "ARQ HEARTBEAT"},
#FR_TYPE.ARQ_CONNECTION_OPEN.value: {"class": ARQFrameHandler, "name": "ARQ OPEN SESSION"},
FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP"},
FR_TYPE.ARQ_STOP_ACK.value: {"class": ARQFrameHandler, "name": "ARQ STOP ACK"},
FR_TYPE.BEACON.value: {"class": BeaconFrameHandler, "name": "BEACON"},
FR_TYPE.ARQ_BURST_FRAME.value:{"class": ARQFrameHandler, "name": "BURST FRAME"},
FR_TYPE.ARQ_BURST_ACK.value: {"class": ARQFrameHandler, "name": "BURST ACK"},
FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"},
FR_TYPE.PING_ACK.value: {"class": FrameHandler, "name": "PING ACK"},
FR_TYPE.PING.value: {"class": PingFrameHandler, "name": "PING"},
FR_TYPE.QRV.value: {"class": FrameHandler, "name": "QRV"},
FR_TYPE.IS_WRITING.value: {"class": FrameHandler, "name": "IS_WRITING"},
FR_TYPE.FEC.value: {"class": FrameHandler, "name": "FEC"},
FR_TYPE.FEC_WAKEUP.value: {"class": FrameHandler, "name": "FEC WAKEUP"},
}
def __init__(self, config, event_manager, states, modem):
self.log = structlog.get_logger("frame_dispatcher")
self.log.info("loading frame dispatcher.....\n")
self.config = config
self.states = states
self.event_manager = event_manager
self._initialize_handlers(config, states)
self.modem = modem
self.data_queue_received = modem.data_queue_received
self.arq_sessions = []
def _initialize_handlers(self, config, states):
"""Initializes various data handlers."""
self.frame_factory = DataFrameFactory(config)
def start(self):
"""Starts worker threads for transmit and receive operations."""
threading.Thread(target=self.worker_receive, name="Receive Worker", daemon=True).start()
def worker_receive(self) -> None:
"""Queue received data for processing"""
while True:
data = self.data_queue_received.get()
self.new_process_data(
data['payload'],
data['freedv'],
data['bytes_per_frame'],
data['snr'],
data['frequency_offset'],
)
def new_process_data(self, bytes_out, freedv, bytes_per_frame: int, snr, frequency_offset) -> None:
# get frame as dictionary
deconstructed_frame = self.frame_factory.deconstruct(bytes_out)
frametype = deconstructed_frame["frame_type_int"]
if frametype not in self.FRAME_HANDLER:
self.log.warning(
"[DISPATCHER] ARQ - other frame type", frametype=FR_TYPE(frametype).name)
return
# instantiate handler
handler_class = self.FRAME_HANDLER[frametype]['class']
handler: FrameHandler = handler_class(self.FRAME_HANDLER[frametype]['name'],
self.config,
self.states,
self.event_manager,
self.modem)
handler.handle(deconstructed_frame, snr, frequency_offset, freedv, bytes_per_frame)
def get_id_from_frame(self, data):
if data[:1] == FR_TYPE.ARQ_SESSION_OPEN:
return data[13:14]
return None