mirror of https://github.com/DJ2LS/FreeDATA.git
adjustments to modem tests - still not working yet. but we have first benefits of new modem structure
parent
feaaa699e8
commit
e5208cffff
|
@ -30,6 +30,8 @@ class AppContext:
|
||||||
self.message_system_db_manager = DatabaseManager(self)
|
self.message_system_db_manager = DatabaseManager(self)
|
||||||
self.message_system_db_attachments = DatabaseManagerAttachments(self)
|
self.message_system_db_attachments = DatabaseManagerAttachments(self)
|
||||||
|
|
||||||
|
self.TESTMODE = False
|
||||||
|
|
||||||
def startup(self):
|
def startup(self):
|
||||||
|
|
||||||
# initially read config
|
# initially read config
|
||||||
|
|
|
@ -120,7 +120,10 @@ class Demodulator():
|
||||||
self.MODE_DICT[mode]["nin"] = nin
|
self.MODE_DICT[mode]["nin"] = nin
|
||||||
|
|
||||||
def start(self, stream):
|
def start(self, stream):
|
||||||
self.stream = stream
|
if self.ctx.TESTMODE:
|
||||||
|
self.stream = None
|
||||||
|
else:
|
||||||
|
self.stream = stream
|
||||||
|
|
||||||
for mode in self.MODE_DICT:
|
for mode in self.MODE_DICT:
|
||||||
# Start decoder threads
|
# Start decoder threads
|
||||||
|
@ -160,7 +163,7 @@ class Demodulator():
|
||||||
last_rx_status = 0
|
last_rx_status = 0
|
||||||
|
|
||||||
try:
|
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)
|
threading.Event().wait(0.01)
|
||||||
if audiobuffer.nbuffer >= nin and not self.shutdown_flag.is_set():
|
if audiobuffer.nbuffer >= nin and not self.shutdown_flag.is_set():
|
||||||
# demodulate audio
|
# demodulate audio
|
||||||
|
|
|
@ -20,7 +20,6 @@ import audio
|
||||||
import demodulator
|
import demodulator
|
||||||
import modulator
|
import modulator
|
||||||
|
|
||||||
TESTMODE = False
|
|
||||||
|
|
||||||
class RF:
|
class RF:
|
||||||
"""Handles FreeDATA modem functionality.
|
"""Handles FreeDATA modem functionality.
|
||||||
|
@ -44,7 +43,7 @@ class RF:
|
||||||
states (StateManager): State manager instance.
|
states (StateManager): State manager instance.
|
||||||
radio_manager (RadioManager): Radio manager instance.
|
radio_manager (RadioManager): Radio manager instance.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
self.sampler_avg = 0
|
self.sampler_avg = 0
|
||||||
self.buffer_avg = 0
|
self.buffer_avg = 0
|
||||||
|
@ -99,7 +98,10 @@ class RF:
|
||||||
Raises:
|
Raises:
|
||||||
RuntimeError: If audio device initialization fails.
|
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
|
return True
|
||||||
else:
|
else:
|
||||||
if not self.init_audio():
|
if not self.init_audio():
|
||||||
|
@ -324,7 +326,11 @@ class RF:
|
||||||
self.ctx.event_manager.send_ptt_change(True)
|
self.ctx.event_manager.send_ptt_change(True)
|
||||||
|
|
||||||
# slice audio data to needed blocklength
|
# 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
|
pad_length = -len(audio_48k) % block_size
|
||||||
padded_data = np.pad(audio_48k, (0, pad_length), mode='constant')
|
padded_data = np.pad(audio_48k, (0, pad_length), mode='constant')
|
||||||
sliced_audio_data = padded_data.reshape(-1, block_size)
|
sliced_audio_data = padded_data.reshape(-1, block_size)
|
||||||
|
|
|
@ -129,13 +129,14 @@ class SM:
|
||||||
self.log.warning("freedata_server already running")
|
self.log.warning("freedata_server already running")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# test audio devices
|
if not self.ctx.TESTMODE:
|
||||||
audio_test = self.test_audio()
|
# test audio devices
|
||||||
if False in audio_test or None in audio_test or self.ctx.state_manager.is_modem_running:
|
audio_test = self.test_audio()
|
||||||
self.log.warning("starting freedata_server failed", input_test=audio_test[0], output_test=audio_test[1])
|
if False in audio_test or None in audio_test or self.ctx.state_manager.is_modem_running:
|
||||||
self.ctx.state_manager.set("is_modem_running", False)
|
self.log.warning("starting freedata_server failed", input_test=audio_test[0], output_test=audio_test[1])
|
||||||
self.ctx.event_manager.modem_failed()
|
self.ctx.state_manager.set("is_modem_running", False)
|
||||||
return False
|
self.ctx.event_manager.modem_failed()
|
||||||
|
return False
|
||||||
|
|
||||||
self.log.info("starting freedata_server....")
|
self.log.info("starting freedata_server....")
|
||||||
self.ctx.rf_modem = modem.RF(self.ctx)
|
self.ctx.rf_modem = modem.RF(self.ctx)
|
||||||
|
|
|
@ -4,7 +4,9 @@ sys.path.append('freedata_server')
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
from config import CONFIG
|
import config
|
||||||
|
from context import AppContext
|
||||||
|
|
||||||
import helpers
|
import helpers
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
|
@ -20,6 +22,8 @@ from state_manager import StateManager
|
||||||
from data_frame_factory import DataFrameFactory
|
from data_frame_factory import DataFrameFactory
|
||||||
import codec2
|
import codec2
|
||||||
import arq_session_irs
|
import arq_session_irs
|
||||||
|
import os
|
||||||
|
|
||||||
class TestModem:
|
class TestModem:
|
||||||
def __init__(self, event_q, state_q):
|
def __init__(self, event_q, state_q):
|
||||||
self.data_queue_received = queue.Queue()
|
self.data_queue_received = queue.Queue()
|
||||||
|
@ -54,47 +58,45 @@ class TestModem:
|
||||||
}
|
}
|
||||||
self.data_queue_received.put(transmission)
|
self.data_queue_received.put(transmission)
|
||||||
|
|
||||||
|
class DummyCtx:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestARQSession(unittest.TestCase):
|
class TestARQSession(unittest.TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
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.logger = structlog.get_logger("TESTS")
|
||||||
cls.frame_factory = DataFrameFactory(cls.config)
|
|
||||||
|
|
||||||
# ISS
|
# 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.ctx_ISS = AppContext('freedata_server/config.ini.example')
|
||||||
cls.iss_event_queue = queue.Queue()
|
cls.ctx_ISS.TESTMODE = True
|
||||||
cls.iss_state_queue = queue.Queue()
|
cls.ctx_ISS.startup()
|
||||||
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)
|
|
||||||
|
|
||||||
# IRS
|
# IRS
|
||||||
cls.irs_state_manager = StateManager(queue.Queue())
|
cls.ctx_IRS = AppContext('freedata_server/config.ini.example')
|
||||||
cls.iss_state_manager.set_channel_busy_condition_codec2(False)
|
cls.ctx_IRS.TESTMODE = True
|
||||||
|
cls.ctx_IRS.startup()
|
||||||
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)
|
|
||||||
|
|
||||||
# simulate a busy condition
|
# 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 %
|
# Frame loss probability in %
|
||||||
cls.loss_probability = 0
|
cls.loss_probability = 0
|
||||||
|
|
||||||
cls.channels_running = True
|
|
||||||
|
|
||||||
|
|
||||||
|
cls.channels_running = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def channelWorker(self, modem_transmit_queue: queue.Queue, frame_dispatcher: DISPATCHER):
|
def channelWorker(self, modem_transmit_queue: queue.Queue, frame_dispatcher: DISPATCHER):
|
||||||
while self.channels_running:
|
while self.channels_running:
|
||||||
|
@ -126,23 +128,22 @@ class TestARQSession(unittest.TestCase):
|
||||||
break
|
break
|
||||||
|
|
||||||
def establishChannels(self):
|
def establishChannels(self):
|
||||||
self.channels_running = True
|
self.iss_to_irs_channel = threading.Thread(target=self.channelWorker,
|
||||||
self.iss_to_irs_channel = threading.Thread(target=self.channelWorker,
|
args=[self.ctx_ISS.rf_modem.data_queue_received,
|
||||||
args=[self.iss_modem.data_queue_received,
|
self.ctx_IRS.service_manager.frame_dispatcher],
|
||||||
self.irs_frame_dispatcher],
|
|
||||||
name = "ISS to IRS channel")
|
name = "ISS to IRS channel")
|
||||||
self.iss_to_irs_channel.start()
|
self.iss_to_irs_channel.start()
|
||||||
|
|
||||||
self.irs_to_iss_channel = threading.Thread(target=self.channelWorker,
|
self.irs_to_iss_channel = threading.Thread(target=self.channelWorker,
|
||||||
args=[self.irs_modem.data_queue_received,
|
args=[self.ctx_IRS.rf_modem.data_queue_received,
|
||||||
self.iss_frame_dispatcher],
|
self.ctx_ISS.service_manager.frame_dispatcher],
|
||||||
name = "IRS to ISS channel")
|
name = "IRS to ISS channel")
|
||||||
self.irs_to_iss_channel.start()
|
self.irs_to_iss_channel.start()
|
||||||
|
self.channels_running = True
|
||||||
def waitAndCloseChannels(self):
|
def waitAndCloseChannels(self):
|
||||||
self.waitForSession(self.iss_event_queue, True)
|
self.waitForSession(self.ctx_ISS.modem_events, True)
|
||||||
self.channels_running = False
|
self.channels_running = False
|
||||||
self.waitForSession(self.irs_event_queue, False)
|
self.waitForSession(self.ctx_IRS.modem_events, False)
|
||||||
self.channels_running = False
|
self.channels_running = False
|
||||||
|
|
||||||
def DisabledtestARQSessionSmallPayload(self):
|
def DisabledtestARQSessionSmallPayload(self):
|
||||||
|
@ -155,8 +156,8 @@ class TestARQSession(unittest.TestCase):
|
||||||
'data': base64.b64encode(bytes("Hello world!", encoding="utf-8")),
|
'data': base64.b64encode(bytes("Hello world!", encoding="utf-8")),
|
||||||
'type': "raw_lzma"
|
'type': "raw_lzma"
|
||||||
}
|
}
|
||||||
cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params)
|
cmd = ARQRawCommand(self.ctx_ISS, params)
|
||||||
cmd.run(self.iss_event_queue, self.iss_modem)
|
cmd.run()
|
||||||
self.waitAndCloseChannels()
|
self.waitAndCloseChannels()
|
||||||
del cmd
|
del cmd
|
||||||
|
|
||||||
|
@ -170,8 +171,8 @@ class TestARQSession(unittest.TestCase):
|
||||||
'data': base64.b64encode(np.random.bytes(1000)),
|
'data': base64.b64encode(np.random.bytes(1000)),
|
||||||
'type': "raw_lzma"
|
'type': "raw_lzma"
|
||||||
}
|
}
|
||||||
cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params)
|
cmd = ARQRawCommand(self.ctx_ISS, params)
|
||||||
cmd.run(self.iss_event_queue, self.iss_modem)
|
cmd.run()
|
||||||
|
|
||||||
self.waitAndCloseChannels()
|
self.waitAndCloseChannels()
|
||||||
del cmd
|
del cmd
|
||||||
|
@ -185,12 +186,12 @@ class TestARQSession(unittest.TestCase):
|
||||||
'dxcall': "AA1AAA-1",
|
'dxcall': "AA1AAA-1",
|
||||||
'data': base64.b64encode(np.random.bytes(100)),
|
'data': base64.b64encode(np.random.bytes(100)),
|
||||||
}
|
}
|
||||||
cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params)
|
cmd = ARQRawCommand(self.ctx_ISS, params)
|
||||||
cmd.run(self.iss_event_queue, self.iss_modem)
|
cmd.run()
|
||||||
|
|
||||||
threading.Event().wait(np.random.randint(10,10))
|
threading.Event().wait(np.random.randint(10,10))
|
||||||
for id in self.iss_state_manager.arq_iss_sessions:
|
for id in self.ctx_ISS.state_manager.arq_iss_sessions:
|
||||||
self.iss_state_manager.arq_iss_sessions[id].abort_transmission()
|
self.ctx_ISS.state_manager.arq_iss_sessions[id].abort_transmission()
|
||||||
|
|
||||||
self.waitAndCloseChannels()
|
self.waitAndCloseChannels()
|
||||||
del cmd
|
del cmd
|
||||||
|
@ -204,12 +205,12 @@ class TestARQSession(unittest.TestCase):
|
||||||
'dxcall': "AA1AAA-1",
|
'dxcall': "AA1AAA-1",
|
||||||
'data': base64.b64encode(np.random.bytes(100)),
|
'data': base64.b64encode(np.random.bytes(100)),
|
||||||
}
|
}
|
||||||
cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params)
|
cmd = ARQRawCommand(self.ctx_ISS, params)
|
||||||
cmd.run(self.iss_event_queue, self.iss_modem)
|
cmd.run()
|
||||||
|
|
||||||
threading.Event().wait(np.random.randint(1,10))
|
threading.Event().wait(np.random.randint(1,10))
|
||||||
for id in self.irs_state_manager.arq_irs_sessions:
|
for id in self.ctx_IRS.state_manager.arq_irs_sessions:
|
||||||
self.irs_state_manager.arq_irs_sessions[id].abort_transmission()
|
self.ctx_IRS.state_manager.arq_irs_sessions[id].abort_transmission()
|
||||||
|
|
||||||
self.waitAndCloseChannels()
|
self.waitAndCloseChannels()
|
||||||
del cmd
|
del cmd
|
||||||
|
|
|
@ -17,7 +17,6 @@ class TestMessageP2P(unittest.TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
# Starte echten Context
|
|
||||||
cls.ctx = AppContext('freedata_server/config.ini.example')
|
cls.ctx = AppContext('freedata_server/config.ini.example')
|
||||||
cls.ctx.config_manager.read()
|
cls.ctx.config_manager.read()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue