From 390817caa7301e09071e56381781ea37974ec9b7 Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Fri, 16 Feb 2024 11:02:10 +0100 Subject: [PATCH 01/12] repeat message when beacon received --- modem/frame_handler_beacon.py | 4 +++ modem/message_system_db_messages.py | 42 ++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/modem/frame_handler_beacon.py b/modem/frame_handler_beacon.py index 1b0e0148..7a88dc20 100644 --- a/modem/frame_handler_beacon.py +++ b/modem/frame_handler_beacon.py @@ -4,6 +4,7 @@ import data_frame_factory import frame_handler import datetime from message_system_db_beacon import DatabaseManagerBeacon +from message_system_db_messages import DatabaseManagerMessages from message_system_db_manager import DatabaseManager @@ -15,3 +16,6 @@ class BeaconFrameHandler(frame_handler.FrameHandler): self.details["snr"], self.details['frame']["gridsquare"] ) + + # set message to queued if beacon received + DatabaseManagerMessages(self.event_manager).set_message_to_queued_for_callsign(self.details['frame']["origin"]) diff --git a/modem/message_system_db_messages.py b/modem/message_system_db_messages.py index 6b87cf2b..255b8ab5 100644 --- a/modem/message_system_db_messages.py +++ b/modem/message_system_db_messages.py @@ -201,4 +201,44 @@ class DatabaseManagerMessages(DatabaseManager): session.rollback() self.log(f"An error occurred while marking message {message_id} as read: {e}") finally: - session.remove() \ No newline at end of file + session.remove() + + def set_message_to_queued_for_callsign(self, callsign): + session = self.get_thread_scoped_session() + try: + # Find the 'failed' status object + failed_status = session.query(Status).filter_by(name='failed').first() + # Find the 'queued' status object + queued_status = session.query(Status).filter_by(name='queued').first() + + # Ensure both statuses are found + if not failed_status or not queued_status: + self.log("Failed or queued status not found", isWarning=True) + return + + # Query for messages with the specified callsign, 'failed' status, and fewer than 10 attempts + messages = session.query(P2PMessage) \ + .filter(P2PMessage.origin_callsign == callsign) \ + .filter(P2PMessage.status_id == failed_status.id) \ + .filter(P2PMessage.attempt < 10) \ + .all() + + if messages: + # Update each message's status to 'queued' + for message in messages: + # Increment attempt count using the existing function + self.increment_message_attempts(message.id) + + message.status_id = queued_status.id + self.log(f"Set message {message.id} to queued and incremented attempt") + + session.commit() + return {'status': 'success', 'message': f'{len(messages)} message(s) set to queued'} + else: + return {'status': 'failure', 'message': 'No eligible messages found'} + except Exception as e: + session.rollback() + self.log(f"An error occurred while setting messages to queued: {e}", isWarning=True) + return {'status': 'failure', 'message': str(e)} + finally: + session.remove() From 7f86ab2ece3d9300331d047a3fd38bd8b93addc5 Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Sun, 18 Feb 2024 15:06:13 +0100 Subject: [PATCH 02/12] arq adjustments and attempt fixing tests --- modem/arq_session_irs.py | 21 ++++++++++++--------- modem/config.ini.example | 4 ++-- modem/server.py | 9 +++++---- tests/test_arq_session.py | 12 ++++++------ 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/modem/arq_session_irs.py b/modem/arq_session_irs.py index 8e0b461f..1c853568 100644 --- a/modem/arq_session_irs.py +++ b/modem/arq_session_irs.py @@ -96,9 +96,7 @@ class ARQSessionIRS(arq_session.ARQSession): self.log(f"Waiting {timeout} seconds...") if not self.event_frame_received.wait(timeout): self.log("Timeout waiting for ISS. Session failed.") - self.session_ended = time.time() - self.set_state(IRS_State.FAILED) - self.event_manager.send_arq_session_finished(False, self.id, self.dxcall, False, self.state.name, statistics=self.calculate_session_statistics()) + self.transmission_failed() def launch_transmit_and_wait(self, frame, timeout, mode): thread_wait = threading.Thread(target = self.transmit_and_wait, @@ -208,11 +206,7 @@ class ARQSessionIRS(arq_session.ARQSession): flag_checksum=False) self.transmit_frame(ack, mode=FREEDV_MODE.signalling) self.log("CRC fail at the end of transmission!") - self.session_ended = time.time() - self.set_state(IRS_State.FAILED) - self.event_manager.send_arq_session_finished( - False, self.id, self.dxcall, False, self.state.name, statistics=self.calculate_session_statistics()) - return False, False + self.transmission_failed() def calibrate_speed_settings(self): self.speed_level = 0 # for now stay at lowest speed level @@ -236,4 +230,13 @@ class ARQSessionIRS(arq_session.ARQSession): self.set_state(IRS_State.ABORTED) self.event_manager.send_arq_session_finished( False, self.id, self.dxcall, False, self.state.name, statistics=self.calculate_session_statistics()) - return None, None \ No newline at end of file + return None, None + + def transmission_failed(self, irs_frame=None): + # final function for failed transmissions + self.session_ended = time.time() + self.set_state(IRS_State.FAILED) + self.log(f"Transmission failed!") + self.event_manager.send_arq_session_finished(True, self.id, self.dxcall,False, self.state.name, statistics=self.calculate_session_statistics()) + self.states.setARQ(False) + return None, None diff --git a/modem/config.ini.example b/modem/config.ini.example index c0496ed3..59cc6ea2 100644 --- a/modem/config.ini.example +++ b/modem/config.ini.example @@ -2,9 +2,9 @@ modemport = 3050 [STATION] -mycall = XX1XXX +mycall = AA1AAA mygrid = AA12aa -myssid = 6 +myssid = 1 ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] enable_explorer = True enable_stats = True diff --git a/modem/server.py b/modem/server.py index 3fb046f4..823c8ffb 100644 --- a/modem/server.py +++ b/modem/server.py @@ -222,10 +222,11 @@ def post_modem_send_raw_stop(): if not app.state_manager.is_modem_running: api_abort('Modem not running', 503) - for id in app.state_manager.arq_irs_sessions: - app.state_manager.arq_irs_sessions[id].abort_transmission() - for id in app.state_manager.arq_iss_sessions: - app.state_manager.arq_iss_sessions[id].abort_transmission() + if app.state_manager.getARQ(): + for id in app.state_manager.arq_irs_sessions: + app.state_manager.arq_irs_sessions[id].abort_transmission() + for id in app.state_manager.arq_iss_sessions: + app.state_manager.arq_iss_sessions[id].abort_transmission() return api_response(request.json) diff --git a/tests/test_arq_session.py b/tests/test_arq_session.py index 96d7e337..961c2262 100644 --- a/tests/test_arq_session.py +++ b/tests/test_arq_session.py @@ -130,11 +130,11 @@ class TestARQSession(unittest.TestCase): def testARQSessionSmallPayload(self): # set Packet Error Rate (PER) / frame loss probability - self.loss_probability = 0 + self.loss_probability = 30 self.establishChannels() params = { - 'dxcall': "XX1XXX-1", + 'dxcall': "AA1AAA-1", 'data': base64.b64encode(bytes("Hello world!", encoding="utf-8")), 'type': "raw_lzma" } @@ -149,7 +149,7 @@ class TestARQSession(unittest.TestCase): self.establishChannels() params = { - 'dxcall': "XX1XXX-1", + 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(1000)), 'type': "raw_lzma" } @@ -165,7 +165,7 @@ class TestARQSession(unittest.TestCase): self.establishChannels() params = { - 'dxcall': "XX1XXX-1", + 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(100)), } cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) @@ -184,7 +184,7 @@ class TestARQSession(unittest.TestCase): self.establishChannels() params = { - 'dxcall': "XX1XXX-1", + 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(100)), } cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) @@ -200,7 +200,7 @@ class TestARQSession(unittest.TestCase): def testSessionCleanupISS(self): params = { - 'dxcall': "XX1XXX-1", + 'dxcall': "AA1AAA-1", 'data': base64.b64encode(np.random.bytes(100)), } cmd = ARQRawCommand(self.config, self.iss_state_manager, self.iss_event_queue, params) From 44d24123b19dbd8e891860f9fe17596cb7fc88af Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 13:57:16 -0500 Subject: [PATCH 03/12] Remove enable_fft from gui settingstore --- gui/src/store/settingsStore.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gui/src/store/settingsStore.js b/gui/src/store/settingsStore.js index 8baa9b2d..48200fbe 100644 --- a/gui/src/store/settingsStore.js +++ b/gui/src/store/settingsStore.js @@ -54,7 +54,6 @@ const defaultConfig = { enable_protocol: false, }, MODEM: { - enable_fft: false, enable_fsk: false, enable_low_bandwidth_mode: false, respond_to_cq: false, From 273914d714bd1bd1a55d8c8c403f5336b47d966b Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 13:57:53 -0500 Subject: [PATCH 04/12] Extra serial port in config.py --- modem/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modem/config.py b/modem/config.py index b9e20636..18388b24 100644 --- a/modem/config.py +++ b/modem/config.py @@ -31,7 +31,6 @@ class CONFIG: 'control': str, 'serial_port': str, 'model_id': int, - 'serial_port': str, 'serial_speed': int, 'data_bits': int, 'stop_bits': int, From e90d1f771625a061711f0ba573c89b3d8288f606 Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Sun, 18 Feb 2024 20:31:01 +0100 Subject: [PATCH 05/12] adjusted config --- modem/config.ini.example | 2 +- modem/config.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/modem/config.ini.example b/modem/config.ini.example index 59cc6ea2..4729ff19 100644 --- a/modem/config.ini.example +++ b/modem/config.ini.example @@ -1,5 +1,5 @@ [NETWORK] -modemport = 3050 +modemport = 5000 [STATION] mycall = AA1AAA diff --git a/modem/config.py b/modem/config.py index b9e20636..f3070d12 100644 --- a/modem/config.py +++ b/modem/config.py @@ -147,9 +147,7 @@ class CONFIG: self.parser.set(section, setting, str(default_value)) self.log.info(f"[CFG] Adding missing setting: {section}.{setting}") - self.write_to_file() - - + return self.write_to_file() # Handle special setting data type conversion # is_writing means data from a dict being writen to the config file @@ -177,7 +175,6 @@ class CONFIG: def write(self, data): # Validate config data before writing self.validate_data(data) - for section in data: # init section if it doesn't exist yet if not section.upper() in self.parser.keys(): @@ -186,9 +183,11 @@ class CONFIG: for setting in data[section]: new_value = self.handle_setting( section, setting, data[section][setting], True) - self.parser[section][setting] = str(new_value) - - self.write_to_file() + try: + self.parser[section][setting] = str(new_value) + except Exception as e: + self.log.error("[CFG] error setting config key", e=e) + return self.write_to_file() def write_to_file(self): # Write config data to file From 7a09f947679c8e60fa4fb415afd26fe5b74d2ebb Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Sun, 18 Feb 2024 21:08:14 +0100 Subject: [PATCH 06/12] added config related parts --- gui/src/components/settings_chat.vue | 19 +++++++++++++++++-- gui/src/store/settingsStore.js | 3 +++ modem/config.py | 4 ++++ modem/frame_handler_beacon.py | 5 +++-- modem/frame_handler_cq.py | 7 +++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/gui/src/components/settings_chat.vue b/gui/src/components/settings_chat.vue index 02a5d726..596132d6 100644 --- a/gui/src/components/settings_chat.vue +++ b/gui/src/components/settings_chat.vue @@ -5,9 +5,24 @@ import { setActivePinia } from "pinia"; import pinia from "../store/index"; setActivePinia(pinia); -import { settingsStore as settings } from "../store/settingsStore.js"; +import { settingsStore as settings, onChange } from "../store/settingsStore.js"; diff --git a/gui/src/store/settingsStore.js b/gui/src/store/settingsStore.js index 8baa9b2d..25a0aa3e 100644 --- a/gui/src/store/settingsStore.js +++ b/gui/src/store/settingsStore.js @@ -98,6 +98,9 @@ const defaultConfig = { tci_ip: "127.0.0.1", tci_port: 0, }, + MESSAGES: { + enable_auto_repeat: false, + }, }, }; diff --git a/modem/config.py b/modem/config.py index b9e20636..cb97eb5f 100644 --- a/modem/config.py +++ b/modem/config.py @@ -67,6 +67,9 @@ class CONFIG: 'tx_delay': int, 'beacon_interval': int, }, + 'MESSAGES': { + 'enable_auto_repeat': bool, + } } default_values = { @@ -175,6 +178,7 @@ class CONFIG: # Sets and writes config data from a dict containing data settings def write(self, data): + print(data) # Validate config data before writing self.validate_data(data) diff --git a/modem/frame_handler_beacon.py b/modem/frame_handler_beacon.py index 7a88dc20..10b79822 100644 --- a/modem/frame_handler_beacon.py +++ b/modem/frame_handler_beacon.py @@ -17,5 +17,6 @@ class BeaconFrameHandler(frame_handler.FrameHandler): self.details['frame']["gridsquare"] ) - # set message to queued if beacon received - DatabaseManagerMessages(self.event_manager).set_message_to_queued_for_callsign(self.details['frame']["origin"]) + if self.config["MESSAGES"]["enable_auto_repeat"]: + # set message to queued if beacon received + DatabaseManagerMessages(self.event_manager).set_message_to_queued_for_callsign(self.details['frame']["origin"]) diff --git a/modem/frame_handler_cq.py b/modem/frame_handler_cq.py index 67fd4e44..1fe59d90 100644 --- a/modem/frame_handler_cq.py +++ b/modem/frame_handler_cq.py @@ -2,6 +2,9 @@ import frame_handler_ping import helpers import data_frame_factory import frame_handler +from message_system_db_messages import DatabaseManagerMessages + + class CQFrameHandler(frame_handler_ping.PingFrameHandler): def should_respond(self): @@ -14,3 +17,7 @@ class CQFrameHandler(frame_handler_ping.PingFrameHandler): self.details['snr'] ) self.transmit(qrv_frame) + + if self.config["MESSAGES"]["enable_auto_repeat"]: + # set message to queued if beacon received + DatabaseManagerMessages(self.event_manager).set_message_to_queued_for_callsign(self.details['frame']["origin"]) From dbc959d06e545ec27bf245700a1d4f113996e505 Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Sun, 18 Feb 2024 21:15:33 +0100 Subject: [PATCH 07/12] added config related parts --- modem/config.py | 1 - modem/server.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/modem/config.py b/modem/config.py index cb97eb5f..eeff2375 100644 --- a/modem/config.py +++ b/modem/config.py @@ -178,7 +178,6 @@ class CONFIG: # Sets and writes config data from a dict containing data settings def write(self, data): - print(data) # Validate config data before writing self.validate_data(data) diff --git a/modem/server.py b/modem/server.py index 8a248150..16895b03 100644 --- a/modem/server.py +++ b/modem/server.py @@ -93,6 +93,7 @@ def index(): @app.route('/config', methods=['GET', 'POST']) def config(): if request.method in ['POST']: + print(request.json) set_config = app.config_manager.write(request.json) app.modem_service.put("restart") if not set_config: From f8bff53eae7fad5691e0198e8c5676281c3cd53b Mon Sep 17 00:00:00 2001 From: DJ2LS Date: Sun, 18 Feb 2024 21:31:08 +0100 Subject: [PATCH 08/12] updated example config and typo --- modem/config.ini.example | 3 +++ modem/frame_handler_cq.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modem/config.ini.example b/modem/config.ini.example index 4729ff19..b82b5ab5 100644 --- a/modem/config.ini.example +++ b/modem/config.ini.example @@ -55,3 +55,6 @@ rx_buffer_size = 64 tx_delay = 200 beacon_interval = 300 +[MESSAGES] +enable_auto_repeat = False + diff --git a/modem/frame_handler_cq.py b/modem/frame_handler_cq.py index 1fe59d90..a23d2c69 100644 --- a/modem/frame_handler_cq.py +++ b/modem/frame_handler_cq.py @@ -19,5 +19,5 @@ class CQFrameHandler(frame_handler_ping.PingFrameHandler): self.transmit(qrv_frame) if self.config["MESSAGES"]["enable_auto_repeat"]: - # set message to queued if beacon received + # set message to queued if CQ received DatabaseManagerMessages(self.event_manager).set_message_to_queued_for_callsign(self.details['frame']["origin"]) From 70228054fd0cd69a91410efc2490bee02db24893 Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 15:33:29 -0500 Subject: [PATCH 09/12] Remove unused setting --- gui/src/store/settingsStore.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gui/src/store/settingsStore.js b/gui/src/store/settingsStore.js index 8baa9b2d..48200fbe 100644 --- a/gui/src/store/settingsStore.js +++ b/gui/src/store/settingsStore.js @@ -54,7 +54,6 @@ const defaultConfig = { enable_protocol: false, }, MODEM: { - enable_fft: false, enable_fsk: false, enable_low_bandwidth_mode: false, respond_to_cq: false, From 47242fb33eb0513931174a779ba406e54fadea0f Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 15:33:42 -0500 Subject: [PATCH 10/12] Remove duplicate setting --- modem/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modem/config.py b/modem/config.py index f3070d12..cd6dcb18 100644 --- a/modem/config.py +++ b/modem/config.py @@ -31,7 +31,6 @@ class CONFIG: 'control': str, 'serial_port': str, 'model_id': int, - 'serial_port': str, 'serial_speed': int, 'data_bits': int, 'stop_bits': int, From 796d1c0566ab37100ebb303029cfee418811bf45 Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 15:34:10 -0500 Subject: [PATCH 11/12] Only restart modem if config is valid --- modem/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modem/server.py b/modem/server.py index 8a248150..50fe5f49 100644 --- a/modem/server.py +++ b/modem/server.py @@ -94,10 +94,10 @@ def index(): def config(): if request.method in ['POST']: set_config = app.config_manager.write(request.json) - app.modem_service.put("restart") if not set_config: response = api_response(None, 'error writing config') else: + app.modem_service.put("restart") response = api_response(set_config) return response elif request.method == 'GET': From 6db6c486a3ebd6bea7eb870e57912b645206257d Mon Sep 17 00:00:00 2001 From: Mashintime Date: Sun, 18 Feb 2024 15:46:40 -0500 Subject: [PATCH 12/12] Remove print (accidentally committed) --- modem/server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modem/server.py b/modem/server.py index ce0c15d2..50fe5f49 100644 --- a/modem/server.py +++ b/modem/server.py @@ -93,7 +93,6 @@ def index(): @app.route('/config', methods=['GET', 'POST']) def config(): if request.method in ['POST']: - print(request.json) set_config = app.config_manager.write(request.json) if not set_config: response = api_response(None, 'error writing config')