Merge branch 'develop' of github.com:DJ2LS/FreeDATA into develop

This commit is contained in:
Mashintime 2023-12-03 22:48:09 -05:00
commit ce12679f2d
15 changed files with 248 additions and 165 deletions

View file

@ -78,7 +78,7 @@
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.17.0",
"typescript": "^5.2.2",
"vite": "^5.0.2",
"vite": "^5.0.4",
"vite-plugin-electron": "^0.15.4",
"vite-plugin-electron-renderer": "^0.14.5",
"vitest": "^0.34.6",

View file

@ -23,7 +23,7 @@ export function connectionFailed(endpoint, event) {
}
export function stateDispatcher(data) {
data = JSON.parse(data);
//console.log(data);
console.log(data);
stateStore.modem_connection = "connected";

View file

@ -4,9 +4,11 @@ from codec2 import FREEDV_MODE
class TxCommand():
def __init__(self, config, logger, apiParams = {}):
def __init__(self, config, logger, state_manager, modem_events, apiParams = {}):
self.config = config
self.logger = logger
self.state_manager = state_manager
self.modem_events = modem_events
self.set_params_from_api(apiParams)
self.frame_factory = DataFrameFactory(config)

36
modem/command_arq_raw.py Normal file
View file

@ -0,0 +1,36 @@
from command import TxCommand
import api_validations
from protocol_arq_iss import ISS
from protocol_arq import ARQ
class ARQRawCommand(TxCommand):
def __int__(self, state_manager):
# open a new arq instance here
self.initialize_arq_instance()
def set_params_from_api(self, apiParams):
self.dxcall = apiParams['dxcall']
if not api_validations.validate_freedata_callsign(self.dxcall):
self.dxcall = f"{self.dxcall}-0"
return super().set_params_from_api(apiParams)
def initialize_arq_transmission_iss(self, data):
if id := self.get_id_from_frame(data):
instance = self.initialize_arq_instance()
self.states.register_arq_instance_by_id(id, instance)
instance['arq_irs'].arq_received_data_channel_opener()
def initialize_arq_instance(self):
self.arq = ARQ(self.config, self.event_queue, self.state_manager)
self.arq_iss = ISS(self.config, self.event_queue, self.state_manager)
return {
'arq': self.arq,
'arq_irs': self.arq_irs,
'arq_iss': self.arq_iss,
'arq_session': self.arq_session
}
def build_frame(self):
return self.frame_factory.build_arq_connect(destination=self.dxcall, session_id=b'', isWideband=True)

View file

@ -9,7 +9,7 @@ import structlog
import event_manager
import command_qrv
from data_handler import DATA
from deprecated_data_handler import DATA
TESTMODE = False

View file

@ -5,7 +5,7 @@ import time
import modem
import base64
import ujson as json
from data_handler import DATA
from deprecated_data_handler import DATA
class DATABROADCAST(DATA):
"""Terminal Node Controller for FreeDATA"""

View file

@ -4,7 +4,7 @@ from codec2 import FREEDV_MODE
import helpers
import uuid
import structlog
from data_handler import DATA
from deprecated_data_handler import DATA
class PING(DATA):
def __init__(self, config, event_queue, states):
super().__init__(config, event_queue, states)

View file

@ -657,4 +657,15 @@ class Demodulator():
# only take every tenth data point
self.event_manager.send_scatter_change(scatterdata[::10])
def reset_data_sync(self) -> None:
"""
reset sync state for data modes
:param frames_per_burst: Number of frames per burst requested
:type frames_per_burst: int
"""
codec2.api.freedv_set_sync(self.dat0_datac1_freedv, 0)
codec2.api.freedv_set_sync(self.dat0_datac3_freedv, 0)
codec2.api.freedv_set_sync(self.dat0_datac4_freedv, 0)
codec2.api.freedv_set_sync(self.fsk_ldpc_freedv_0, 0)

View file

@ -4,16 +4,15 @@ FRAME DISPATCHER - We are dispatching the received frames to the needed function
"""
import threading
import helpers
import structlog
from modem_frametypes import FRAME_TYPE as FR_TYPE
import event_manager
from queues import DATA_QUEUE_RECEIVED, DATA_QUEUE_TRANSMIT, MODEM_TRANSMIT_QUEUE
from data_frame_factory import DataFrameFactory
from data_handler_broadcasts import BROADCAST
from data_handler_data_broadcasts import DATABROADCAST
from data_handler_ping import PING
#from deprecated_data_handler_broadcasts import BROADCAST
#from deprecated_data_handler_data_broadcasts import DATABROADCAST
#from deprecated_data_handler_ping import PING
from protocol_arq_iss import ISS
from protocol_arq_irs import IRS
@ -59,7 +58,7 @@ class DISPATCHER():
self.states = states
self._initialize_handlers(config, event_queue, states)
self._initialize_dispatchers()
#self._initialize_dispatchers()
self.data_queue_transmit = DATA_QUEUE_TRANSMIT
self.data_queue_received = data_q_rx
@ -71,18 +70,170 @@ class DISPATCHER():
self.frame_factory = DataFrameFactory(config)
self.broadcasts = BROADCAST(config, event_queue, states)
self.data_broadcasts = DATABROADCAST(config, event_queue, states)
self.ping = PING(config, event_queue, states)
#self.broadcasts = BROADCAST(config, event_queue, states)
#self.data_broadcasts = DATABROADCAST(config, event_queue, states)
#self.ping = PING(config, event_queue, states)
self.arq = ARQ(config, event_queue, states)
self.arq_irs = IRS(config, event_queue, states)
self.arq_iss = ISS(config, event_queue, states)
self.arq_session = SESSION(config, event_queue, states)
self.event_manager = event_manager.EventManager([event_queue])
def start(self):
"""Starts worker threads for transmit and receive operations."""
threading.Thread(target=self.worker_transmit, name="Transmit Worker", daemon=True).start()
threading.Thread(target=self.worker_receive, name="Receive Worker", daemon=True).start()
def worker_transmit(self) -> None:
"""Dispatch incoming UI instructions for transmitting operations"""
while True:
command = self.data_queue_transmit.get()
command.run(self.event_queue, MODEM_TRANSMIT_QUEUE)
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, 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(
"[Modem] ARQ - other frame type", frametype=FR_TYPE(frametype).name)
return
# instantiate handler
handler_class = self.FRAME_HANDLER[frametype]['class']
handler = handler_class(self.FRAME_HANDLER[frametype]['name'],
self.config,
self.states,
self.event_manager,
MODEM_TRANSMIT_QUEUE,
self.arq_sessions)
handler.handle(deconstructed_frame, snr, offset, freedv, bytes_per_frame)
def get_id_from_frame(self, data):
if data[:1] in [FR_TYPE.ARQ_DC_OPEN_N, FR_TYPE.ARQ_DC_OPEN_W]:
return data[13:14]
return None
def initialize_arq_instance(self):
self.arq = ARQ(self.config, self.event_queue, self.states)
self.arq_irs = IRS(self.config, self.event_queue, self.states)
self.arq_iss = ISS(self.config, self.event_queue, self.states)
self.arq_session = SESSION(self.config, self.event_queue, self.states)
return {
'arq': self.arq,
'arq_irs': self.arq_irs,
'arq_iss': self.arq_iss,
'arq_session': self.arq_session
}
def initialize_arq_transmission_irs(self, data):
if id := self.get_id_from_frame(data):
instance = self.initialize_arq_instance()
self.states.register_arq_instance_by_id(id, instance)
instance['arq_irs'].arq_received_data_channel_opener()
def old_process_data(self, bytes_out, freedv, bytes_per_frame: int, snr) -> None:
"""
Process incoming data and decide what to do with the frame.
Args:
bytes_out:
freedv:
bytes_per_frame:
snr:
Returns:
"""
# get frame as dictionary
deconstructed_frame = self.frame_factory.deconstruct(bytes_out)
frametype = deconstructed_frame["frame_type_int"]
if frametype not in self.rx_dispatcher:
self.log.warning(
"[Modem] ARQ - other frame type", frametype=FR_TYPE(frametype).name)
return
# Process frametypes requiring a different set of arguments.
if FR_TYPE.BURST_51.value >= frametype >= FR_TYPE.BURST_01.value:
self.arq_irs.arq_data_received(
deconstructed_frame, bytes_per_frame, snr, freedv
)
# if we received the last frame of a burst or the last remaining rpt frame, do a modem unsync
# if self.arq_rx_burst_buffer.count(None) <= 1 or (frame+1) == n_frames_per_burst:
# self.log.debug(f"[Modem] LAST FRAME OF BURST --> UNSYNC {frame+1}/{n_frames_per_burst}")
# self.c_lib.freedv_set_sync(freedv, 0)
return
# TESTFRAMES
if frametype == FR_TYPE.TEST_FRAME.value:
self.log.debug("[Modem] TESTFRAME RECEIVED", frame=deconstructed_frame)
return
# Process frames "known" by rx_dispatcher
# self.log.debug(f"[Modem] {self.rx_dispatcher[frametype][1]} RECEIVED....")
self.rx_dispatcher[frametype][0](deconstructed_frame, snr)
def _initialize_dispatchers(self):
"""Initializes dispatchers for handling different frame types."""
# Dictionary of functions and log messages used in process_data
@ -131,136 +282,3 @@ class DISPATCHER():
FR_TYPE.FEC.value: (self.data_broadcasts.received_fec, "FEC"),
FR_TYPE.FEC_WAKEUP.value: (self.data_broadcasts.received_fec_wakeup, "FEC WAKEUP"),
}
def start(self):
"""Starts worker threads for transmit and receive operations."""
threading.Thread(target=self.worker_transmit, name="Transmit Worker", daemon=True).start()
threading.Thread(target=self.worker_receive, name="Receive Worker", daemon=True).start()
def worker_transmit(self) -> None:
"""Dispatch incoming UI instructions for transmitting operations"""
while True:
command = self.data_queue_transmit.get()
command.run(self.event_queue, MODEM_TRANSMIT_QUEUE)
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, 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(
"[Modem] ARQ - other frame type", frametype=FR_TYPE(frametype).name)
return
# instantiate handler
handler_class = self.FRAME_HANDLER[frametype]['class']
handler = handler_class(self.FRAME_HANDLER[frametype]['name'],
self.config,
self.states,
self.event_manager,
MODEM_TRANSMIT_QUEUE,
self.arq_sessions)
activity = {
"direction": "received",
"snr": snr,
"offset": offset,
"activity_type": self.FRAME_HANDLER[frametype]['name']
}
if "origin" in deconstructed_frame:
activity["origin"] = deconstructed_frame["origin"]
if "destination" in deconstructed_frame:
activity["destination"] = deconstructed_frame["destination"]
if "gridsquare" in deconstructed_frame:
activity["gridsquare"] = deconstructed_frame["gridsquare"]
if "session_id" in deconstructed_frame:
activity["session_id"] = deconstructed_frame["session_id"]
self.states.add_activity(activity)
handler.handle(deconstructed_frame, snr, offset, freedv, bytes_per_frame)
def old_process_data(self, bytes_out, freedv, bytes_per_frame: int, snr) -> None:
"""
Process incoming data and decide what to do with the frame.
Args:
bytes_out:
freedv:
bytes_per_frame:
snr:
Returns:
"""
# get frame as dictionary
deconstructed_frame = self.frame_factory.deconstruct(bytes_out)
frametype = deconstructed_frame["frame_type_int"]
if frametype not in self.rx_dispatcher:
self.log.warning(
"[Modem] ARQ - other frame type", frametype=FR_TYPE(frametype).name)
return
# Process frametypes requiring a different set of arguments.
if FR_TYPE.BURST_51.value >= frametype >= FR_TYPE.BURST_01.value:
self.arq_irs.arq_data_received(
deconstructed_frame, bytes_per_frame, snr, freedv
)
# if we received the last frame of a burst or the last remaining rpt frame, do a modem unsync
# if self.arq_rx_burst_buffer.count(None) <= 1 or (frame+1) == n_frames_per_burst:
# self.log.debug(f"[Modem] LAST FRAME OF BURST --> UNSYNC {frame+1}/{n_frames_per_burst}")
# self.c_lib.freedv_set_sync(freedv, 0)
return
# TESTFRAMES
if frametype == FR_TYPE.TEST_FRAME.value:
self.log.debug("[Modem] TESTFRAME RECEIVED", frame=deconstructed_frame)
return
# Process frames "known" by rx_dispatcher
# self.log.debug(f"[Modem] {self.rx_dispatcher[frametype][1]} RECEIVED....")
self.rx_dispatcher[frametype][0](deconstructed_frame, snr)
def get_id_from_frame(self, data):
if data[:1] in [FR_TYPE.ARQ_DC_OPEN_N, FR_TYPE.ARQ_DC_OPEN_W]:
return data[13:14]
return None
def initialize_arq_instance(self):
self.arq = ARQ(self.config, self.event_queue, self.states)
self.arq_irs = IRS(self.config, self.event_queue, self.states)
self.arq_iss = ISS(self.config, self.event_queue, self.states)
self.arq_session = SESSION(self.config, self.event_queue, self.states)
return {
'arq': self.arq,
'arq_irs': self.arq_irs,
'arq_iss': self.arq_iss,
'arq_session': self.arq_session
}
def initialize_arq_transmission_irs(self, data):
if id := self.get_id_from_frame(data):
instance = self.initialize_arq_instance()
self.states.register_arq_instance_by_id(id, instance)
instance['arq_irs'].arq_received_data_channel_opener()

View file

@ -28,6 +28,32 @@ class FrameHandler():
'bytes_per_frame': 0
}
def add_to_activity_list(self):
frame = self.details['frame']
activity = {
"direction": "received",
"snr": self.details['snr'],
"freq_offset": self.details['freq_offset'],
"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)
def add_to_heard_stations(self):
frame = self.details['frame']
@ -97,5 +123,6 @@ class FrameHandler():
self.log()
self.add_to_heard_stations()
self.add_to_activity_list()
self.emit_event()
self.follow_protocol()

View file

@ -2,7 +2,7 @@ import frame_handler_ping
import helpers
import data_frame_factory
import frame_handler
class CQFrameHandler(frame_handler.FrameHandler):
class CQFrameHandler(frame_handler_ping.PingFrameHandler):
def should_respond(self):
self.logger.debug(f"Respond to CQ: {self.config['MODEM']['respond_to_cq']}")

View file

@ -302,7 +302,7 @@ class RF:
frames:
"""
self.reset_data_sync()
self.demodulator.reset_data_sync()
if mode == codec2.FREEDV_MODE.datac0.value:
freedv = self.freedv_datac0_tx
@ -866,19 +866,6 @@ class RF:
# else 0
self.fft_queue.put([0])
def reset_data_sync(self) -> None:
"""
reset sync state for data modes
:param frames_per_burst: Number of frames per burst requested
:type frames_per_burst: int
"""
#codec2.api.freedv_set_sync(self.dat0_datac1_freedv, 0)
#codec2.api.freedv_set_sync(self.dat0_datac3_freedv, 0)
#codec2.api.freedv_set_sync(self.dat0_datac4_freedv, 0)
#codec2.api.freedv_set_sync(self.fsk_ldpc_freedv_0, 0)
def set_FFT_stream(self, enable: bool):
# Set config boolean regarding wheter it should sent FFT data to queue
self.enable_fft_stream = enable

View file

@ -11,7 +11,6 @@ from codec2 import FREEDV_MODE, FREEDV_MODE_USED_SLOTS
from modem_frametypes import FRAME_TYPE as FR_TYPE
import event_manager
from data_handler import DATA
TESTMODE = False
class ARQ:
def __init__(self, config, event_queue, states):

View file

@ -16,6 +16,8 @@ import command_cq
import command_ping
import command_feq
import command_test
import command_arq_raw
from queues import DATA_QUEUE_TRANSMIT as tx_cmd_queue
app = Flask(__name__)
@ -82,7 +84,7 @@ def validate(req, param, validator, isRequired = True):
# Takes a transmit command and puts it in the transmit command queue
def enqueue_tx_command(cmd_class, params = {}):
command = cmd_class(app.config_manager.read(), app.logger, params)
command = cmd_class(app.config_manager.read(), app.logger, app.state_manager, app.modem_events, params)
tx_cmd_queue.put(command)
app.logger.info(f"Command {command.get_name()} enqueued.")
@ -210,6 +212,7 @@ def post_modem_send_raw():
return api_response({"info": "endpoint for SENDING RAW DATA via POST"})
if not app.state_manager.is_modem_running:
api_abort('Modem not running', 503)
enqueue_tx_command(command_arq_raw.ARQRawCommand, request.json)
# server_commands.modem_arq_send_raw(request.json)
return "Not implemented yet"