diff --git a/modem/command.py b/modem/command.py index 01f81107..7690f02d 100644 --- a/modem/command.py +++ b/modem/command.py @@ -1,5 +1,5 @@ from data_frame_factory import DataFrameFactory -from modem.modem import RF +from modem import RF import queue from codec2 import FREEDV_MODE @@ -26,18 +26,22 @@ class TxCommand(): def build_frame(self): pass - def get_c2_mode(self): + def get_tx_mode(self): c2_mode = FREEDV_MODE.fsk_ldpc_0.value if self.config.enable_fsk else FREEDV_MODE.sig0.value return c2_mode - - def transmit(self, tx_frame_queue): - frame = self.build_frame() - tx_queue_item = { + + def make_modem_queue_item(self, mode, repeat, repeat_delay, frame): + item = { 'mode': self.get_c2_mode(), 'repeat': 1, 'repeat_delay': 0, 'frame': frame } + return item + + def transmit(self, tx_frame_queue): + frame = self.build_frame() + tx_queue_item = self.make_modem_queue_item(self.get_tx_mode(), 1, 0, frame) tx_frame_queue.put(tx_queue_item) def run(self, event_queue: queue.Queue, tx_frame_queue: queue.Queue): diff --git a/modem/command_cq.py b/modem/command_cq.py index 79f2787d..b8eeb7b0 100644 --- a/modem/command_cq.py +++ b/modem/command_cq.py @@ -1,3 +1,6 @@ from command import TxCommand class CQCommand(TxCommand): + + def build_frame(self): + return self.frame_factory.build_cq() diff --git a/modem/command_feq.py b/modem/command_feq.py index d2364365..cdd16310 100644 --- a/modem/command_feq.py +++ b/modem/command_feq.py @@ -22,8 +22,8 @@ class FecCommand(TxCommand): def transmit(self, tx_frame_queue): if self.wakeup: - tx_queue_item = [self.get_c2_mode(), 1, 0, self.build_wakeup_frame()] + tx_queue_item = self.make_modem_queue_item(self.get_c2_mode(), 1, 0, self.build_wakeup_frame()) tx_frame_queue.put(tx_queue_item) - tx_queue_item = [self.get_c2_mode(), 1, 0, self.build_frame()] + tx_queue_item = self.make_modem_queue_item(self.get_c2_mode(), 1, 0, self.build_frame()) tx_frame_queue.put(tx_queue_item) diff --git a/modem/command_ping.py b/modem/command_ping.py index e6e155bf..0ab38a49 100644 --- a/modem/command_ping.py +++ b/modem/command_ping.py @@ -6,10 +6,5 @@ class PingCommand(TxCommand): self.dxcall = apiParams['dxcall'] return super().setParamsFromApi() - def run(self, modem_state, tx_frame_queue): - frame = self.frame_factory.build_ping(self.dxcall) - - - return super().execute(modem_state, tx_frame_queue) - - + def build_frame(self): + return self.frame_factory.build_ping(self.dxcall) diff --git a/modem/command_test.py b/modem/command_test.py new file mode 100644 index 00000000..67c61450 --- /dev/null +++ b/modem/command_test.py @@ -0,0 +1,10 @@ +from command import TxCommand +import codec2 + +class TestCommand(TxCommand): + + def build_frame(self): + return self.frame_factory.build_test() + + def get_tx_mode(self): + return codec2.FREEDV_MODE.datac13.value diff --git a/modem/data_frame_factory.py b/modem/data_frame_factory.py index 15e1d6c1..2c3869a0 100644 --- a/modem/data_frame_factory.py +++ b/modem/data_frame_factory.py @@ -76,3 +76,7 @@ class DataFrameFactory: fec_frame[:1] = bytes([FR_TYPE.FEC.value]) fec_frame[1:payload_per_frame] = bytes(payload[:fec_payload_length]) return fec_frame + + def build_test(self): + test_frame = bytearray(126) + test_frame[:1] = bytes([FR_TYPE.TEST_FRAME.value]) diff --git a/modem/frame_dispatcher.py b/modem/frame_dispatcher.py index aa025032..0e99c4b7 100644 --- a/modem/frame_dispatcher.py +++ b/modem/frame_dispatcher.py @@ -95,13 +95,6 @@ class DISPATCHER(): FR_TYPE.FEC_WAKEUP.value: (self.data_broadcasts.received_fec_wakeup, "FEC WAKEUP"), } - self.command_dispatcher = { - # "CONNECT": (self.arq_session_handler, "CONNECT"), - "CQ": (self.broadcasts.transmit_cq, "CQ"), - "DISCONNECT": (self.arq_session.close_session, "DISCONNECT"), - "SEND_TEST_FRAME": (self.broadcasts.send_test_frame, "TEST"), - "STOP": (self.arq.stop_transmission, "STOP"), - } def _initialize_queues(self): """Initializes data queues.""" @@ -121,47 +114,6 @@ class DISPATCHER(): while True: command = self.data_queue_transmit.get() command.execute(self.event_queue, MODEM_TRANSMIT_QUEUE) - continue - - # Dispatch commands known to command_dispatcher - if data[0] in self.command_dispatcher: - self.log.debug(f"[Modem] TX {self.command_dispatcher[data[0]][1]}...") - self.command_dispatcher[data[0]][0]() - - # Dispatch commands that need more arguments. - elif data[0] == "CONNECT": - # [1] mycallsign - # [2] dxcallsign - self.arq.arq_session_handler(data[1], data[2]) - - elif data[0] == "PING": - # [1] mycallsign // this is being injected as None - # [2] dxcallsign - mycallsign = f"{self.config['STATION']['mycall']}-{self.config['STATION']['myssid']}" - self.ping.transmit_ping(mycallsign, data[2]) - - elif data[0] == "ARQ_RAW": - # [1] DATA_OUT bytes - # [2] self.transmission_uuid str - # [3] mycallsign with ssid str - # [4] dxcallsign with ssid str - self.arq_iss.open_dc_and_transmit(data[1], data[2], data[3], data[4]) - - elif data[0] == "FEC_IS_WRITING": - # [1] DATA_OUT bytes - # [2] MODE str datac0/1/3... - self.broadcasts.send_fec_is_writing(data[1]) - - elif data[0] == "FEC": - # [1] WAKEUP bool - # [2] MODE str datac0/1/3... - # [3] PAYLOAD - # [4] MYCALLSIGN - self.broadcasts.send_fec(data[1], data[2], data[3], data[4]) - else: - self.log.error( - "[Modem] worker_transmit: received invalid command:", data=data - ) def worker_receive(self) -> None: """Queue received data for processing""" diff --git a/modem/server.py b/modem/server.py index 5f1d0032..c58ac9d0 100644 --- a/modem/server.py +++ b/modem/server.py @@ -6,14 +6,16 @@ import serial_ports from config import CONFIG import audio import queue -import server_commands import service_manager import state_manager import ujson as json import websocket_manager as wsm import api_validations as validations -from command import TxCommand -from command_ping import PingCommand +import command_ping +import command_cq +import command_ping +import command_feq +import command_test from queues import DATA_QUEUE_TRANSMIT as tx_cmd_queue app = Flask(__name__) @@ -125,9 +127,10 @@ def get_modem_state(): def post_cqcqcq(): if request.method not in ['POST']: return api_response({"info": "endpoint for triggering a CQ via POST"}) - if app.state_manager.is_modem_running: - server_commands.cqcqcq() - return api_response({"cmd": "cqcqcq"}) + if not app.state_manager.is_modem_running: + api_abort('Modem not running', 503) + enqueue_tx_command(command_cq.CQCommand) + return "ok" @app.route('/modem/beacon', methods=['POST']) def post_beacon(): @@ -147,32 +150,35 @@ def post_ping(): if not app.state_manager.is_modem_running: api_abort('Modem not running', 503) validate(request.json, 'dxcall', validations.validate_freedata_callsign) - enqueue_tx_command(PingCommand, request.json) + enqueue_tx_command(command_ping.PingCommand, request.json) return 'ok' @app.route('/modem/send_test_frame', methods=['POST']) def post_send_test_frame(): if request.method not in ['POST']: return api_response({"info": "endpoint for triggering a TEST_FRAME via POST"}) - if app.state_manager.is_modem_running: - server_commands.modem_send_test_frame() - return api_response({"cmd": "test_frame"}) + if not app.state_manager.is_modem_running: + api_abort('Modem not running', 503) + enqueue_tx_command(command_test.TestCommand) + return "ok" @app.route('/modem/fec_transmit', methods=['POST']) def post_send_fec_frame(): if request.method not in ['POST']: return api_response({"info": "endpoint for triggering a FEC frame via POST"}) - if app.state_manager.is_modem_running: - server_commands.modem_fec_transmit(request.json) - return api_response(request.json) + if not app.state_manager.is_modem_running: + api_abort('Modem not running', 503) + enqueue_tx_command(command_feq.FecCommand, request.json) + return "ok" @app.route('/modem/fec_is_writing', methods=['POST']) def post_send_fec_is_writing(): if request.method not in ['POST']: return api_response({"info": "endpoint for triggering a IS WRITING frame via POST"}) - if app.state_manager.is_modem_running: - server_commands.modem_fec_is_writing(request.json) - return api_response(request.json) + if not app.state_manager.is_modem_running: + api_abort('Modem not running', 503) + #server_commands.modem_fec_is_writing(request.json) + return 'Not implemented yet' @app.route('/modem/start', methods=['POST']) def post_modem_start(): @@ -199,8 +205,11 @@ def get_modem_version(): def post_modem_send_raw(): if request.method not in ['POST']: return api_response({"info": "endpoint for SENDING RAW DATA via POST"}) - server_commands.modem_arq_send_raw(request.json) - return api_response(request.json) + if not app.state_manager.is_modem_running: + api_abort('Modem not running', 503) + + # server_commands.modem_arq_send_raw(request.json) + return "Not implemented yet" # @app.route('/modem/arq_connect', methods=['POST']) # @app.route('/modem/arq_disconnect', methods=['POST']) diff --git a/modem/server_commands.py b/modem/server_commands.py deleted file mode 100644 index 73464167..00000000 --- a/modem/server_commands.py +++ /dev/null @@ -1,66 +0,0 @@ -from queues import DATA_QUEUE_TRANSMIT -import base64 -import structlog -import threading -from random import randrange -log = structlog.get_logger("COMMANDS") - -def cqcqcq(): - try: - DATA_QUEUE_TRANSMIT.put(["CQ"]) - return - except Exception as err: - log.warning("[CMD] error while transmiting CQ", e=err) - -def ping_ping(dxcall): - try: - DATA_QUEUE_TRANSMIT.put(["PING", None, dxcall]) - - except Exception as err: - log.warning( - "[CMD] PING command execution error", e=err - ) - -def modem_send_test_frame(): - - log.info( - "[CMD] Send test frame" - ) - DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"]) - -def modem_arq_send_raw(mycallsign, dxcallsign, payload, arq_uuid = "no-uuid"): - - # wait some random time - threading.Event().wait(randrange(5, 25, 5) / 10.0) - - base64data = payload - - if len(base64data) % 4: - raise TypeError - - binarydata = base64.b64decode(base64data) - - DATA_QUEUE_TRANSMIT.put( - ["ARQ_RAW", binarydata, arq_uuid, mycallsign, dxcallsign] - ) - - -def modem_fec_transmit(mode, wakeup, base64data, mycallsign = None): - log.info( - "[CMD] Send fec frame" - ) - if len(base64data) % 4: - raise TypeError - payload = base64.b64decode(base64data) - - DATA_QUEUE_TRANSMIT.put(["FEC", mode, wakeup, payload, mycallsign]) - -def modem_fec_is_writing(mycallsign): - try: - DATA_QUEUE_TRANSMIT.put(["FEC_IS_WRITING", mycallsign]) - except Exception as err: - log.warning( - "[SCK] Send fec frame command execution error", - e=err, - ) -