From e5208cffffcc81692a7bf668ca7f88a06a2ce686 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Mon, 19 May 2025 08:54:24 +0200 Subject: [PATCH] adjustments to modem tests - still not working yet. but we have first benefits of new modem structure --- freedata_server/context.py | 2 + freedata_server/demodulator.py | 7 ++- freedata_server/modem.py | 14 +++-- freedata_server/service_manager.py | 15 ++--- tests/test_arq_session.py | 97 +++++++++++++++--------------- tests/test_message_p2p.py | 1 - 6 files changed, 74 insertions(+), 62 deletions(-) diff --git a/freedata_server/context.py b/freedata_server/context.py index 8dbedd3f..e937cee3 100644 --- a/freedata_server/context.py +++ b/freedata_server/context.py @@ -30,6 +30,8 @@ class AppContext: self.message_system_db_manager = DatabaseManager(self) self.message_system_db_attachments = DatabaseManagerAttachments(self) + self.TESTMODE = False + def startup(self): # initially read config diff --git a/freedata_server/demodulator.py b/freedata_server/demodulator.py index 20c55303..0aad30b2 100644 --- a/freedata_server/demodulator.py +++ b/freedata_server/demodulator.py @@ -120,7 +120,10 @@ class Demodulator(): self.MODE_DICT[mode]["nin"] = nin def start(self, stream): - self.stream = stream + if self.ctx.TESTMODE: + self.stream = None + else: + self.stream = stream for mode in self.MODE_DICT: # Start decoder threads @@ -160,7 +163,7 @@ class Demodulator(): last_rx_status = 0 try: - while self.stream and self.stream.active and not self.shutdown_flag.is_set(): + while self.stream and self.stream.active and not self.shutdown_flag.is_set() or self.ctx.TESTMODE: threading.Event().wait(0.01) if audiobuffer.nbuffer >= nin and not self.shutdown_flag.is_set(): # demodulate audio diff --git a/freedata_server/modem.py b/freedata_server/modem.py index 96e2266c..66cde5cc 100644 --- a/freedata_server/modem.py +++ b/freedata_server/modem.py @@ -20,7 +20,6 @@ import audio import demodulator import modulator -TESTMODE = False class RF: """Handles FreeDATA modem functionality. @@ -44,7 +43,7 @@ class RF: states (StateManager): State manager instance. radio_manager (RadioManager): Radio manager instance. """ - + self.ctx = ctx self.sampler_avg = 0 self.buffer_avg = 0 @@ -99,7 +98,10 @@ class RF: Raises: RuntimeError: If audio device initialization fails. """ - if TESTMODE: + if self.ctx.TESTMODE: + self.log.warning("RUNNING IN TEST MODE") + self.resampler = codec2.resampler() # we need a resampler in test mode + self.demodulator.start(None) return True else: if not self.init_audio(): @@ -324,7 +326,11 @@ class RF: self.ctx.event_manager.send_ptt_change(True) # slice audio data to needed blocklength - block_size = self.sd_output_stream.blocksize + if self.ctx.TESTMODE: + block_size = 2400 + else: + block_size = self.sd_output_stream.blocksize + pad_length = -len(audio_48k) % block_size padded_data = np.pad(audio_48k, (0, pad_length), mode='constant') sliced_audio_data = padded_data.reshape(-1, block_size) diff --git a/freedata_server/service_manager.py b/freedata_server/service_manager.py index 4b22ed09..08e9cb89 100644 --- a/freedata_server/service_manager.py +++ b/freedata_server/service_manager.py @@ -129,13 +129,14 @@ class SM: self.log.warning("freedata_server already running") return False - # test audio devices - audio_test = self.test_audio() - if False in audio_test or None in audio_test or self.ctx.state_manager.is_modem_running: - self.log.warning("starting freedata_server failed", input_test=audio_test[0], output_test=audio_test[1]) - self.ctx.state_manager.set("is_modem_running", False) - self.ctx.event_manager.modem_failed() - return False + if not self.ctx.TESTMODE: + # test audio devices + audio_test = self.test_audio() + if False in audio_test or None in audio_test or self.ctx.state_manager.is_modem_running: + self.log.warning("starting freedata_server failed", input_test=audio_test[0], output_test=audio_test[1]) + self.ctx.state_manager.set("is_modem_running", False) + self.ctx.event_manager.modem_failed() + return False self.log.info("starting freedata_server....") self.ctx.rf_modem = modem.RF(self.ctx) diff --git a/tests/test_arq_session.py b/tests/test_arq_session.py index cba96211..e3463183 100644 --- a/tests/test_arq_session.py +++ b/tests/test_arq_session.py @@ -4,7 +4,9 @@ sys.path.append('freedata_server') import unittest import unittest.mock -from config import CONFIG +import config +from context import AppContext + import helpers import queue import threading @@ -20,6 +22,8 @@ from state_manager import StateManager from data_frame_factory import DataFrameFactory import codec2 import arq_session_irs +import os + class TestModem: def __init__(self, event_q, state_q): self.data_queue_received = queue.Queue() @@ -54,47 +58,45 @@ class TestModem: } self.data_queue_received.put(transmission) +class DummyCtx: + def __init__(self): + pass + + + class TestARQSession(unittest.TestCase): @classmethod def setUpClass(cls): - config_manager = CONFIG('freedata_server/config.ini.example') - cls.config = config_manager.read() + + # TODO: + # ESTABLISH MODEM CHANNELS CORRECTLY SO WE ARE GETTING THE CORRESPINDING BURSTS + cls.logger = structlog.get_logger("TESTS") - cls.frame_factory = DataFrameFactory(cls.config) # ISS - cls.iss_state_manager = StateManager(queue.Queue()) - cls.iss_state_manager.set_channel_busy_condition_codec2(False) - cls.iss_event_manager = EventManager([queue.Queue()]) - cls.iss_event_queue = queue.Queue() - cls.iss_state_queue = queue.Queue() - cls.iss_modem = TestModem(cls.iss_event_queue, cls.iss_state_queue) - cls.iss_frame_dispatcher = DISPATCHER(cls.config, - cls.iss_event_manager, - cls.iss_state_manager, - cls.iss_modem, None) + cls.ctx_ISS = AppContext('freedata_server/config.ini.example') + cls.ctx_ISS.TESTMODE = True + cls.ctx_ISS.startup() + # IRS - cls.irs_state_manager = StateManager(queue.Queue()) - cls.iss_state_manager.set_channel_busy_condition_codec2(False) - - cls.irs_event_manager = EventManager([queue.Queue()]) - cls.irs_event_queue = queue.Queue() - cls.irs_state_queue = queue.Queue() - cls.irs_modem = TestModem(cls.irs_event_queue, cls.irs_state_queue) - cls.irs_frame_dispatcher = DISPATCHER(cls.config, - cls.irs_event_manager, - cls.irs_state_manager, - cls.irs_modem, None) + cls.ctx_IRS = AppContext('freedata_server/config.ini.example') + cls.ctx_IRS.TESTMODE = True + cls.ctx_IRS.startup() # simulate a busy condition - cls.irs_state_manager.channel_busy_slot = [True, False, False, False, False] + cls.ctx_IRS.state_manager.channel_busy_slot = [True, False, False, False, False] # Frame loss probability in % cls.loss_probability = 0 - cls.channels_running = True + + + + cls.channels_running = False + + def channelWorker(self, modem_transmit_queue: queue.Queue, frame_dispatcher: DISPATCHER): while self.channels_running: @@ -126,23 +128,22 @@ class TestARQSession(unittest.TestCase): break def establishChannels(self): - self.channels_running = True - self.iss_to_irs_channel = threading.Thread(target=self.channelWorker, - args=[self.iss_modem.data_queue_received, - self.irs_frame_dispatcher], + self.iss_to_irs_channel = threading.Thread(target=self.channelWorker, + args=[self.ctx_ISS.rf_modem.data_queue_received, + self.ctx_IRS.service_manager.frame_dispatcher], name = "ISS to IRS channel") self.iss_to_irs_channel.start() self.irs_to_iss_channel = threading.Thread(target=self.channelWorker, - args=[self.irs_modem.data_queue_received, - self.iss_frame_dispatcher], + args=[self.ctx_IRS.rf_modem.data_queue_received, + self.ctx_ISS.service_manager.frame_dispatcher], name = "IRS to ISS channel") self.irs_to_iss_channel.start() - + self.channels_running = True def waitAndCloseChannels(self): - self.waitForSession(self.iss_event_queue, True) + self.waitForSession(self.ctx_ISS.modem_events, True) self.channels_running = False - self.waitForSession(self.irs_event_queue, False) + self.waitForSession(self.ctx_IRS.modem_events, False) self.channels_running = False def DisabledtestARQSessionSmallPayload(self): @@ -155,8 +156,8 @@ class TestARQSession(unittest.TestCase): 'data': base64.b64encode(bytes("Hello world!", encoding="utf-8")), 'type': "raw_lzma" } - cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) - cmd.run(self.iss_event_queue, self.iss_modem) + cmd = ARQRawCommand(self.ctx_ISS, params) + cmd.run() self.waitAndCloseChannels() del cmd @@ -170,8 +171,8 @@ class TestARQSession(unittest.TestCase): 'data': base64.b64encode(np.random.bytes(1000)), 'type': "raw_lzma" } - cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) - cmd.run(self.iss_event_queue, self.iss_modem) + cmd = ARQRawCommand(self.ctx_ISS, params) + cmd.run() self.waitAndCloseChannels() del cmd @@ -185,12 +186,12 @@ class TestARQSession(unittest.TestCase): 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(100)), } - cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) - cmd.run(self.iss_event_queue, self.iss_modem) + cmd = ARQRawCommand(self.ctx_ISS, params) + cmd.run() threading.Event().wait(np.random.randint(10,10)) - for id in self.iss_state_manager.arq_iss_sessions: - self.iss_state_manager.arq_iss_sessions[id].abort_transmission() + for id in self.ctx_ISS.state_manager.arq_iss_sessions: + self.ctx_ISS.state_manager.arq_iss_sessions[id].abort_transmission() self.waitAndCloseChannels() del cmd @@ -204,12 +205,12 @@ class TestARQSession(unittest.TestCase): 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(100)), } - cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) - cmd.run(self.iss_event_queue, self.iss_modem) + cmd = ARQRawCommand(self.ctx_ISS, params) + cmd.run() threading.Event().wait(np.random.randint(1,10)) - for id in self.irs_state_manager.arq_irs_sessions: - self.irs_state_manager.arq_irs_sessions[id].abort_transmission() + for id in self.ctx_IRS.state_manager.arq_irs_sessions: + self.ctx_IRS.state_manager.arq_irs_sessions[id].abort_transmission() self.waitAndCloseChannels() del cmd diff --git a/tests/test_message_p2p.py b/tests/test_message_p2p.py index 6a65f63c..f6d8a97c 100755 --- a/tests/test_message_p2p.py +++ b/tests/test_message_p2p.py @@ -17,7 +17,6 @@ class TestMessageP2P(unittest.TestCase): @classmethod def setUpClass(cls): - # Starte echten Context cls.ctx = AppContext('freedata_server/config.ini.example') cls.ctx.config_manager.read()