mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Refactoring of tx commands - WIP
This commit is contained in:
parent
5c34ef40da
commit
5bb25c3d45
7 changed files with 71 additions and 38 deletions
25
modem/command.py
Normal file
25
modem/command.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from data_frame_factory import DataFrameFactory
|
||||||
|
from modem.modem import RF
|
||||||
|
|
||||||
|
class TxCommand():
|
||||||
|
|
||||||
|
def __init__(self, modem: RF, apiParams):
|
||||||
|
self.setParamsFromApi(apiParams)
|
||||||
|
self.modem = modem
|
||||||
|
self.frame_factory = DataFrameFactory(modem)
|
||||||
|
|
||||||
|
def setParamsFromApi(self, apiParams):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getPayload(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def execute(self, modem):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def transmit(self, frame):
|
||||||
|
# MODEM_TRANSMIT_QUEUE.put([c2_mode, copies, repeat_delay, frame_to_tx])
|
||||||
|
|
||||||
|
self.modem.modem_transmit_queue.put(
|
||||||
|
|
||||||
|
)
|
3
modem/command_cq.py
Normal file
3
modem/command_cq.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from command import TxCommand
|
||||||
|
|
||||||
|
class CQCommand(TxCommand):
|
11
modem/command_ping.py
Normal file
11
modem/command_ping.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from command import TxCommand
|
||||||
|
|
||||||
|
class PingCommand(TxCommand):
|
||||||
|
|
||||||
|
def setParamsFromApi(self, apiParams):
|
||||||
|
self.dxcall = apiParams['dxcall']
|
||||||
|
return super().setParamsFromApi()
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
self.frame_factory.build_ping(self.dxcall)
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
from modem_frametypes import FRAME_TYPE as FR_TYPE
|
from modem_frametypes import FRAME_TYPE as FR_TYPE
|
||||||
import helpers
|
import helpers
|
||||||
|
import codec2
|
||||||
|
|
||||||
class DataFrameFactory:
|
class DataFrameFactory:
|
||||||
|
|
||||||
def __init__(self, modem_config, modem_state, **data):
|
def __init__(self, modem):
|
||||||
self.modem_config = modem_config
|
self.modem_config = modem.config
|
||||||
self.modem_state = modem_state
|
self.modem_state = modem.state
|
||||||
self.data = data
|
|
||||||
|
|
||||||
self.myfullcall = f"{modem_config['STATION']['mycall']}-{modem_config['STATION']['myssid']}"
|
self.myfullcall = f"{self.modem_config['STATION']['mycall']}-{self.modem_config['STATION']['myssid']}"
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
build_method = getattr(self, self.type.name)
|
build_method = getattr(self, self.type.name)
|
||||||
return build_method()
|
return build_method()
|
||||||
|
|
||||||
def build_ping(self):
|
def build_ping(self, dxcallsign):
|
||||||
ping_frame = bytearray(self.length_sig0_frame)
|
ping_frame = bytearray(self.length_sig0_frame)
|
||||||
ping_frame[:1] = bytes(self.type.value)
|
ping_frame[:1] = bytes(self.type.value)
|
||||||
ping_frame[1:4] = helpers.get_crc_24(self.data['dxcallsign'])
|
ping_frame[1:4] = helpers.get_crc_24(dxcallsign)
|
||||||
ping_frame[4:7] = helpers.get_crc_24(self.myfullcall)
|
ping_frame[4:7] = helpers.get_crc_24(self.myfullcall)
|
||||||
ping_frame[7:13] = helpers.callsign_to_bytes(self.myfullcall)
|
ping_frame[7:13] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
return ping_frame
|
return ping_frame
|
||||||
|
@ -25,20 +25,20 @@ class DataFrameFactory:
|
||||||
def build_cq(self):
|
def build_cq(self):
|
||||||
cq_frame = bytearray(self.length_sig0_frame)
|
cq_frame = bytearray(self.length_sig0_frame)
|
||||||
cq_frame[:1] = bytes([FR_TYPE.CQ.value])
|
cq_frame[:1] = bytes([FR_TYPE.CQ.value])
|
||||||
cq_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign)
|
cq_frame[1:7] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
cq_frame[7:11] = helpers.encode_grid(self.mygrid)
|
cq_frame[7:11] = helpers.encode_grid(self.mygrid)
|
||||||
return cq_frame
|
return cq_frame
|
||||||
|
|
||||||
def build_fec_is_writing(self):
|
def build_fec_is_writing(self):
|
||||||
fec_frame = bytearray(14)
|
fec_frame = bytearray(14)
|
||||||
fec_frame[:1] = bytes([FR_TYPE.IS_WRITING.value])
|
fec_frame[:1] = bytes([FR_TYPE.IS_WRITING.value])
|
||||||
fec_frame[1:7] = helpers.callsign_to_bytes(mycallsign)
|
fec_frame[1:7] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
return fec_frame
|
return fec_frame
|
||||||
|
|
||||||
def build_qrv(self):
|
def build_qrv(self):
|
||||||
qrv_frame = bytearray(self.length_sig0_frame)
|
qrv_frame = bytearray(self.length_sig0_frame)
|
||||||
qrv_frame[:1] = bytes([FR_TYPE.QRV.value])
|
qrv_frame[:1] = bytes([FR_TYPE.QRV.value])
|
||||||
qrv_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign)
|
qrv_frame[1:7] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
qrv_frame[7:11] = helpers.encode_grid(self.mygrid)
|
qrv_frame[7:11] = helpers.encode_grid(self.mygrid)
|
||||||
qrv_frame[11:12] = helpers.snr_to_bytes(snr)
|
qrv_frame[11:12] = helpers.snr_to_bytes(snr)
|
||||||
return qrv_frame
|
return qrv_frame
|
||||||
|
@ -46,16 +46,16 @@ class DataFrameFactory:
|
||||||
def build_beacon(self):
|
def build_beacon(self):
|
||||||
beacon_frame = bytearray(self.length_sig0_frame)
|
beacon_frame = bytearray(self.length_sig0_frame)
|
||||||
beacon_frame[:1] = bytes([FR_TYPE.BEACON.value])
|
beacon_frame[:1] = bytes([FR_TYPE.BEACON.value])
|
||||||
beacon_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign)
|
beacon_frame[1:7] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
beacon_frame[7:11] = helpers.encode_grid(self.mygrid)
|
beacon_frame[7:11] = helpers.encode_grid(self.mygrid)
|
||||||
return beacon_frame
|
return beacon_frame
|
||||||
|
|
||||||
def build_fec_wakeup(self):
|
def build_fec_wakeup(self):
|
||||||
mode_int_wakeup = codec2.freedv_get_mode_value_by_name("sig0")
|
mode_int_wakeup = codec2.freedv_get_mode_value_by_name("sig0")
|
||||||
payload_per_wakeup_frame = modem.get_bytes_per_frame(mode_int_wakeup) - 2
|
payload_per_wakeup_frame = self.modem.get_bytes_per_frame(mode_int_wakeup) - 2
|
||||||
fec_wakeup_frame = bytearray(payload_per_wakeup_frame)
|
fec_wakeup_frame = bytearray(payload_per_wakeup_frame)
|
||||||
fec_wakeup_frame[:1] = bytes([FR_TYPE.FEC_WAKEUP.value])
|
fec_wakeup_frame[:1] = bytes([FR_TYPE.FEC_WAKEUP.value])
|
||||||
fec_wakeup_frame[1:7] = helpers.callsign_to_bytes(mycallsign)
|
fec_wakeup_frame[1:7] = helpers.callsign_to_bytes(self.myfullcall)
|
||||||
fec_wakeup_frame[7:8] = bytes([mode_int])
|
fec_wakeup_frame[7:8] = bytes([mode_int])
|
||||||
fec_wakeup_frame[8:9] = bytes([1]) # n payload bursts
|
fec_wakeup_frame[8:9] = bytes([1]) # n payload bursts
|
||||||
return fec_wakeup_frame
|
return fec_wakeup_frame
|
||||||
|
|
|
@ -27,7 +27,6 @@ class DISPATCHER():
|
||||||
self._initialize_handlers(config, event_queue, states)
|
self._initialize_handlers(config, event_queue, states)
|
||||||
self._initialize_dispatchers()
|
self._initialize_dispatchers()
|
||||||
self._initialize_queues()
|
self._initialize_queues()
|
||||||
self._start_worker_threads()
|
|
||||||
|
|
||||||
def _initialize_handlers(self, config, event_queue, states):
|
def _initialize_handlers(self, config, event_queue, states):
|
||||||
"""Initializes various data handlers."""
|
"""Initializes various data handlers."""
|
||||||
|
@ -109,34 +108,19 @@ class DISPATCHER():
|
||||||
threading.Thread(target=self.worker_transmit, name="Transmit Worker", daemon=True).start()
|
threading.Thread(target=self.worker_transmit, name="Transmit Worker", daemon=True).start()
|
||||||
threading.Thread(target=self.worker_receive, name="Receive Worker", daemon=True).start()
|
threading.Thread(target=self.worker_receive, name="Receive Worker", daemon=True).start()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self._start_worker_threads()
|
||||||
|
|
||||||
def worker_transmit(self) -> None:
|
def worker_transmit(self) -> None:
|
||||||
"""Dispatch incoming UI instructions for transmitting operations"""
|
"""Dispatch incoming UI instructions for transmitting operations"""
|
||||||
while True:
|
while True:
|
||||||
data = self.data_queue_transmit.get()
|
data = self.data_queue_transmit.get()
|
||||||
# if we are already in ARQ_STATE, or we're receiving codec2 traffic
|
|
||||||
# let's wait with processing data
|
|
||||||
# this should avoid weird toggle states where both stations
|
|
||||||
# stuck in IRS
|
|
||||||
#
|
|
||||||
# send transmission queued information once
|
|
||||||
if self.states.is_arq_state or self.states.is_codec2_traffic:
|
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"[Modem] TX DISPATCHER - waiting with processing command ",
|
"[Modem] TX DISPATCHER - got a transmit command",
|
||||||
is_arq_state=self.states.is_arq_state,
|
command=data,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.send_data_to_socket_queue(
|
|
||||||
freedata="modem-message",
|
|
||||||
command=data[0],
|
|
||||||
status="queued",
|
|
||||||
)
|
|
||||||
|
|
||||||
# now stay in while loop until state released
|
|
||||||
while self.states.is_arq_state or self.states.is_codec2_traffic:
|
|
||||||
threading.Event().wait(0.01)
|
|
||||||
|
|
||||||
# and finally sleep some time
|
|
||||||
threading.Event().wait(1.0)
|
|
||||||
|
|
||||||
# Dispatch commands known to command_dispatcher
|
# Dispatch commands known to command_dispatcher
|
||||||
if data[0] in self.command_dispatcher:
|
if data[0] in self.command_dispatcher:
|
||||||
|
|
|
@ -12,6 +12,9 @@ import state_manager
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import websocket_manager as wsm
|
import websocket_manager as wsm
|
||||||
import api_validations as validations
|
import api_validations as validations
|
||||||
|
from tx_command.tx_command import TxCommand
|
||||||
|
from tx_command.ping_command import PingCommand
|
||||||
|
from queues import DATA_QUEUE_TRANSMIT as tx_cmd_queue
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
@ -72,6 +75,12 @@ def validate(req, param, validator, isRequired = True):
|
||||||
if not validator(req[param]):
|
if not validator(req[param]):
|
||||||
api_abort(f"Value of '{param}' is invalid.", 400)
|
api_abort(f"Value of '{param}' is invalid.", 400)
|
||||||
|
|
||||||
|
# Takes a transmit command and puts it in the transmit command queue
|
||||||
|
def enqueue_tx_command(cmd_class, params = {}):
|
||||||
|
command = cmd_class(modem, params)
|
||||||
|
tx_cmd_queue.put(command)
|
||||||
|
app.logger.info(f"Command {type(command).__name__} enqueued.")
|
||||||
|
|
||||||
## REST API
|
## REST API
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
def index():
|
def index():
|
||||||
|
@ -138,8 +147,8 @@ def post_ping():
|
||||||
if not app.state_manager.is_modem_running:
|
if not app.state_manager.is_modem_running:
|
||||||
api_abort('Modem not running', 503)
|
api_abort('Modem not running', 503)
|
||||||
validate(request.json, 'dxcall', validations.validate_freedata_callsign)
|
validate(request.json, 'dxcall', validations.validate_freedata_callsign)
|
||||||
server_commands.ping_ping(request.json['dxcall'])
|
enqueue_tx_command(PingCommand, request.json)
|
||||||
return api_response(request.json)
|
return 'ok'
|
||||||
|
|
||||||
@app.route('/modem/send_test_frame', methods=['POST'])
|
@app.route('/modem/send_test_frame', methods=['POST'])
|
||||||
def post_send_test_frame():
|
def post_send_test_frame():
|
||||||
|
|
|
@ -72,6 +72,7 @@ class SM:
|
||||||
self.modem = modem.RF(self.config, self.modem_events, self.modem_fft, self.modem_service, self.states)
|
self.modem = modem.RF(self.config, self.modem_events, self.modem_fft, self.modem_service, self.states)
|
||||||
#self.data_handler = data_handler.DATA(self.config, self.modem_events, self.states)
|
#self.data_handler = data_handler.DATA(self.config, self.modem_events, self.states)
|
||||||
self.frame_dispatcher = frame_dispatcher.DISPATCHER(self.config, self.modem_events, self.states)
|
self.frame_dispatcher = frame_dispatcher.DISPATCHER(self.config, self.modem_events, self.states)
|
||||||
|
self.frame_dispatcher.start()
|
||||||
self.states.set("is_modem_running", True)
|
self.states.set("is_modem_running", True)
|
||||||
self.modem.set_FFT_stream(self.enable_fft)
|
self.modem.set_FFT_stream(self.enable_fft)
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in a new issue