From f88f5fe2a37d7116821c395220cc5e27306999e7 Mon Sep 17 00:00:00 2001 From: as3ii Date: Thu, 8 Jan 2026 19:59:14 +0100 Subject: [PATCH 1/6] Increased max line length to 120, reformatted everything In practice, in this commit I've increased from 100 to 120 the maximum allowed line length for python files and re-run ruff's formatter. --- freedata_server/adif_udp_logger.py | 4 +- freedata_server/api/devices.py | 6 +- freedata_server/api/freedata.py | 58 +++------- freedata_server/api/modem.py | 4 +- freedata_server/api/websocket.py | 24 ++-- freedata_server/arq_data_type_handler.py | 46 ++------ freedata_server/arq_session.py | 9 +- freedata_server/arq_session_irs.py | 41 ++----- freedata_server/arq_session_iss.py | 20 +--- freedata_server/audio.py | 14 +-- freedata_server/b64.py | 4 +- freedata_server/codec2.py | 36 ++---- freedata_server/command_fec.py | 4 +- freedata_server/command_message_send.py | 12 +- freedata_server/command_norm.py | 29 ++--- freedata_server/config.py | 8 +- freedata_server/constants.py | 12 +- freedata_server/data_frame_factory.py | 104 +++++++++-------- freedata_server/demodulator.py | 19 +--- freedata_server/explorer.py | 6 +- freedata_server/frame_dispatcher.py | 23 ++-- freedata_server/frame_handler.py | 71 ++++-------- freedata_server/frame_handler_arq_session.py | 4 +- freedata_server/frame_handler_norm.py | 30 ++--- freedata_server/frame_handler_ping.py | 4 +- freedata_server/helpers.py | 8 +- freedata_server/maidenhead.py | 4 +- freedata_server/message_p2p.py | 12 +- .../message_system_db_attachments.py | 18 +-- freedata_server/message_system_db_beacon.py | 12 +- .../message_system_db_broadcasts.py | 105 +++++++----------- freedata_server/message_system_db_manager.py | 15 +-- freedata_server/message_system_db_messages.py | 26 ++--- freedata_server/message_system_db_model.py | 67 +++++------ freedata_server/message_system_db_station.py | 8 +- freedata_server/modem.py | 32 ++---- freedata_server/modem_frametypes.py | 6 +- freedata_server/norm/norm_transmission.py | 39 ++++--- freedata_server/norm/norm_transmission_irs.py | 13 +-- freedata_server/norm/norm_transmission_iss.py | 35 +++--- .../norm/norm_transmission_resend.py | 2 +- freedata_server/p2p_connection.py | 78 ++++--------- freedata_server/radio_manager.py | 4 +- freedata_server/rigctld.py | 29 ++--- freedata_server/schedule_manager.py | 63 +++++------ freedata_server/service_manager.py | 16 +-- freedata_server/socket_interface.py | 12 +- freedata_server/state_manager.py | 5 +- freedata_server/wavelog_api_logger.py | 8 +- freedata_server/websocket_manager.py | 11 +- pyproject.toml | 2 +- tests/test_arq_session.py | 12 +- tests/test_data_frame_factory.py | 12 +- tests/test_data_type_handler.py | 24 +--- tests/test_message_database.py | 8 +- tests/test_message_p2p.py | 4 +- tests/test_message_protocol.py | 12 +- tests/test_norm_protocol.py | 53 ++++----- tests/test_p2p_connection.py | 4 +- tests/test_protocols.py | 4 +- tools/custom_mode_tests/run_mode_tests.py | 16 +-- 61 files changed, 492 insertions(+), 879 deletions(-) diff --git a/freedata_server/adif_udp_logger.py b/freedata_server/adif_udp_logger.py index fb8a3b841..5382aeca1 100644 --- a/freedata_server/adif_udp_logger.py +++ b/freedata_server/adif_udp_logger.py @@ -37,9 +37,7 @@ def send_thread(): ctx.event_manager.freedata_logging(type="udp", status=True, message=f" {call_value} ") except socket.timeout: - log.info( - f"[CHAT] Timeout occurred sending ADIF data to {adif_log_host}:{adif_log_port}" - ) + log.info(f"[CHAT] Timeout occurred sending ADIF data to {adif_log_host}:{adif_log_port}") ctx.event_manager.freedata_logging(type="udp", status=True, message=f" {call_value} ") except Exception as e: log.info(f"[CHAT] Error sending ADIF data: {e}") diff --git a/freedata_server/api/devices.py b/freedata_server/api/devices.py index be7808f21..8c77c78ad 100644 --- a/freedata_server/api/devices.py +++ b/freedata_server/api/devices.py @@ -79,11 +79,7 @@ async def get_audio_devices(ctx: AppContext = Depends(get_ctx)): responses={ 200: { "description": "List of available serial devices (COM ports).", - "content": { - "application/json": { - "example": [{"description": "n/a [26a9]", "port": "/dev/ttyS4"}] - } - }, + "content": {"application/json": {"example": [{"description": "n/a [26a9]", "port": "/dev/ttyS4"}]}}, }, 404: { "description": "The requested resource was not found.", diff --git a/freedata_server/api/freedata.py b/freedata_server/api/freedata.py index a6a27f63f..6d56c6725 100644 --- a/freedata_server/api/freedata.py +++ b/freedata_server/api/freedata.py @@ -39,6 +39,7 @@ def _mgr_beacon(ctx: AppContext): def _mgr_stations(ctx: AppContext): return DatabaseManagerStations(ctx) + def _mgr_broadcasts(ctx: AppContext): return DatabaseManagerBroadcasts(ctx) @@ -66,11 +67,7 @@ async def get_freedata_message(message_id: str, ctx: AppContext = Depends(get_ct responses={ 200: { "description": "Message transmitted successfully.", - "content": { - "application/json": { - "example": {"destination": "XX1XXX-6", "body": "Hello FreeDATA"} - } - }, + "content": {"application/json": {"example": {"destination": "XX1XXX-6", "body": "Hello FreeDATA"}}}, }, 404: { "description": "The requested resource was not found.", @@ -136,9 +133,7 @@ async def post_freedata_message_adif_log(message_id: str, ctx: AppContext = Depe }, }, ) -async def patch_freedata_message( - message_id: str, payload: dict, ctx: AppContext = Depends(get_ctx) -): +async def patch_freedata_message(message_id: str, payload: dict, ctx: AppContext = Depends(get_ctx)): if payload.get("action") == "retransmit": _mgr_msgs(ctx).update_message(message_id, {"status": "queued"}) _mgr_msgs(ctx).increment_message_attempts(message_id) @@ -224,11 +219,7 @@ async def get_freedata_messages(ctx: AppContext = Depends(get_ctx)): }, 404: { "description": "Message not found.", - "content": { - "application/json": { - "example": {"message": "Message not found", "status": "failure"} - } - }, + "content": {"application/json": {"example": {"message": "Message not found", "status": "failure"}}}, }, }, ) @@ -543,29 +534,23 @@ async def set_station_info(callsign: str, payload: dict, ctx: AppContext = Depen @router.get("/broadcasts", summary="Get All Broadcast Messages", tags=["FreeDATA"], responses={}) -async def get_freedata_broadcasts( - ctx: AppContext = Depends(get_ctx) -): - #filters = {k: v for k, v in ctx.config_manager.read().get('FILTERS', {}).items()} +async def get_freedata_broadcasts(ctx: AppContext = Depends(get_ctx)): + # filters = {k: v for k, v in ctx.config_manager.read().get('FILTERS', {}).items()} # use query params if needed # filters = dict(ctx.request.query_params) result = _mgr_broadcasts(ctx).get_all_broadcasts_json() return api_response(result) + @router.get("/broadcasts/{domain}/", summary="Get Broadcats per Domain", tags=["FreeDATA"], responses={}) -async def get_freedata_broadcasts_per_domain( - domain: str, - ctx: AppContext = Depends(get_ctx) -): +async def get_freedata_broadcasts_per_domain(domain: str, ctx: AppContext = Depends(get_ctx)): result = _mgr_broadcasts(ctx).get_broadcasts_per_domain_json(domain) return api_response(result) @router.get("/broadcasts/domains", summary="Get All Broadcast Messages", tags=["FreeDATA"], responses={}) -async def get_freedata_broadcasts( - ctx: AppContext = Depends(get_ctx) -): - #filters = {k: v for k, v in ctx.config_manager.read().get('FILTERS', {}).items()} +async def get_freedata_broadcasts(ctx: AppContext = Depends(get_ctx)): + # filters = {k: v for k, v in ctx.config_manager.read().get('FILTERS', {}).items()} # use query params if needed # filters = dict(ctx.request.query_params) result = _mgr_broadcasts(ctx).get_broadcast_domains_json() @@ -573,33 +558,21 @@ async def get_freedata_broadcasts( @router.delete("/broadcasts/{id}", summary="Delete Message or Broadcast by ID", tags=["FreeDATA"], responses={}) -async def delete_freedata_broadcast_domain( - id: str, - ctx: AppContext = Depends(get_ctx) -): +async def delete_freedata_broadcast_domain(id: str, ctx: AppContext = Depends(get_ctx)): ok = _mgr_broadcasts(ctx).delete_broadcast_message_or_domain(id) if not ok: api_abort("Message not found", 404) return api_response({"message": f"{id} deleted", "status": "success"}) - @router.patch("/broadcasts/{id}", summary="Retransmit Broadcast by ID", tags=["FreeDATA"], responses={}) -async def patch_freedata_broadcast_domain( - id: str, - payload: dict, - ctx: AppContext = Depends(get_ctx) -): +async def patch_freedata_broadcast_domain(id: str, payload: dict, ctx: AppContext = Depends(get_ctx)): if payload.get("action") == "retransmit": _mgr_broadcasts(ctx).increment_attempts(id) msg = _mgr_broadcasts(ctx).get_broadcast_per_id(id, get_object=True) if msg: loop = asyncio.get_running_loop() - loop.run_in_executor( - None, - NormTransmissionISS(ctx).retransmit_data, - msg - ) + loop.run_in_executor(None, NormTransmissionISS(ctx).retransmit_data, msg) return api_response({"message_id": id, "status": "retransmit started"}) else: api_abort("Message not found", 404) @@ -608,9 +581,6 @@ async def patch_freedata_broadcast_domain( @router.post("/broadcasts", summary="Transmit Broadcast", tags=["FreeDATA"], responses={}) -async def post_freedata_broadcast( - payload: dict, - ctx: AppContext = Depends(get_ctx) -): +async def post_freedata_broadcast(payload: dict, ctx: AppContext = Depends(get_ctx)): await enqueue_tx_command(ctx, command_norm.Norm, payload) return api_response({"message": f"broadcast transmitted", "status": "success"}) diff --git a/freedata_server/api/modem.py b/freedata_server/api/modem.py index 9eb4a37e4..6df878afa 100644 --- a/freedata_server/api/modem.py +++ b/freedata_server/api/modem.py @@ -179,9 +179,7 @@ async def post_cq(ctx: AppContext = Depends(get_ctx)): "description": "Invalid input parameters.", "content": { "application/json": { - "example": { - "error": "Incorrect value for 'enabled' or 'away_from_key'. Should be bool." - } + "example": {"error": "Incorrect value for 'enabled' or 'away_from_key'. Should be bool."} } }, }, diff --git a/freedata_server/api/websocket.py b/freedata_server/api/websocket.py index 36b4d3cfc..30bfc81c9 100644 --- a/freedata_server/api/websocket.py +++ b/freedata_server/api/websocket.py @@ -10,9 +10,7 @@ async def websocket_events(websocket: WebSocket, ctx: AppContext = Depends(get_c WebSocket endpoint for event streams. """ await websocket.accept() - await ctx.websocket_manager.handle_connection( - websocket, ctx.websocket_manager.events_client_list, ctx.modem_events - ) + await ctx.websocket_manager.handle_connection(websocket, ctx.websocket_manager.events_client_list, ctx.modem_events) @router.websocket("/fft") @@ -21,9 +19,7 @@ async def websocket_fft(websocket: WebSocket, ctx: AppContext = Depends(get_ctx) WebSocket endpoint for FFT data streams. """ await websocket.accept() - await ctx.websocket_manager.handle_connection( - websocket, ctx.websocket_manager.fft_client_list, ctx.modem_fft - ) + await ctx.websocket_manager.handle_connection(websocket, ctx.websocket_manager.fft_client_list, ctx.modem_fft) @router.websocket("/states") @@ -32,23 +28,17 @@ async def websocket_states(websocket: WebSocket, ctx: AppContext = Depends(get_c WebSocket endpoint for state updates. """ await websocket.accept() - await ctx.websocket_manager.handle_connection( - websocket, ctx.websocket_manager.states_client_list, ctx.state_queue - ) + await ctx.websocket_manager.handle_connection(websocket, ctx.websocket_manager.states_client_list, ctx.state_queue) + @router.websocket("/audio_rx") -async def websocket_audio_rx( - websocket: WebSocket, - ctx: AppContext = Depends(get_ctx) -): +async def websocket_audio_rx(websocket: WebSocket, ctx: AppContext = Depends(get_ctx)): """ WebSocket endpoint for state updates. """ await websocket.accept() await ctx.websocket_manager.handle_connection( - websocket, - ctx.websocket_manager.audio_rx_client_list, - ctx.state_queue + websocket, ctx.websocket_manager.audio_rx_client_list, ctx.state_queue ) - #while True: + # while True: # await websocket.send_bytes(b"\x00" * 1024) diff --git a/freedata_server/arq_data_type_handler.py b/freedata_server/arq_data_type_handler.py index 9ae47fbdb..aad8bee35 100644 --- a/freedata_server/arq_data_type_handler.py +++ b/freedata_server/arq_data_type_handler.py @@ -106,11 +106,7 @@ def dispatch(self, type_byte: int, data: bytearray, statistics: dict): self.ctx.state_manager.setARQ(False) - if ( - session_type - and session_type in self.handlers - and "handle" in self.handlers[session_type] - ): + if session_type and session_type in self.handlers and "handle" in self.handlers[session_type]: return self.handlers[session_type]["handle"](data, statistics) else: self.log(f"Unknown handling endpoint for type: {type_byte}", isWarning=True) @@ -271,9 +267,7 @@ def prepare_raw_lzma(self, data): The LZMA-compressed data as a bytearray. """ compressed_data = lzma.compress(data) - self.log( - f"Preparing LZMA compressed data: {len(data)} Bytes >>> {len(compressed_data)} Bytes" - ) + self.log(f"Preparing LZMA compressed data: {len(data)} Bytes >>> {len(compressed_data)} Bytes") return compressed_data def handle_raw_lzma(self, data, statistics): @@ -290,9 +284,7 @@ def handle_raw_lzma(self, data, statistics): The decompressed data as a bytearray. """ decompressed_data = lzma.decompress(data) - self.log( - f"Handling LZMA compressed data: {len(decompressed_data)} Bytes from {len(data)} Bytes" - ) + self.log(f"Handling LZMA compressed data: {len(decompressed_data)} Bytes from {len(data)} Bytes") return decompressed_data def failed_raw_lzma(self, data, statistics): @@ -338,9 +330,7 @@ def prepare_raw_gzip(self, data): The GZIP-compressed data as a bytearray. """ compressed_data = gzip.compress(data) - self.log( - f"Preparing GZIP compressed data: {len(data)} Bytes >>> {len(compressed_data)} Bytes" - ) + self.log(f"Preparing GZIP compressed data: {len(data)} Bytes >>> {len(compressed_data)} Bytes") return compressed_data def handle_raw_gzip(self, data, statistics): @@ -357,9 +347,7 @@ def handle_raw_gzip(self, data, statistics): The decompressed data as a bytearray. """ decompressed_data = gzip.decompress(data) - self.log( - f"Handling GZIP compressed data: {len(decompressed_data)} Bytes from {len(data)} Bytes" - ) + self.log(f"Handling GZIP compressed data: {len(decompressed_data)} Bytes from {len(data)} Bytes") return decompressed_data def failed_raw_gzip(self, data, statistics): @@ -408,9 +396,7 @@ def prepare_p2pmsg_zlib(self, data): compressor = zlib.compressobj(level=6, wbits=-zlib.MAX_WBITS, strategy=zlib.Z_FILTERED) compressed_data = compressor.compress(data) + compressor.flush() - self.log( - f"Preparing ZLIB compressed P2PMSG data: {len(data)} Bytes >>> {len(compressed_data)} Bytes" - ) + self.log(f"Preparing ZLIB compressed P2PMSG data: {len(data)} Bytes >>> {len(compressed_data)} Bytes") return compressed_data def handle_p2pmsg_zlib(self, data, statistics): @@ -431,9 +417,7 @@ def handle_p2pmsg_zlib(self, data, statistics): decompressed_data = decompressor.decompress(data) decompressed_data += decompressor.flush() - self.log( - f"Handling ZLIB compressed P2PMSG data: {len(decompressed_data)} Bytes from {len(data)} Bytes" - ) + self.log(f"Handling ZLIB compressed P2PMSG data: {len(decompressed_data)} Bytes from {len(data)} Bytes") message_received(self.ctx, decompressed_data, statistics) return decompressed_data @@ -500,9 +484,7 @@ def prepare_p2p_connection(self, data): compressor = zlib.compressobj(level=6, wbits=-zlib.MAX_WBITS, strategy=zlib.Z_FILTERED) compressed_data = compressor.compress(data) + compressor.flush() - self.log( - f"Preparing zlib compressed P2P_CONNECTION data: {len(data)} Bytes >>> {len(compressed_data)} Bytes" - ) + self.log(f"Preparing zlib compressed P2P_CONNECTION data: {len(data)} Bytes >>> {len(compressed_data)} Bytes") print(self.ctx.state_manager.p2p_connection_sessions) return compressed_data @@ -511,13 +493,9 @@ def handle_p2p_connection(self, data, statistics): decompressed_data = decompressor.decompress(data) decompressed_data += decompressor.flush() - self.log( - f"Handling gzip compressed P2P_CONNECTION data: {len(decompressed_data)} Bytes from {len(data)} Bytes" - ) + self.log(f"Handling gzip compressed P2P_CONNECTION data: {len(decompressed_data)} Bytes from {len(data)} Bytes") for session_id in self.ctx.state_manager.p2p_connection_sessions: - self.ctx.state_manager.p2p_connection_sessions[session_id].received_arq( - decompressed_data - ) + self.ctx.state_manager.p2p_connection_sessions[session_id].received_arq(decompressed_data) def failed_p2p_connection(self, data, statistics): decompressor = zlib.decompressobj(wbits=-zlib.MAX_WBITS) @@ -535,6 +513,4 @@ def transmitted_p2p_connection(self, data, statistics): decompressed_data = decompressor.decompress(data) decompressed_data += decompressor.flush() for session_id in self.ctx.state_manager.p2p_connection_sessions: - self.ctx.state_manager.p2p_connection_sessions[session_id].transmitted_arq( - decompressed_data - ) + self.ctx.state_manager.p2p_connection_sessions[session_id].transmitted_arq(decompressed_data) diff --git a/freedata_server/arq_session.py b/freedata_server/arq_session.py index a136d9224..a165a8f79 100644 --- a/freedata_server/arq_session.py +++ b/freedata_server/arq_session.py @@ -98,7 +98,6 @@ def __init__(self, ctx, dxcall: str): # we will use the schedule manager, for checking, how old is the state change for deciding, how we continue with the message self.last_state_change_timestamp = time.time() - # histogram lists for storing statistics self.snr_histogram = [] self.bpm_histogram = [] @@ -219,9 +218,7 @@ def on_frame_received(self, frame): ) return - self.log( - f"Ignoring unknown transition from state {self.state.name} with frame {frame['frame_type']}" - ) + self.log(f"Ignoring unknown transition from state {self.state.name} with frame {frame['frame_type']}") def is_session_outdated(self): """Checks if the session is outdated. @@ -365,9 +362,7 @@ def get_appropriate_speed_level(self, snr, maximum_bandwidth=None): # Adjust maximum_bandwidth if set to 0 (use maximum available bandwidth from speed levels) if maximum_bandwidth == 0: - maximum_bandwidth = max( - details["bandwidth"] for details in self.SPEED_LEVEL_DICT.values() - ) + maximum_bandwidth = max(details["bandwidth"] for details in self.SPEED_LEVEL_DICT.values()) # Iterate through speed levels in reverse order to find the highest appropriate one for level in sorted(self.SPEED_LEVEL_DICT.keys(), reverse=True): diff --git a/freedata_server/arq_session_irs.py b/freedata_server/arq_session_irs.py index 4582ee470..477cee356 100644 --- a/freedata_server/arq_session_irs.py +++ b/freedata_server/arq_session_irs.py @@ -187,9 +187,7 @@ def launch_transmit_and_wait(self, frame, timeout, mode): timeout: The timeout period in seconds. mode: The FreeDV mode to use for transmission. """ - thread_wait = threading.Thread( - target=self.transmit_and_wait, args=[frame, timeout, mode], daemon=True - ) + thread_wait = threading.Thread(target=self.transmit_and_wait, args=[frame, timeout, mode], daemon=True) thread_wait.start() def send_open_ack(self, open_frame): @@ -206,10 +204,7 @@ def send_open_ack(self, open_frame): Tuple[None, None]: Returns None for both data and type_byte as this method doesn't handle data. """ # check for maximum bandwidth. If ISS bandwidth is higher than own, then use own - if ( - open_frame["maximum_bandwidth"] - > self.ctx.config_manager.config["MODEM"]["maximum_bandwidth"] - ): + if open_frame["maximum_bandwidth"] > self.ctx.config_manager.config["MODEM"]["maximum_bandwidth"]: self.maximum_bandwidth = self.ctx.config_manager.config["MODEM"]["maximum_bandwidth"] else: self.maximum_bandwidth = open_frame["maximum_bandwidth"] @@ -254,12 +249,8 @@ def send_info_ack(self, info_frame): self.calibrate_speed_settings() - self.log( - f"New transfer of {self.total_length} bytes, received_bytes: {self.received_bytes}" - ) - self.ctx.event_manager.send_arq_session_new( - False, self.id, self.dxcall, self.total_length, self.state.name - ) + self.log(f"New transfer of {self.total_length} bytes, received_bytes: {self.received_bytes}") + self.ctx.event_manager.send_arq_session_new(False, self.id, self.dxcall, self.total_length, self.state.name) info_ack = self.frame_factory.build_arq_session_info_ack( self.id, @@ -357,9 +348,7 @@ def receive_data(self, burst_frame): if not self.all_data_received(): self.calibrate_speed_settings(burst_frame=burst_frame) - ack = self.frame_factory.build_arq_burst_ack( - self.id, self.speed_level, flag_abort=self.abort - ) + ack = self.frame_factory.build_arq_burst_ack(self.id, self.speed_level, flag_abort=self.abort) self.set_state(IRS_State.BURST_REPLY_SENT) self.ctx.event_manager.send_arq_session_progress( @@ -370,9 +359,7 @@ def receive_data(self, burst_frame): self.total_length, self.state.name, self.speed_level, - statistics=self.calculate_session_statistics( - self.received_bytes, self.total_length - ), + statistics=self.calculate_session_statistics(self.received_bytes, self.total_length), ) self.launch_transmit_and_wait(ack, self.TIMEOUT_DATA, mode=FREEDV_MODE.signalling_ack) @@ -380,9 +367,7 @@ def receive_data(self, burst_frame): if self.final_crc_matches(): self.log("All data received successfully!") - ack = self.frame_factory.build_arq_burst_ack( - self.id, self.speed_level, flag_final=True, flag_checksum=True - ) + ack = self.frame_factory.build_arq_burst_ack(self.id, self.speed_level, flag_final=True, flag_checksum=True) self.transmit_frame(ack, mode=FREEDV_MODE.signalling_ack) self.log("ACK sent") self.session_ended = time.time() @@ -417,9 +402,7 @@ def calibrate_speed_settings(self, burst_frame=None): _received_speed_level = burst_frame["speed_level"] if burst_frame else 0 latest_snr = self.snr if self.snr else -10 - appropriate_speed_level = self.get_appropriate_speed_level( - latest_snr, self.maximum_bandwidth - ) + appropriate_speed_level = self.get_appropriate_speed_level(latest_snr, self.maximum_bandwidth) modes_to_decode = {} # Log the latest SNR, current, appropriate speed levels, and the previous speed level @@ -485,9 +468,7 @@ def send_stop_ack(self, stop_frame): Tuple[None, None]: Returns None for both data and type_byte as this method doesn't handle data. """ stop_ack = self.frame_factory.build_arq_stop_ack(self.id) - self.launch_transmit_and_wait( - stop_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling_ack - ) + self.launch_transmit_and_wait(stop_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling_ack) self.set_state(IRS_State.ABORTED) self.ctx.state_manager.setARQ(False) session_stats = self.calculate_session_statistics(self.received_bytes, self.total_length) @@ -554,9 +535,7 @@ def transmission_aborted(self): self.dxcall, False, self.state.name, - statistics=self.calculate_session_statistics( - self.received_bytes, self.total_length - ), + statistics=self.calculate_session_statistics(self.received_bytes, self.total_length), ) self.ctx.state_manager.setARQ(False) return None, None diff --git a/freedata_server/arq_session_iss.py b/freedata_server/arq_session_iss.py index 81d376a4c..16d832b64 100644 --- a/freedata_server/arq_session_iss.py +++ b/freedata_server/arq_session_iss.py @@ -242,9 +242,7 @@ def start(self): """ maximum_bandwidth = self.ctx.config_manager.config["MODEM"]["maximum_bandwidth"] print(maximum_bandwidth) - self.ctx.event_manager.send_arq_session_new( - True, self.id, self.dxcall, self.total_length, self.state.name - ) + self.ctx.event_manager.send_arq_session_new(True, self.id, self.dxcall, self.total_length, self.state.name) session_open_frame = self.frame_factory.build_arq_session_open( self.dxcall, self.id, maximum_bandwidth, self.protocol_version ) @@ -319,9 +317,7 @@ def send_info(self, irs_frame): self.id, self.total_length, self.data_crc, self.snr, self.type_byte ) - self.launch_twr( - info_frame, self.TIMEOUT_CONNECT_ACK, self.RETRIES_INFO, mode=FREEDV_MODE.signalling - ) + self.launch_twr(info_frame, self.TIMEOUT_CONNECT_ACK, self.RETRIES_INFO, mode=FREEDV_MODE.signalling) self.set_state(ISS_State.INFO_SENT) return None, None @@ -405,9 +401,7 @@ def send_data(self, irs_frame, fallback=None): self.speed_level, ) burst.append(data_frame) - self.launch_twr( - burst, self.TIMEOUT_TRANSFER, self.RETRIES_DATA, mode="auto", isARQBurst=True - ) + self.launch_twr(burst, self.TIMEOUT_TRANSFER, self.RETRIES_DATA, mode="auto", isARQBurst=True) self.set_state(ISS_State.BURST_SENT) return None, None @@ -531,9 +525,7 @@ def send_stop(self): for transmission and retries. """ stop_frame = self.frame_factory.build_arq_stop(self.id) - self.launch_twr( - stop_frame, self.TIMEOUT_STOP_ACK, self.RETRIES_STOP, mode=FREEDV_MODE.signalling - ) + self.launch_twr(stop_frame, self.TIMEOUT_STOP_ACK, self.RETRIES_STOP, mode=FREEDV_MODE.signalling) def transmission_aborted(self, irs_frame=None): """Handles the abortion of the transmission. @@ -563,9 +555,7 @@ def transmission_aborted(self, irs_frame=None): self.dxcall, False, self.state.name, - statistics=self.calculate_session_statistics( - self.confirmed_bytes, self.total_length - ), + statistics=self.calculate_session_statistics(self.confirmed_bytes, self.total_length), ) # self.ctx.state_manager.remove_arq_iss_session(self.id) self.ctx.state_manager.setARQ(False) diff --git a/freedata_server/audio.py b/freedata_server/audio.py index c3aca6c24..bafe87c56 100644 --- a/freedata_server/audio.py +++ b/freedata_server/audio.py @@ -33,9 +33,7 @@ def get_audio_devices(): proxy_input_devices = manager.list() proxy_output_devices = manager.list() # print(multiprocessing.get_start_method()) - proc = multiprocessing.Process( - target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices) - ) + proc = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)) proc.start() proc.join(3) @@ -334,9 +332,7 @@ def prepare_data_for_fft(data, target_length_samples=800): # If data is shorter than the target length, pad with zeros if len(data) < target_length_samples: - return np.pad( - data, (0, target_length_samples - len(data)), "constant", constant_values=(0,) - ) + return np.pad(data, (0, target_length_samples - len(data)), "constant", constant_values=(0,)) else: # If data is longer or equal to the target length, truncate it return data[:target_length_samples] @@ -430,11 +426,7 @@ def calculate_fft(data, fft_queue, states) -> None: # Iterate over each slot range to detect activity for slot, (range_start, range_end) in enumerate(SLOT_RANGES): # Check if any frequency in the slot exceeds the threshold - if ( - np.any(significant_frequencies[range_start:range_end]) - and not_transmitting - and not_receiving - ): + if np.any(significant_frequencies[range_start:range_end]) and not_transmitting and not_receiving: # Mark that additional delay should be added addDelay = True diff --git a/freedata_server/b64.py b/freedata_server/b64.py index 54e9deacc..65f33a9f5 100644 --- a/freedata_server/b64.py +++ b/freedata_server/b64.py @@ -1,6 +1,6 @@ import base64 -string = b'aGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQh' +string = b"aGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQhaGVsbG8gd29ybGQh" -print(base64.b64decode(string)) \ No newline at end of file +print(base64.b64decode(string)) diff --git a/freedata_server/codec2.py b/freedata_server/codec2.py index 8f4a4ad96..62bbfb997 100644 --- a/freedata_server/codec2.py +++ b/freedata_server/codec2.py @@ -531,9 +531,7 @@ def create_default_ofdm_config(): tx_bpf_en=False, rx_bpf_en=False, tx_bpf_proto=codec2_filter_coeff.testFilter, - tx_bpf_proto_n=int( - ctypes.sizeof(codec2_filter_coeff.testFilter) / ctypes.sizeof(ctypes.c_float) - ), + tx_bpf_proto_n=int(ctypes.sizeof(codec2_filter_coeff.testFilter) / ctypes.sizeof(ctypes.c_float)), foff_limiter=False, amp_scale=300e3, clip_gain1=2.2, @@ -639,12 +637,8 @@ def get_centered_first_tone(config, center=1500): data_ofdm_200_config.config.contents.clip_gain1 = 1.2 data_ofdm_200_config.config.contents.clip_gain2 = 1.0 data_ofdm_200_config.config.contents.tx_bpf_en = False -data_ofdm_200_config.config.contents.tx_bpf_proto = ( - codec2_filter_coeff.generate_filter_coefficients(8000, 400, 101) -) -data_ofdm_200_config.config.contents.tx_bpf_proto_n = ( - 101 # TODO sizeof(filtP200S400) / sizeof(float); -) +data_ofdm_200_config.config.contents.tx_bpf_proto = codec2_filter_coeff.generate_filter_coefficients(8000, 400, 101) +data_ofdm_200_config.config.contents.tx_bpf_proto_n = 101 # TODO sizeof(filtP200S400) / sizeof(float); # DATAC4 # OFDM 250 @@ -667,12 +661,8 @@ def get_centered_first_tone(config, center=1500): data_ofdm_250_config.config.contents.clip_gain1 = 1.2 data_ofdm_250_config.config.contents.clip_gain2 = 1.0 data_ofdm_250_config.config.contents.tx_bpf_en = True -data_ofdm_250_config.config.contents.tx_bpf_proto = ( - codec2_filter_coeff.generate_filter_coefficients(8000, 400, 101) -) -data_ofdm_250_config.config.contents.tx_bpf_proto_n = ( - 101 # TODO sizeof(filtP200S400) / sizeof(float); -) +data_ofdm_250_config.config.contents.tx_bpf_proto = codec2_filter_coeff.generate_filter_coefficients(8000, 400, 101) +data_ofdm_250_config.config.contents.tx_bpf_proto_n = 101 # TODO sizeof(filtP200S400) / sizeof(float); # OFDM 500 @@ -695,9 +685,7 @@ def get_centered_first_tone(config, center=1500): data_ofdm_500_config.config.contents.clip_gain1 = 2.5 # 2.8 data_ofdm_500_config.config.contents.clip_gain2 = 1.0 # 0.9 data_ofdm_500_config.config.contents.tx_bpf_en = True -data_ofdm_500_config.config.contents.tx_bpf_proto = ( - codec2_filter_coeff.generate_filter_coefficients(8000, 600, 100) -) +data_ofdm_500_config.config.contents.tx_bpf_proto = codec2_filter_coeff.generate_filter_coefficients(8000, 600, 100) data_ofdm_500_config.config.contents.tx_bpf_proto_n = 100 @@ -716,9 +704,7 @@ def get_centered_first_tone(config, center=1500): data_ofdm_1700_config.config.contents.clip_gain2 = 0.8 data_ofdm_1700_config.config.contents.amp_scale = 145e3 data_ofdm_1700_config.config.contents.tx_bpf_en = False -data_ofdm_1700_config.config.contents.tx_bpf_proto = ( - codec2_filter_coeff.generate_filter_coefficients(8000, 2000, 100) -) +data_ofdm_1700_config.config.contents.tx_bpf_proto = codec2_filter_coeff.generate_filter_coefficients(8000, 2000, 100) data_ofdm_1700_config.config.contents.tx_bpf_proto_n = 100 data_ofdm_1700_config.config.contents.tx_uw = create_tx_uw( data_ofdm_1700_config.config.contents.nuwbits, [1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0] @@ -758,16 +744,16 @@ def get_centered_first_tone(config, center=1500): data_ofdm_2438_config.config.contents.amp_scale = 106e3 data_ofdm_2438_config.config.contents.codename = "H_16200_9720".encode("utf-8") data_ofdm_2438_config.config.contents.clip_gain1 = 3.3 -data_ofdm_2438_config.config.contents.clip_gain2 = 1.5 # 0.8 - a test in real world shows, 0.8 seems to be not enough for decoding. Lets test this some more time. +data_ofdm_2438_config.config.contents.clip_gain2 = ( + 1.5 # 0.8 - a test in real world shows, 0.8 seems to be not enough for decoding. Lets test this some more time. +) data_ofdm_2438_config.config.contents.timing_mx_thresh = 0.10 data_ofdm_2438_config.config.contents.tx_uw = create_tx_uw( data_ofdm_2438_config.config.contents.nuwbits, [1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], ) data_ofdm_2438_config.config.contents.tx_bpf_en = True -data_ofdm_2438_config.config.contents.tx_bpf_proto = ( - codec2_filter_coeff.generate_filter_coefficients(8000, 2700, 100) -) +data_ofdm_2438_config.config.contents.tx_bpf_proto = codec2_filter_coeff.generate_filter_coefficients(8000, 2700, 100) data_ofdm_2438_config.config.contents.tx_bpf_proto_n = 100 # ---------------- QAM 2438 Hz Bandwidth ---------------# diff --git a/freedata_server/command_fec.py b/freedata_server/command_fec.py index 6bf5e396b..d6a2960ba 100644 --- a/freedata_server/command_fec.py +++ b/freedata_server/command_fec.py @@ -69,9 +69,7 @@ def transmit(self, tx_frame_queue): tx_frame_queue: The transmission queue. """ if self.wakeup: - tx_queue_item = self.make_modem_queue_item( - self.get_c2_mode(), 1, 0, self.build_wakeup_frame() - ) + tx_queue_item = self.make_modem_queue_item(self.get_c2_mode(), 1, 0, self.build_wakeup_frame()) tx_frame_queue.put(tx_queue_item) tx_queue_item = self.make_modem_queue_item(self.get_c2_mode(), 1, 0, self.build_frame()) diff --git a/freedata_server/command_message_send.py b/freedata_server/command_message_send.py index 32caf09e9..0d1e01e84 100644 --- a/freedata_server/command_message_send.py +++ b/freedata_server/command_message_send.py @@ -56,9 +56,7 @@ def transmit(self): try: self.log(f"Queued message found: {first_queued_message['id']}") # DatabaseManagerMessages(self.ctx.event_manager).update_message(first_queued_message["id"], update_data={'status': 'transmitting'}, frequency=self.ctx.state_manager.radio_frequency) - message_dict = DatabaseManagerMessages(self.ctx).get_message_by_id( - first_queued_message["id"] - ) + message_dict = DatabaseManagerMessages(self.ctx).get_message_by_id(first_queued_message["id"]) message = MessageP2P.from_api_params(message_dict["origin"], message_dict) # wait some random time and wait if we have an ongoing codec2 transmission @@ -77,9 +75,7 @@ def transmit(self): while time.time() < time_waiting_for_free_channel: threading.Event().wait(0.1) if self.ctx.state_manager.is_receiving_codec2_signal(): - self.log( - "Codec2 signal found, skipping message until next cycle", isWarning=True - ) + self.log("Codec2 signal found, skipping message until next cycle", isWarning=True) return # If we came until here, we are setting status to transmitting, otherwise it stays in queued @@ -92,9 +88,7 @@ def transmit(self): # Convert JSON string to bytes (using UTF-8 encoding) payload = message.to_payload().encode("utf-8") json_bytearray = bytearray(payload) - data, data_type = self.arq_data_type_handler.prepare( - json_bytearray, ARQ_SESSION_TYPES.p2pmsg_zlib - ) + data, data_type = self.arq_data_type_handler.prepare(json_bytearray, ARQ_SESSION_TYPES.p2pmsg_zlib) iss = ARQSessionISS(self.ctx, self.message.destination, data, data_type) self.ctx.state_manager.register_arq_iss_session(iss) iss.start() diff --git a/freedata_server/command_norm.py b/freedata_server/command_norm.py index 47e54f5ac..2cc10ad8d 100644 --- a/freedata_server/command_norm.py +++ b/freedata_server/command_norm.py @@ -7,51 +7,46 @@ import threading from norm.norm_transmission_iss import NormTransmissionISS + class Norm(TxCommand): def set_params_from_api(self, apiParams): - self.origin = apiParams['origin'] + self.origin = apiParams["origin"] if not api_validations.validate_freedata_callsign(self.origin): self.origin = f"{self.origin}-0" - self.domain = apiParams['domain'] + self.domain = apiParams["domain"] if not api_validations.validate_freedata_callsign(self.domain): self.domain = f"{self.domain}-0" - # strip data to maximum payload - self.data = base64.b64decode(apiParams['data']) - self.data = self.data[:15*26] + self.data = base64.b64decode(apiParams["data"]) + self.data = self.data[: 15 * 26] - - if 'priority' not in apiParams: + if "priority" not in apiParams: self.priority = 1 else: - self.priority = apiParams['priority'] - - self.msgtype = apiParams['type'] - self.gridsquare = apiParams['gridsquare'] + self.priority = apiParams["priority"] + self.msgtype = apiParams["type"] + self.gridsquare = apiParams["gridsquare"] def run(self): try: - if not self.ctx.config_manager.config["EXP"]["enable_groupchat"]: return False self.emit_event() self.logger.info(self.log_message()) - #NormTransmissionISS(self.ctx).prepare_and_transmit_data(self.origin, self.domain, self.gridsquare, self.data, self.priority, self.msgtype) + # NormTransmissionISS(self.ctx).prepare_and_transmit_data(self.origin, self.domain, self.gridsquare, self.data, self.priority, self.msgtype) tx_thread = threading.Thread( target=NormTransmissionISS(self.ctx).prepare_and_transmit_data, - args=(self.origin, self.domain, self.gridsquare, self.data, self.priority, self.msgtype) + args=(self.origin, self.domain, self.gridsquare, self.data, self.priority, self.msgtype), ) tx_thread.start() - - except Exception as e: self.log(f"Error starting NORM transmission: {e}", isWarning=True) - return False \ No newline at end of file + return False diff --git a/freedata_server/config.py b/freedata_server/config.py index e88ff3d39..d6f0e8328 100644 --- a/freedata_server/config.py +++ b/freedata_server/config.py @@ -250,9 +250,7 @@ def handle_setting(self, section, setting, value, is_writing=False): else: return value except KeyError as key: - self.log.error( - "[CFG] key error in logfile, please check 'config.ini.example' for help", key=key - ) + self.log.error("[CFG] key error in logfile, please check 'config.ini.example' for help", key=key) # Sets and writes config data from a dict containing data settings def write(self, data): @@ -328,9 +326,7 @@ def read(self): # handle the special settings for section in result: for setting in result[section]: - result[section][setting] = self.handle_setting( - section, setting, result[section][setting], False - ) + result[section][setting] = self.handle_setting(section, setting, result[section][setting], False) # store config in config manager instance self.config = result diff --git a/freedata_server/constants.py b/freedata_server/constants.py index 68408413f..6f611b182 100644 --- a/freedata_server/constants.py +++ b/freedata_server/constants.py @@ -1,11 +1,11 @@ # Module for saving some constants -CONFIG_ENV_VAR = 'FREEDATA_CONFIG' -DEFAULT_CONFIG_FILE = 'config.ini' +CONFIG_ENV_VAR = "FREEDATA_CONFIG" +DEFAULT_CONFIG_FILE = "config.ini" MODEM_VERSION = "0.19.0" API_VERSION = 4 ARQ_PROTOCOL_VERSION = 1 -LICENSE = 'GPL3.0' -DOCUMENTATION_URL = 'https://wiki.freedata.app' -STATS_API_URL = 'https://api.freedata.app/stats.php' -EXPLORER_API_URL = 'https://api.freedata.app/explorer.php' +LICENSE = "GPL3.0" +DOCUMENTATION_URL = "https://wiki.freedata.app" +STATS_API_URL = "https://api.freedata.app/stats.php" +EXPLORER_API_URL = "https://api.freedata.app/explorer.php" MESSAGE_SYSTEM_DATABASE_VERSION = 1 diff --git a/freedata_server/data_frame_factory.py b/freedata_server/data_frame_factory.py index 3c9d7c2eb..c2889ace4 100644 --- a/freedata_server/data_frame_factory.py +++ b/freedata_server/data_frame_factory.py @@ -31,16 +31,14 @@ class DataFrameFactory: } NORM_FLAGS = { - 'LAST_DATA': 0, # Bit-position for indicating the LAST DATA state + "LAST_DATA": 0, # Bit-position for indicating the LAST DATA state } def __init__(self, ctx): self.ctx = ctx self.myfullcall = f"{self.ctx.config_manager.config['STATION']['mycall']}-{self.ctx.config_manager.config['STATION']['myssid']}" - self.mygrid = maidenhead.generate_full_maidenhead( - self.ctx.config_manager.config["STATION"]["mygrid"] - ) + self.mygrid = maidenhead.generate_full_maidenhead(self.ctx.config_manager.config["STATION"]["mygrid"]) # table for holding our frame templates self.template_list = {} @@ -243,7 +241,7 @@ def _load_norm_templates(self): "burst_info": 1, "checksum": 3, "payload_size": 2, - "payload_data": 26 + "payload_data": 26, } # repair frame @@ -257,7 +255,7 @@ def _load_norm_templates(self): "burst_info": 1, "checksum": 3, "payload_size": 2, - "payload_data": 26 + "payload_data": 26, } # nack frame @@ -265,7 +263,7 @@ def _load_norm_templates(self): "frame_length": self.LENGTH_NORM_FRAME, "origin": 6, "id": 10, - "burst_numbers":8 + "burst_numbers": 8, } # cmd frame @@ -274,10 +272,10 @@ def _load_norm_templates(self): "frame_length": self.LENGTH_NORM_FRAME, "origin": 6, "domain": 4, - "flag": 1 + "flag": 1, } - def construct(self, frametype, content, frame_length = LENGTH_SIG1_FRAME): + def construct(self, frametype, content, frame_length=LENGTH_SIG1_FRAME): frame_template = self.template_list[frametype.value] if isinstance(frame_template["frame_length"], int): @@ -302,7 +300,7 @@ def construct(self, frametype, content, frame_length = LENGTH_SIG1_FRAME): # print(content) if buffer_position + item_length > frame_length: raise OverflowError(f"Frame data overflow! {buffer_position + item_length} of max {frame_length}") - frame[buffer_position: buffer_position + item_length] = content[key] + frame[buffer_position : buffer_position + item_length] = content[key] buffer_position += item_length return frame @@ -352,12 +350,24 @@ def deconstruct(self, frame, mode_name=None): extracted_data[key] = helpers.decode_grid(data) elif key == "burst_numbers": - extracted_data[key] = [x for x in data if x !=0] - - elif key in ["session_id", "speed_level", - "frames_per_burst", "version", - "offset", "total_length", "state", "type", "maximum_bandwidth", "protocol_version", "burst_info", "timestamp", "payload_size"]: - extracted_data[key] = int.from_bytes(data, 'big') + extracted_data[key] = [x for x in data if x != 0] + + elif key in [ + "session_id", + "speed_level", + "frames_per_burst", + "version", + "offset", + "total_length", + "state", + "type", + "maximum_bandwidth", + "protocol_version", + "burst_info", + "timestamp", + "payload_size", + ]: + extracted_data[key] = int.from_bytes(data, "big") print(key, data) elif key in ["snr"]: extracted_data[key] = helpers.snr_from_bytes(data) @@ -395,7 +405,12 @@ def deconstruct(self, frame, mode_name=None): # get_flag returns True or False based on the bit value at the flag's position extracted_data[key][flag] = helpers.get_flag(data, flag, flag_dict) - if frametype in [FR_TYPE.NORM_DATA.value, FR_TYPE.NORM_NACK.value, FR_TYPE.NORM_REPAIR.value, FR_TYPE.NORM_CMD.value]: + if frametype in [ + FR_TYPE.NORM_DATA.value, + FR_TYPE.NORM_NACK.value, + FR_TYPE.NORM_REPAIR.value, + FR_TYPE.NORM_CMD.value, + ]: extracted_data[key] = data # flag_dict = self.NORM_FLAGS # for flag in flag_dict: @@ -525,9 +540,7 @@ def build_arq_session_open_ack(self, session_id, destination, version, snr, flag } return self.construct(FR_TYPE.ARQ_SESSION_OPEN_ACK, payload) - def build_arq_session_info( - self, session_id: int, total_length: int, total_crc: bytes, snr, type - ): + def build_arq_session_info(self, session_id: int, total_length: int, total_crc: bytes, snr, type): flag = 0b00000000 payload = { @@ -593,9 +606,7 @@ def build_arq_burst_frame( "offset": offset.to_bytes(4, "big"), "data": data, } - return self.construct( - FR_TYPE.ARQ_BURST_FRAME, payload, self.get_bytes_per_frame(freedv_mode) - ) + return self.construct(FR_TYPE.ARQ_BURST_FRAME, payload, self.get_bytes_per_frame(freedv_mode)) def build_arq_burst_ack( self, @@ -638,9 +649,7 @@ def build_p2p_connection_connect_ack(self, destination, origin, session_id): } return self.construct(FR_TYPE.P2P_CONNECTION_CONNECT_ACK, payload) - def build_p2p_connection_heartbeat( - self, session_id, flag_has_data=False, flag_announce_arq=False - ): + def build_p2p_connection_heartbeat(self, session_id, flag_has_data=False, flag_announce_arq=False): flag = 0b00000000 if flag_has_data: flag = helpers.set_flag(flag, "HAS_DATA", True, self.P2P_FLAGS) @@ -653,9 +662,7 @@ def build_p2p_connection_heartbeat( } return self.construct(FR_TYPE.P2P_CONNECTION_HEARTBEAT, payload) - def build_p2p_connection_heartbeat_ack( - self, session_id, flag_has_data=False, flag_announce_arq=False - ): + def build_p2p_connection_heartbeat_ack(self, session_id, flag_has_data=False, flag_announce_arq=False): flag = 0b00000000 if flag_has_data: flag = helpers.set_flag(flag, "HAS_DATA", True, self.P2P_FLAGS) @@ -715,48 +722,49 @@ def build_p2p_connection_disconnect_ack(self, session_id): } return self.construct(FR_TYPE.P2P_CONNECTION_DISCONNECT_ACK, payload) - def build_norm_data(self, origin, domain, gridsquare, timestamp, burst_info, payload_size, payload_data, flag, checksum): + def build_norm_data( + self, origin, domain, gridsquare, timestamp, burst_info, payload_size, payload_data, flag, checksum + ): payload = { "origin": helpers.callsign_to_bytes(origin), "domain": helpers.callsign_to_bytes(domain), "gridsquare": helpers.encode_grid(gridsquare), - "flag": flag.to_bytes(1, 'big'), - "timestamp": timestamp.to_bytes(4, 'big'), - "burst_info": burst_info.to_bytes(1, 'big'), - "payload_size": payload_size.to_bytes(2, 'big'), + "flag": flag.to_bytes(1, "big"), + "timestamp": timestamp.to_bytes(4, "big"), + "burst_info": burst_info.to_bytes(1, "big"), + "payload_size": payload_size.to_bytes(2, "big"), "payload_data": payload_data, - "checksum": checksum + "checksum": checksum, } return self.construct(FR_TYPE.NORM_DATA, payload) - - - - def build_norm_nack(self, origin, id, burst_numbers:list[int]): + def build_norm_nack(self, origin, id, burst_numbers: list[int]): max_burst_numbers = self.template_list[FR_TYPE.NORM_NACK.value]["burst_numbers"] - padded_numbers = burst_numbers + [0] * (max_burst_numbers-len(burst_numbers)) + padded_numbers = burst_numbers + [0] * (max_burst_numbers - len(burst_numbers)) payload = { "origin": helpers.callsign_to_bytes(origin), - "id": bytes(id, 'utf-8'), + "id": bytes(id, "utf-8"), "burst_numbers": bytes(padded_numbers), } return self.construct(FR_TYPE.NORM_NACK, payload) - def build_norm_repair(self, origin, domain, gridsquare, timestamp, burst_info, payload_size, payload_data, flag, checksum): + def build_norm_repair( + self, origin, domain, gridsquare, timestamp, burst_info, payload_size, payload_data, flag, checksum + ): payload = { "origin": helpers.callsign_to_bytes(origin), "domain": helpers.callsign_to_bytes(domain), "gridsquare": helpers.encode_grid(gridsquare), - "flag": flag.to_bytes(1, 'big'), - "timestamp": timestamp.to_bytes(4, 'big'), - "burst_info": burst_info.to_bytes(1, 'big'), - "payload_size": payload_size.to_bytes(2, 'big'), + "flag": flag.to_bytes(1, "big"), + "timestamp": timestamp.to_bytes(4, "big"), + "burst_info": burst_info.to_bytes(1, "big"), + "payload_size": payload_size.to_bytes(2, "big"), "payload_data": payload_data, - "checksum": checksum + "checksum": checksum, } return self.construct(FR_TYPE.NORM_REPAIR, payload) def build_norm_cmd(self): - pass \ No newline at end of file + pass diff --git a/freedata_server/demodulator.py b/freedata_server/demodulator.py index 7b56b3dc6..9a1118a64 100644 --- a/freedata_server/demodulator.py +++ b/freedata_server/demodulator.py @@ -154,19 +154,12 @@ def demodulate_audio(self, mode) -> int: last_rx_status = 0 try: - while ( - self.stream - and self.stream.active - and not self.shutdown_flag.is_set() - or self.ctx.TESTMODE - ): + 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 if not self.ctx.state_manager.isTransmitting(): - nbytes = codec2.api.freedv_rawdatarx( - freedv, bytes_out, audiobuffer.buffer.ctypes - ) + nbytes = codec2.api.freedv_rawdatarx(freedv, bytes_out, audiobuffer.buffer.ctypes) # get current freedata_server states and write to list # 1 trial @@ -266,9 +259,7 @@ def calculate_snr(self, freedv: ctypes.c_void_p) -> float: modem_stats_snr = ctypes.c_float() modem_stats_sync = ctypes.c_int() - codec2.api.freedv_get_modem_stats( - freedv, ctypes.byref(modem_stats_sync), ctypes.byref(modem_stats_snr) - ) + codec2.api.freedv_get_modem_stats(freedv, ctypes.byref(modem_stats_sync), ctypes.byref(modem_stats_snr)) modem_stats_snr = modem_stats_snr.value modem_stats_sync = modem_stats_sync.value @@ -306,9 +297,7 @@ def get_scatter(self, freedv: ctypes.c_void_p) -> None: # if xsymbols != 0.0 and ysymbols != 0.0: # scatterdata.append({"x": str(xsymbols), "y": str(ysymbols)}) - for i, j in itertools.product( - range(codec2.MODEM_STATS_NC_MAX), range(1, codec2.MODEM_STATS_NR_MAX, 2) - ): + for i, j in itertools.product(range(codec2.MODEM_STATS_NC_MAX), range(1, codec2.MODEM_STATS_NR_MAX, 2)): # print(f"{modemStats.rx_symbols[i][j]} - {modemStats.rx_symbols[i][j]}") xsymbols = round(modemStats.rx_symbols[i][j - 1] // 1000) ysymbols = round(modemStats.rx_symbols[i][j] // 1000) diff --git a/freedata_server/explorer.py b/freedata_server/explorer.py index 46e4ecce0..cd3b3084c 100644 --- a/freedata_server/explorer.py +++ b/freedata_server/explorer.py @@ -44,11 +44,7 @@ def push(self): pushes, failed pushes, and connection issues. """ - frequency = ( - 0 - if self.ctx.state_manager.radio_frequency is None - else self.ctx.state_manager.radio_frequency - ) + frequency = 0 if self.ctx.state_manager.radio_frequency is None else self.ctx.state_manager.radio_frequency band = "USB" callsign = f"{self.ctx.config_manager.config['STATION']['mycall']}-{self.ctx.config_manager.config['STATION']['myssid']}" gridsquare = str(self.ctx.config_manager.config["STATION"]["mygrid"]) diff --git a/freedata_server/frame_dispatcher.py b/freedata_server/frame_dispatcher.py index b92768882..f38853812 100644 --- a/freedata_server/frame_dispatcher.py +++ b/freedata_server/frame_dispatcher.py @@ -76,19 +76,18 @@ class DISPATCHER: FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP"}, FR_TYPE.ARQ_STOP_ACK.value: {"class": ARQFrameHandler, "name": "ARQ STOP ACK"}, FR_TYPE.BEACON.value: {"class": BeaconFrameHandler, "name": "BEACON"}, - FR_TYPE.ARQ_BURST_FRAME.value:{"class": ARQFrameHandler, "name": "BURST FRAME"}, - FR_TYPE.ARQ_BURST_ACK.value: {"class": ARQFrameHandler, "name": "BURST ACK"}, - FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"}, - FR_TYPE.PING_ACK.value: {"class": FrameHandler, "name": "PING ACK"}, - FR_TYPE.PING.value: {"class": PingFrameHandler, "name": "PING"}, - FR_TYPE.QRV.value: {"class": FrameHandler, "name": "QRV"}, + FR_TYPE.ARQ_BURST_FRAME.value: {"class": ARQFrameHandler, "name": "BURST FRAME"}, + FR_TYPE.ARQ_BURST_ACK.value: {"class": ARQFrameHandler, "name": "BURST ACK"}, + FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"}, + FR_TYPE.PING_ACK.value: {"class": FrameHandler, "name": "PING ACK"}, + FR_TYPE.PING.value: {"class": PingFrameHandler, "name": "PING"}, + FR_TYPE.QRV.value: {"class": FrameHandler, "name": "QRV"}, FR_TYPE.NORM_DATA.value: {"class": NORMFrameHandler, "name": "NORM DATA"}, FR_TYPE.NORM_NACK.value: {"class": NORMFrameHandler, "name": "NORM NACK"}, FR_TYPE.NORM_REPAIR.value: {"class": NORMFrameHandler, "name": "NORM REPAIR"}, - - #FR_TYPE.IS_WRITING.value: {"class": FrameHandler, "name": "IS_WRITING"}, - #FR_TYPE.FEC.value: {"class": FrameHandler, "name": "FEC"}, - #FR_TYPE.FEC_WAKEUP.value: {"class": FrameHandler, "name": "FEC WAKEUP"}, + # FR_TYPE.IS_WRITING.value: {"class": FrameHandler, "name": "IS_WRITING"}, + # FR_TYPE.FEC.value: {"class": FrameHandler, "name": "FEC"}, + # FR_TYPE.FEC_WAKEUP.value: {"class": FrameHandler, "name": "FEC WAKEUP"}, } def __init__(self, ctx): @@ -137,9 +136,7 @@ def worker_receive(self) -> None: except Exception: continue - def process_data( - self, bytes_out, freedv, bytes_per_frame: int, snr, frequency_offset, mode_name - ) -> None: + def process_data(self, bytes_out, freedv, bytes_per_frame: int, snr, frequency_offset, mode_name) -> None: """Processes received data frames. This method deconstructs the received data into a frame dictionary, diff --git a/freedata_server/frame_handler.py b/freedata_server/frame_handler.py index 6b8451034..a0c328e58 100644 --- a/freedata_server/frame_handler.py +++ b/freedata_server/frame_handler.py @@ -88,24 +88,18 @@ def is_frame_for_me(self): valid = True # check for NORM data - elif ft in ['NORM_DATA']: + elif ft in ["NORM_DATA"]: # TODO # maybe we can add a list of domains, we are listening to in state manager? valid = True - # check for p2p connection elif ft in ["P2P_CONNECTION_CONNECT"]: # Need to make sure this does not affect any other features in FreeDATA. # This will allow the client to respond to any call sent in the "MYCALL" command - self.details["frame"]["destination_crc"] = helpers.get_crc_24( - self.details["frame"]["destination"] - ) - if ( - self.ctx.socket_interface_manager - and self.ctx.socket_interface_manager.socket_interface_callsigns - ): + self.details["frame"]["destination_crc"] = helpers.get_crc_24(self.details["frame"]["destination"]) + if self.ctx.socket_interface_manager and self.ctx.socket_interface_manager.socket_interface_callsigns: print("checking callsings....") print(self.ctx.socket_interface_manager.socket_interface_callsigns) for callsign in self.ctx.socket_interface_manager.socket_interface_callsigns: @@ -173,15 +167,10 @@ def is_origin_on_blacklist(self): origin_callsign = self.details["frame"]["origin"] for blacklist_callsign in self.ctx.config_manager.config["STATION"]["callsign_blacklist"]: - if ( - helpers.get_crc_24(origin_callsign).hex() - == helpers.get_crc_24(blacklist_callsign).hex() - ): + if helpers.get_crc_24(origin_callsign).hex() == helpers.get_crc_24(blacklist_callsign).hex(): return True - if origin_callsign == blacklist_callsign or origin_callsign.startswith( - blacklist_callsign - ): + if origin_callsign == blacklist_callsign or origin_callsign.startswith(blacklist_callsign): return True return False @@ -246,9 +235,9 @@ def add_to_heard_stations(self): distance_miles = distance_dict["miles"] away_from_key = False - if "flag" in self.details['frame'] and isinstance(frame["flag"], (list, dict, Iterable)): - if "AWAY_FROM_KEY" in self.details['frame']["flag"]: - away_from_key = self.details['frame']["flag"]["AWAY_FROM_KEY"] + if "flag" in self.details["frame"] and isinstance(frame["flag"], (list, dict, Iterable)): + if "AWAY_FROM_KEY" in self.details["frame"]["flag"]: + away_from_key = self.details["frame"]["flag"]["AWAY_FROM_KEY"] helpers.add_to_heard_stations( frame["origin"], @@ -299,10 +288,12 @@ def make_event(self): event["distance_kilometers"] = 0 event["distance_miles"] = 0 - - - if "flag" in self.details and isinstance(self.details["flag"], (list, dict, Iterable)) and "AWAY_FROM_KEY" in self.details['frame']["flag"]: - event['away_from_key'] = self.details['frame']["flag"]["AWAY_FROM_KEY"] + if ( + "flag" in self.details + and isinstance(self.details["flag"], (list, dict, Iterable)) + and "AWAY_FROM_KEY" in self.details["frame"]["flag"] + ): + event["away_from_key"] = self.details["frame"]["flag"]["AWAY_FROM_KEY"] return event @@ -382,21 +373,16 @@ def handle(self, frame, snr, frequency_offset, freedv_inst, bytes_per_frame): self.details["freedv_inst"] = freedv_inst self.details["bytes_per_frame"] = bytes_per_frame - if 'origin' not in self.details['frame'] and 'session_id' in self.details['frame']: - dxcall = self.ctx.state_manager.get_dxcall_by_session_id(self.details['frame']['session_id']) + if "origin" not in self.details["frame"] and "session_id" in self.details["frame"]: + dxcall = self.ctx.state_manager.get_dxcall_by_session_id(self.details["frame"]["session_id"]) if dxcall: self.details["frame"]["origin"] = dxcall # look in database for a full callsign if only crc is present if "origin" not in self.details["frame"] and "origin_crc" in self.details["frame"]: - self.details["frame"]["origin"] = DatabaseManager(self.ctx).get_callsign_by_checksum( - frame["origin_crc"] - ) + self.details["frame"]["origin"] = DatabaseManager(self.ctx).get_callsign_by_checksum(frame["origin_crc"]) - if ( - "location" in self.details["frame"] - and "gridsquare" in self.details["frame"]["location"] - ): + if "location" in self.details["frame"] and "gridsquare" in self.details["frame"]["location"]: DatabaseManagerStations(self.ctx).update_station_location( self.details["frame"]["origin"], frame["gridsquare"] ) @@ -404,9 +390,7 @@ def handle(self, frame, snr, frequency_offset, freedv_inst, bytes_per_frame): if "origin" in self.details["frame"]: # try to find station info in database try: - station = DatabaseManagerStations(self.ctx).get_station( - self.details["frame"]["origin"] - ) + station = DatabaseManagerStations(self.ctx).get_station(self.details["frame"]["origin"]) if station and station["location"] and "gridsquare" in station["location"]: dxgrid = station["location"]["gridsquare"] else: @@ -417,16 +401,12 @@ def handle(self, frame, snr, frequency_offset, freedv_inst, bytes_per_frame): self.details["frame"]["gridsquare"] = dxgrid except Exception as e: - self.logger.info( - f"[Frame Handler] Error getting gridsquare from callsign info: {e}" - ) + self.logger.info(f"[Frame Handler] Error getting gridsquare from callsign info: {e}") # check if callsign is blacklisted if self.ctx.config_manager.config["STATION"]["enable_callsign_blacklist"]: if self.is_origin_on_blacklist(): - self.logger.info( - f"[Frame Handler] Callsign blocked: {self.details['frame']['origin']}" - ) + self.logger.info(f"[Frame Handler] Callsign blocked: {self.details['frame']['origin']}") return False self.log() @@ -446,11 +426,6 @@ def check_for_queued_message(self): """ # only check for queued messages, if we have enabled this and if we have a minimum snr received - if ( - self.ctx.config_manager.config["MESSAGES"]["enable_auto_repeat"] - and self.details["snr"] >= -2 - ): + if self.ctx.config_manager.config["MESSAGES"]["enable_auto_repeat"] and self.details["snr"] >= -2: # set message to queued if beacon received - DatabaseManagerMessages(self.ctx).set_message_to_queued_for_callsign( - self.details["frame"]["origin"] - ) + DatabaseManagerMessages(self.ctx).set_message_to_queued_for_callsign(self.details["frame"]["origin"]) diff --git a/freedata_server/frame_handler_arq_session.py b/freedata_server/frame_handler_arq_session.py index 6ca1658fe..aa726978d 100644 --- a/freedata_server/frame_handler_arq_session.py +++ b/freedata_server/frame_handler_arq_session.py @@ -60,9 +60,7 @@ def follow_protocol(self): else: print("First-time reception of SESSION_OPEN frame.") if self.ctx.state_manager.check_if_running_arq_session(): - self.logger.warning( - "DISCARDING SESSION OPEN because of ongoing ARQ session ", frame=frame - ) + self.logger.warning("DISCARDING SESSION OPEN because of ongoing ARQ session ", frame=frame) return session = ARQSessionIRS(self.ctx, frame["origin"], session_id) self.ctx.state_manager.register_arq_irs_session(session) diff --git a/freedata_server/frame_handler_norm.py b/freedata_server/frame_handler_norm.py index 3c2c607b8..5f8c99e88 100644 --- a/freedata_server/frame_handler_norm.py +++ b/freedata_server/frame_handler_norm.py @@ -12,22 +12,22 @@ from norm.norm_transmission_irs import NormTransmissionIRS from norm.norm_transmission_iss import NormTransmissionISS -class NORMFrameHandler(frame_handler.FrameHandler): +class NORMFrameHandler(frame_handler.FrameHandler): def follow_protocol(self): - #self.logger.debug(f"[NORM] handling burst:{self.details}") + # self.logger.debug(f"[NORM] handling burst:{self.details}") - #origin = self.details["frame"]["origin"] - #print(origin) - frame = self.details['frame'] + # origin = self.details["frame"]["origin"] + # print(origin) + frame = self.details["frame"] - if frame['frame_type_int'] == FR.NORM_DATA.value: + if frame["frame_type_int"] == FR.NORM_DATA.value: NormTransmissionIRS(self.ctx, frame) - elif frame['frame_type_int'] == FR.NORM_REPAIR.value: + elif frame["frame_type_int"] == FR.NORM_REPAIR.value: NormTransmissionIRS(self.ctx, frame) - elif frame['frame_type_int'] == FR.NORM_NACK.value: + elif frame["frame_type_int"] == FR.NORM_NACK.value: try: print(str(frame["id"])) print(frame["id"].decode("utf-8")) @@ -41,13 +41,13 @@ def follow_protocol(self): print(broadcast) print("oring", broadcast["origin"]) print("domain", broadcast["domain"]) - #print("gridsquare", broadcast["gridsquare"]) - #print("payload_data", broadcast["payload_data"]["final"]) - #print("priority", broadcast["priority"]) - #print("message_type", broadcast["msg_type"]) - #print("frame:", frame) - #print("missing bursts:", frame["burst_numbers"]) - #NormTransmissionISS(self.ctx, broadcast["origin"], broadcast["domain"], broadcast["gridsquare"], data, priority=broadcast["priority"], message_type=broadcast["msg_type"], send_only_bursts=frame["burst_numbers"]).prepare_and_transmit() + # print("gridsquare", broadcast["gridsquare"]) + # print("payload_data", broadcast["payload_data"]["final"]) + # print("priority", broadcast["priority"]) + # print("message_type", broadcast["msg_type"]) + # print("frame:", frame) + # print("missing bursts:", frame["burst_numbers"]) + # NormTransmissionISS(self.ctx, broadcast["origin"], broadcast["domain"], broadcast["gridsquare"], data, priority=broadcast["priority"], message_type=broadcast["msg_type"], send_only_bursts=frame["burst_numbers"]).prepare_and_transmit() repair_bursts = NormTransmissionISS(self.ctx).create_repair(broadcast, frame["burst_numbers"]) NormTransmissionISS(self.ctx).transmit_bursts(repair_bursts) except Exception as e: diff --git a/freedata_server/frame_handler_ping.py b/freedata_server/frame_handler_ping.py index 7adf3808f..013fdc71a 100644 --- a/freedata_server/frame_handler_ping.py +++ b/freedata_server/frame_handler_ping.py @@ -44,7 +44,5 @@ def send_ack(self): frame's origin CRC and SNR, and transmits it using the modem. """ factory = data_frame_factory.DataFrameFactory(self.ctx) - ping_ack_frame = factory.build_ping_ack( - self.details["frame"]["origin_crc"], self.details["snr"] - ) + ping_ack_frame = factory.build_ping_ack(self.details["frame"]["origin_crc"], self.details["snr"]) self.transmit(ping_ack_frame) diff --git a/freedata_server/helpers.py b/freedata_server/helpers.py index d33e7b7ea..3c3fc2360 100644 --- a/freedata_server/helpers.py +++ b/freedata_server/helpers.py @@ -272,9 +272,7 @@ def callsign_to_bytes(callsign: str) -> bytes: # log.debug("[HLP] callsign_to_bytes: Error converting callsign to bytes:", e=err) pass except Exception as err: - log.debug( - "[HLP] callsign_to_bytes: Error converting callsign to bytes:", e=err, data=callsign - ) + log.debug("[HLP] callsign_to_bytes: Error converting callsign to bytes:", e=err, data=callsign) # Need this step to reduce the needed payload by the callsign # (stripping "-" out of the callsign) @@ -401,9 +399,7 @@ def check_callsign(callsign: str, crc_to_check: bytes, ssid_list): return [True, call_with_ssid.decode()] if get_crc_24(callsign).hex() == crc_to_check: - log.debug( - "[HLP] check_callsign matched:", call_without_ssid=callsign, checksum=crc_to_check - ) + log.debug("[HLP] check_callsign matched:", call_without_ssid=callsign, checksum=crc_to_check) return [True, callsign.decode()] log.debug( diff --git a/freedata_server/maidenhead.py b/freedata_server/maidenhead.py index 66b0ec9f9..1becd1a1f 100644 --- a/freedata_server/maidenhead.py +++ b/freedata_server/maidenhead.py @@ -96,8 +96,8 @@ def latlon_to_maidenhead(lat, lon, precision=6): lon += 180 lat += 90 - A = ord('A') - a = ord('a') + A = ord("A") + a = ord("a") lon_field = int(lon // 20) lat_field = int(lat // 10) diff --git a/freedata_server/message_p2p.py b/freedata_server/message_p2p.py index 3750bd520..f6f119dcd 100644 --- a/freedata_server/message_p2p.py +++ b/freedata_server/message_p2p.py @@ -47,9 +47,7 @@ def message_transmitted(ctx, data, statistics): payload_message_obj = MessageP2P.from_payload(decompressed_json_string) payload_message = MessageP2P.to_dict(payload_message_obj) # Todo we need to optimize this - WIP - DatabaseManagerMessages(ctx).update_message( - payload_message["id"], update_data={"status": "transmitted"} - ) + DatabaseManagerMessages(ctx).update_message(payload_message["id"], update_data={"status": "transmitted"}) DatabaseManagerMessages(ctx).update_message( payload_message["id"], update_data={"statistics": statistics}, @@ -74,9 +72,7 @@ def message_failed(ctx, data, statistics): payload_message_obj = MessageP2P.from_payload(decompressed_json_string) payload_message = MessageP2P.to_dict(payload_message_obj) # Todo we need to optimize this - WIP - DatabaseManagerMessages(ctx).update_message( - payload_message["id"], update_data={"status": "failed"} - ) + DatabaseManagerMessages(ctx).update_message(payload_message["id"], update_data={"status": "failed"}) DatabaseManagerMessages(ctx).update_message( payload_message["id"], update_data={"statistics": statistics}, @@ -94,9 +90,7 @@ class MessageP2P: or payloads, and generating unique message IDs. """ - def __init__( - self, id: str, origin: str, destination: str, body: str, attachments: list - ) -> None: + def __init__(self, id: str, origin: str, destination: str, body: str, attachments: list) -> None: """Initializes a new MessageP2P instance. Args: diff --git a/freedata_server/message_system_db_attachments.py b/freedata_server/message_system_db_attachments.py index 21c3f555b..f03c7f1fc 100644 --- a/freedata_server/message_system_db_attachments.py +++ b/freedata_server/message_system_db_attachments.py @@ -137,9 +137,7 @@ def get_attachment_by_sha512(self, hash_sha512): self.log(f"No attachment found with SHA-512 hash: {hash_sha512}") return None except Exception as e: - self.log( - f"Error fetching attachment with SHA-512 hash {hash_sha512}: {e}", isWarning=True - ) + self.log(f"Error fetching attachment with SHA-512 hash {hash_sha512}: {e}", isWarning=True) return None finally: session.remove() @@ -168,11 +166,7 @@ def delete_attachments_by_message_id(self, message_id): for link in links: # Count how many associations exist for this attachment. - link_count = ( - session.query(MessageAttachment) - .filter_by(attachment_id=link.attachment_id) - .count() - ) + link_count = session.query(MessageAttachment).filter_by(attachment_id=link.attachment_id).count() if link_count > 1: # More than one link exists, so only remove the association. session.delete(link) @@ -183,9 +177,7 @@ def delete_attachments_by_message_id(self, message_id): # Only one link exists, so delete both the association and the attachment. session.delete(link) session.delete(link.attachment) - self.log( - f"Deleted attachment '{link.attachment.name}' from message {message_id} (only link)." - ) + self.log(f"Deleted attachment '{link.attachment.name}' from message {message_id} (only link).") session.commit() return True @@ -217,9 +209,7 @@ def clean_orphaned_attachments(self): attachments = session.query(Attachment).all() for attachment in attachments: # Count the number of MessageAttachment links for this attachment. - link_count = ( - session.query(MessageAttachment).filter_by(attachment_id=attachment.id).count() - ) + link_count = session.query(MessageAttachment).filter_by(attachment_id=attachment.id).count() if link_count == 0: orphaned.append(attachment) diff --git a/freedata_server/message_system_db_beacon.py b/freedata_server/message_system_db_beacon.py index c72573396..a80d26b1a 100644 --- a/freedata_server/message_system_db_beacon.py +++ b/freedata_server/message_system_db_beacon.py @@ -46,9 +46,7 @@ def add_beacon(self, timestamp, callsign, snr, gridsquare): # Now, check and update the station's location with gridsquare if it has changed if station.location.get("gridsquare") != gridsquare: self.log(f"Updating location for {callsign}") - station.location["gridsquare"] = ( - gridsquare # Update directly without re-serialization - ) + station.location["gridsquare"] = gridsquare # Update directly without re-serialization session.flush() # Now, add the beacon @@ -94,9 +92,7 @@ def get_beacons_by_callsign(self, callsign): "id": beacon.id, "timestamp": beacon.timestamp.isoformat(), "snr": beacon.snr, - "gridsquare": station.location.get("gridsquare") - if station.location - else None, + "gridsquare": station.location.get("gridsquare") if station.location else None, } for beacon in beacons ] @@ -137,9 +133,7 @@ def get_all_beacons(self): for beacon in beacons_query: # Fetch the associated station for each beacon to get the 'gridsquare' information station = session.query(Station).filter_by(callsign=beacon.callsign).first() - gridsquare = ( - station.location.get("gridsquare") if station and station.location else None - ) + gridsquare = station.location.get("gridsquare") if station and station.location else None beacons_list.append({ "id": beacon.id, diff --git a/freedata_server/message_system_db_broadcasts.py b/freedata_server/message_system_db_broadcasts.py index 88c855bc8..73c83ebd8 100644 --- a/freedata_server/message_system_db_broadcasts.py +++ b/freedata_server/message_system_db_broadcasts.py @@ -7,9 +7,7 @@ import base64 - class DatabaseManagerBroadcasts(DatabaseManager): - def __init__(self, ctx): super().__init__(ctx) @@ -18,26 +16,26 @@ def __init__(self, ctx): self.stations_manager = DatabaseManagerStations(self.ctx) def process_broadcast_message( - self, - id: str, - origin: str, - timestamp: float, - burst_index: int, - burst_data: str, - total_bursts: int, - checksum: str, - repairing_callsigns: dict = None, - domain: str = None, - gridsquare: str = None, - msg_type: str = None, - received_at: float = None, - expires_at: float = None, - nexttransmission_at: float = None, - priority: int = 1, - is_read: bool = True, - direction: str = None, - status: str = "queued", - error_reason: str = None + self, + id: str, + origin: str, + timestamp: float, + burst_index: int, + burst_data: str, + total_bursts: int, + checksum: str, + repairing_callsigns: dict = None, + domain: str = None, + gridsquare: str = None, + msg_type: str = None, + received_at: float = None, + expires_at: float = None, + nexttransmission_at: float = None, + priority: int = 1, + is_read: bool = True, + direction: str = None, + status: str = "queued", + error_reason: str = None, ) -> bool: """ Handles both creation of a new broadcast message and addition of bursts. @@ -83,7 +81,7 @@ def process_broadcast_message( nexttransmission_at=nexttransmission_at, expires_at=expires_at, status_id=status_obj.id if status_obj else None, - error_reason=error_reason + error_reason=error_reason, ) session.add(msg) self.log(f"Created new broadcast message {id}") @@ -107,7 +105,6 @@ def process_broadcast_message( total = msg.total_bursts if total > 0 and len(received) == total and all(str(i) in received for i in range(1, total + 1)): - ordered = [received[str(i)] for i in range(1, total + 1)] final_bytes = b"".join(base64.b64decode(b64part) for b64part in ordered) @@ -128,7 +125,6 @@ def process_broadcast_message( status_obj = self.get_or_create_status(session, "received") msg.status_id = status_obj.id - self.log(f"Final payload assembled and verified for {id}") session.commit() @@ -173,7 +169,7 @@ def get_all_broadcasts_json(self) -> list: "expires_at": msg.expires_at if msg.expires_at else None, "nexttransmission_at": msg.nexttransmission_at if msg.nexttransmission_at else None, "status": msg.status.name if msg.status else None, - "error_reason": msg.error_reason + "error_reason": msg.error_reason, }) return result @@ -191,7 +187,8 @@ def get_first_queued_message(self): now_ts = datetime.now(timezone.utc).timestamp() message = ( - session.query(BroadcastMessage) + session + .query(BroadcastMessage) .filter( BroadcastMessage.direction == "transmit", BroadcastMessage.attempts < self.MAX_ATTEMPTS, @@ -219,7 +216,8 @@ def get_broadcast_domains_json(self) -> dict: session = self.get_thread_scoped_session() try: messages = ( - session.query(BroadcastMessage) + session + .query(BroadcastMessage) .filter(BroadcastMessage.domain.isnot(None)) .order_by(BroadcastMessage.timestamp.desc()) .all() @@ -289,7 +287,7 @@ def get_broadcasts_per_domain_json(self, domain: str = None) -> dict: "error_reason": msg.error_reason, "received_at": msg.received_at if msg.received_at else None, "nexttransmission_at": msg.nexttransmission_at if msg.nexttransmission_at else None, - "expires_at": msg.expires_at if msg.expires_at else None + "expires_at": msg.expires_at if msg.expires_at else None, }) return result @@ -311,12 +309,7 @@ def delete_broadcast_message_or_domain(self, id) -> dict: session.commit() self.log(f"Deleted broadcast message {id}") self.ctx.event_manager.freedata_message_db_change(message_id=id) - return { - "status": "success", - "deleted": 1, - "type": "message", - "id": id - } + return {"status": "success", "deleted": 1, "type": "message", "id": id} messages = session.query(BroadcastMessage).filter_by(domain=id).all() if messages: @@ -326,25 +319,14 @@ def delete_broadcast_message_or_domain(self, id) -> dict: session.commit() self.log(f"Deleted {count} messages from domain '{id}'") self.ctx.event_manager.freedata_message_db_change(message_id=id) - return { - "status": "success", - "deleted": count, - "type": "domain", - "domain": id - } + return {"status": "success", "deleted": count, "type": "domain", "domain": id} - return { - "status": "error", - "message": f"Neither broadcast message ID '{id}' nor domain found." - } + return {"status": "error", "message": f"Neither broadcast message ID '{id}' nor domain found."} except Exception as e: session.rollback() self.log(f"Error deleting broadcast message or domain '{id}': {e}", isWarning=True) - return { - "status": "error", - "message": str(e) - } + return {"status": "error", "message": str(e)} finally: session.remove() @@ -358,12 +340,13 @@ def check_missing_bursts(self): print(now) print(one_minute_ago_ts) messages = ( - session.query(BroadcastMessage) + session + .query(BroadcastMessage) .filter( BroadcastMessage.direction == "receive", BroadcastMessage.received_at < one_minute_ago_ts, BroadcastMessage.total_bursts > 0, - BroadcastMessage.expires_at > now + BroadcastMessage.expires_at > now, ) .order_by(BroadcastMessage.received_at.asc()) .all() @@ -387,7 +370,6 @@ def check_missing_bursts(self): dt = datetime.fromtimestamp(msg.nexttransmission_at, timezone.utc) self.log(f"Skip {msg.id}: wait until {int(msg.nexttransmission_at)} ({dt.isoformat()})") - continue # Max attempts @@ -398,10 +380,7 @@ def check_missing_bursts(self): bursts = msg.payload_data["bursts"] total = msg.total_bursts - missing = [ - i for i in range(1, total + 1) - if str(i) not in bursts - ] + missing = [i for i in range(1, total + 1) if str(i) not in bursts] if missing: return { @@ -411,7 +390,7 @@ def check_missing_bursts(self): "missing_bursts": missing, "total_bursts": total, "received_bursts": list(bursts.keys()), - "received_at": msg.received_at if msg.received_at else None + "received_at": msg.received_at if msg.received_at else None, } return None @@ -454,7 +433,7 @@ def get_broadcast_per_id(self, id, get_object=False): "nexttransmission_at": msg.nexttransmission_at if msg.nexttransmission_at else None, "status": msg.status.name if msg.status else None, "error_reason": msg.error_reason, - "attempts": msg.attempts + "attempts": msg.attempts, } except Exception as e: @@ -480,9 +459,6 @@ def increment_attempts(self, message_id: str): finally: session.remove() - - - def increment_attempts_and_update_next_transmission(self, message_id: str): session = self.get_thread_scoped_session() try: @@ -513,7 +489,8 @@ def increment_attempts_and_update_next_transmission(self, message_id: str): session.commit() self.log( - f"Incremented attempts for {message_id} to {msg.attempts}, next transmission at {msg.nexttransmission_at}") + f"Incremented attempts for {message_id} to {msg.attempts}, next transmission at {msg.nexttransmission_at}" + ) except Exception as e: session.rollback() @@ -529,7 +506,8 @@ def mark_domain_as_read(self, domain: str) -> int: session = self.get_thread_scoped_session() try: msgs = ( - session.query(BroadcastMessage) + session + .query(BroadcastMessage) .filter( BroadcastMessage.domain == domain, BroadcastMessage.is_read.is_(False), @@ -551,4 +529,3 @@ def mark_domain_as_read(self, domain: str) -> int: return 0 finally: session.remove() - diff --git a/freedata_server/message_system_db_manager.py b/freedata_server/message_system_db_manager.py index 634bd593a..12dcc5f27 100644 --- a/freedata_server/message_system_db_manager.py +++ b/freedata_server/message_system_db_manager.py @@ -75,7 +75,8 @@ def initialize_default_values(self): "aborted", "queued", "receiving", - "assembling" ] + "assembling", + ] # Add default statuses if they don't exist for status_name in statuses: @@ -115,18 +116,14 @@ def database_repair_and_cleanup(self): transmitting_status = session.query(Status).filter_by(name="transmitting").first() if transmitting_status: # Check if any messages have the status "transmitting" and update them to "failed" - messages_to_update = ( - session.query(P2PMessage).filter_by(status_id=transmitting_status.id).all() - ) + messages_to_update = session.query(P2PMessage).filter_by(status_id=transmitting_status.id).all() for message in messages_to_update: message.status_id = failed_status.id session.commit() len_repaired_message = len(messages_to_update) if len_repaired_message > 0: - self.log( - f"Repaired {len_repaired_message} messages ('transmitting' to 'failed')" - ) + self.log(f"Repaired {len_repaired_message} messages ('transmitting' to 'failed')") # Vacuum the database to reclaim space session.execute(text("VACUUM")) @@ -366,9 +363,7 @@ def update_tables_schema(self): inspector = inspect(self.engine) existing_tables = inspector.get_table_names() - new_tables = [ - table for table in Base.metadata.sorted_tables if table.name not in existing_tables - ] + new_tables = [table for table in Base.metadata.sorted_tables if table.name not in existing_tables] if new_tables: table_names = ", ".join(table.name for table in new_tables) diff --git a/freedata_server/message_system_db_messages.py b/freedata_server/message_system_db_messages.py index b8850f453..e12e0ffe3 100644 --- a/freedata_server/message_system_db_messages.py +++ b/freedata_server/message_system_db_messages.py @@ -59,9 +59,7 @@ def add_message( try: # Create and add the origin and destination Stations origin = self.stations_manager.get_or_create_station(message_data["origin"], session) - destination = self.stations_manager.get_or_create_station( - message_data["destination"], session - ) + destination = self.stations_manager.get_or_create_station(message_data["destination"], session) # Create and add Status if provided if status: @@ -266,14 +264,10 @@ def get_message_by_id_adif(self, message_id): # Parse the timestamp for QSO date and time, strip fractional seconds timestamp_clean = timestamp.split(".")[0] # Remove fractional seconds - qso_date = timestamp_clean.split("T")[0].replace( - "-", "" - ) # Extract the date part and remove hyphens + qso_date = timestamp_clean.split("T")[0].replace("-", "") # Extract the date part and remove hyphens # Extract the time and format it as HHMMSS - time_on = datetime.strptime(timestamp_clean.split("T")[1], "%H:%M:%S").strftime( - "%H%M%S" - ) + time_on = datetime.strptime(timestamp_clean.split("T")[1], "%H:%M:%S").strftime("%H%M%S") # Calculate TIME_OFF by adding duration to TIME_ON duration = statistics.get("duration", 0.0) # Duration in seconds @@ -290,11 +284,7 @@ def get_message_by_id_adif(self, message_id): # Gridsquare handling print(origin_info) - if ( - origin_info - and "location" in origin_info - and origin_info["location"] is not None - ): + if origin_info and "location" in origin_info and origin_info["location"] is not None: print(origin_info["location"]) grid = origin_info["location"].get("gridsquare", "") else: @@ -462,10 +452,7 @@ def get_first_queued_message(self): if queued_status: # Query for the first (oldest) message with status "queued" message = ( - session.query(P2PMessage) - .filter_by(status=queued_status) - .order_by(P2PMessage.timestamp) - .first() + session.query(P2PMessage).filter_by(status=queued_status).order_by(P2PMessage.timestamp).first() ) if message: self.log(f"Found queued message with ID {message.id}") @@ -547,7 +534,8 @@ def set_message_to_queued_for_callsign(self, callsign): # Query for messages with the specified callsign, 'failed' status, and fewer than 10 attempts message = ( - session.query(P2PMessage) + session + .query(P2PMessage) .filter(P2PMessage.destination_callsign == callsign) .filter(P2PMessage.status_id == failed_status.id) .filter(P2PMessage.attempt < 10) diff --git a/freedata_server/message_system_db_model.py b/freedata_server/message_system_db_model.py index e488b37cb..bf044be8a 100644 --- a/freedata_server/message_system_db_model.py +++ b/freedata_server/message_system_db_model.py @@ -16,9 +16,7 @@ class MessageAttachment(Base): __tablename__ = "message_attachment" message_id = Column(String, ForeignKey("p2p_message.id", ondelete="CASCADE"), primary_key=True) - attachment_id = Column( - Integer, ForeignKey("attachment.id", ondelete="CASCADE"), primary_key=True - ) + attachment_id = Column(Integer, ForeignKey("attachment.id", ondelete="CASCADE"), primary_key=True) message = relationship("P2PMessage", back_populates="message_attachments") attachment = relationship("Attachment", back_populates="message_attachments") @@ -33,9 +31,7 @@ class Config(Base): """ __tablename__ = "config" - db_variable = Column( - String, primary_key=True - ) # Unique identifier for the configuration setting + db_variable = Column(String, primary_key=True) # Unique identifier for the configuration setting db_version = Column(String) def to_dict(self): @@ -128,9 +124,7 @@ class P2PMessage(Base): via_callsign = Column(String, ForeignKey("station.callsign"), nullable=True) destination_callsign = Column(String, ForeignKey("station.callsign")) body = Column(String, nullable=True) - message_attachments = relationship( - "MessageAttachment", back_populates="message", cascade="all, delete-orphan" - ) + message_attachments = relationship("MessageAttachment", back_populates="message", cascade="all, delete-orphan") attempt = Column(Integer, default=0) timestamp = Column(DateTime) status_id = Column(Integer, ForeignKey("status.id"), nullable=True) @@ -220,11 +214,12 @@ def to_dict(self): from sqlalchemy.orm import relationship from datetime import datetime, timezone + class BroadcastMessage(Base): - __tablename__ = 'broadcast_messages' + __tablename__ = "broadcast_messages" id = Column(String, primary_key=True) - origin = Column(String, ForeignKey('station.callsign')) + origin = Column(String, ForeignKey("station.callsign")) timestamp = Column(Float, default=lambda: datetime.now(timezone.utc)) repairing_callsigns = Column(JSON, nullable=True) domain = Column(String) @@ -242,36 +237,34 @@ class BroadcastMessage(Base): nexttransmission_at = Column(Float, default=lambda: datetime.now(timezone.utc)) expires_at = Column(Float, default=lambda: datetime.now(timezone.utc)) - status_id = Column(Integer, ForeignKey('status.id'), nullable=True) - status = relationship('Status', backref='broadcast_messages') + status_id = Column(Integer, ForeignKey("status.id"), nullable=True) + status = relationship("Status", backref="broadcast_messages") error_reason = Column(String, nullable=True) attempts = Column(Integer, default=0) - __table_args__ = ( - Index('idx_broadcast_domain_received', 'domain', 'received_at'), - ) + __table_args__ = (Index("idx_broadcast_domain_received", "domain", "received_at"),) def to_dict(self): return { - 'id': self.id, - 'origin': self.origin, - 'timestamp': self.timestamp, - 'repairing_callsigns': self.repairing_callsigns, - 'domain': self.domain, - 'gridsquare': self.gridsquare, - 'frequency': self.frequency, - 'priority': self.priority, - 'is_read': self.is_read, - 'direction': self.direction, - 'payload_size': self.payload_size, - 'payload_data': self.payload_data, - 'msg_type': self.msg_type, - 'total_bursts': self.total_bursts, - 'checksum': self.checksum, - 'received_at': self.received_at if self.received_at else None, - 'expires_at': self.expires_at if self.expires_at else None, - 'nexttransmission_at': self.nexttransmission_at if self.nexttransmission_at else None, - 'status': self.status.name if self.status else None, - 'error_reason': self.error_reason, - 'attempts':self.attempts + "id": self.id, + "origin": self.origin, + "timestamp": self.timestamp, + "repairing_callsigns": self.repairing_callsigns, + "domain": self.domain, + "gridsquare": self.gridsquare, + "frequency": self.frequency, + "priority": self.priority, + "is_read": self.is_read, + "direction": self.direction, + "payload_size": self.payload_size, + "payload_data": self.payload_data, + "msg_type": self.msg_type, + "total_bursts": self.total_bursts, + "checksum": self.checksum, + "received_at": self.received_at if self.received_at else None, + "expires_at": self.expires_at if self.expires_at else None, + "nexttransmission_at": self.nexttransmission_at if self.nexttransmission_at else None, + "status": self.status.name if self.status else None, + "error_reason": self.error_reason, + "attempts": self.attempts, } diff --git a/freedata_server/message_system_db_station.py b/freedata_server/message_system_db_station.py index 79105091c..c1a631516 100644 --- a/freedata_server/message_system_db_station.py +++ b/freedata_server/message_system_db_station.py @@ -93,9 +93,7 @@ def update_station_location(self, callsign, gridsquare): # Update the station's location with gridsquare if it has changed if station.location.get("gridsquare") != gridsquare: self.log(f"Updating location for {callsign}") - station.location["gridsquare"] = ( - gridsquare # Update directly without re-serialization - ) + station.location["gridsquare"] = gridsquare # Update directly without re-serialization session.flush() else: self.log(f"No changes needed for {callsign}'s location") @@ -107,9 +105,7 @@ def update_station_location(self, callsign, gridsquare): return False except SQLAlchemyError as e: session.rollback() - self.log( - f"Failed to update location for station {callsign} with error: {e}", isError=True - ) + self.log(f"Failed to update location for station {callsign} with error: {e}", isError=True) return False finally: session.remove() diff --git a/freedata_server/modem.py b/freedata_server/modem.py index 6889154e9..2f203478f 100644 --- a/freedata_server/modem.py +++ b/freedata_server/modem.py @@ -246,9 +246,7 @@ def transmit_morse(self, repeats, repeat_delay, frames): # if we're transmitting FreeDATA signals, reset channel busy state self.log.debug("[MDM] TRANSMIT", mode="MORSE") start_of_transmission = time.time() - txbuffer_out = cw.MorseCodePlayer().text_to_signal( - self.ctx.config_manager.config["STATION"].get("mycall") - ) + txbuffer_out = cw.MorseCodePlayer().text_to_signal(self.ctx.config_manager.config["STATION"].get("mycall")) txbuffer_out = audio.normalize_audio(txbuffer_out) # transmit audio self.enqueue_audio_out(txbuffer_out) @@ -317,9 +315,7 @@ def enqueue_audio_out(self, audio_48k) -> None: if self.ctx.radio_manager: self.ctx.radio_manager.set_ptt(True) else: - self.log.warning( - "Radio manager not yet initialized...should happen soon, some errors might occur" - ) # + self.log.warning("Radio manager not yet initialized...should happen soon, some errors might occur") # self.ctx.event_manager.send_ptt_change(True) @@ -342,17 +338,15 @@ def enqueue_audio_out(self, audio_48k) -> None: if self.ctx.radio_manager: self.ctx.radio_manager.set_ptt(False) else: - self.log.warning( - "Radio manager not yet initialized...should happen soon, some errors might occur" - ) # + self.log.warning("Radio manager not yet initialized...should happen soon, some errors might occur") # self.ctx.event_manager.send_ptt_change(False) return def enqueue_streaming_audio_chunks(self, audio_block, queue): - #total_samples = len(audio_block) - #for start in range(0, total_samples, self.AUDIO_STREAMING_CHUNK_SIZE): + # total_samples = len(audio_block) + # for start in range(0, total_samples, self.AUDIO_STREAMING_CHUNK_SIZE): # end = start + self.AUDIO_STREAMING_CHUNK_SIZE # chunk = audio_block[start:end] # queue.put(chunk.tobytes()) @@ -360,14 +354,12 @@ def enqueue_streaming_audio_chunks(self, audio_block, queue): block_size = self.AUDIO_STREAMING_CHUNK_SIZE pad_length = -len(audio_block) % block_size - padded_data = np.pad(audio_block, (0, pad_length), mode='constant') + padded_data = np.pad(audio_block, (0, pad_length), mode="constant") sliced_audio_data = padded_data.reshape(-1, block_size) # add each block to audio out queue for block in sliced_audio_data: queue.put(block) - - def sd_output_audio_callback(self, outdata: np.ndarray, frames: int, time, status) -> None: """Callback function for the audio output stream. @@ -391,8 +383,6 @@ def sd_output_audio_callback(self, outdata: np.ndarray, frames: int, time, statu audio.calculate_fft(audio_8k, self.ctx.modem_fft, self.ctx.state_manager) outdata[:] = chunk.reshape(outdata.shape) - - else: # reset transmitting state only, if we are not actively processing audio # for avoiding a ptt toggle state bug @@ -431,15 +421,13 @@ def sd_input_audio_callback(self, indata: np.ndarray, frames: int, time, status) self.enqueue_streaming_audio_chunks(audio_8k, self.ctx.audio_rx_queue) - if self.ctx.config_manager.config['AUDIO'].get('rx_auto_audio_level'): + if self.ctx.config_manager.config["AUDIO"].get("rx_auto_audio_level"): audio_8k = audio.normalize_audio(audio_8k) audio_8k_level_adjusted = audio.set_audio_volume(audio_8k, self.rx_audio_level) if not self.ctx.state_manager.isTransmitting(): - audio.calculate_fft( - audio_8k_level_adjusted, self.ctx.modem_fft, self.ctx.state_manager - ) + audio.calculate_fft(audio_8k_level_adjusted, self.ctx.modem_fft, self.ctx.state_manager) length_audio_8k_level_adjusted = len(audio_8k_level_adjusted) # Avoid buffer overflow by filling only if buffer for @@ -453,9 +441,7 @@ def sd_input_audio_callback(self, indata: np.ndarray, frames: int, time, status) if audiobuffer: if (audiobuffer.nbuffer + length_audio_8k_level_adjusted) > audiobuffer.size: self.demodulator.buffer_overflow_counter[index] += 1 - self.ctx.event_manager.send_buffer_overflow( - self.demodulator.buffer_overflow_counter - ) + self.ctx.event_manager.send_buffer_overflow(self.demodulator.buffer_overflow_counter) elif decode: audiobuffer.push(audio_8k_level_adjusted) except Exception as e: diff --git a/freedata_server/modem_frametypes.py b/freedata_server/modem_frametypes.py index b36ba1c0f..9addad03f 100644 --- a/freedata_server/modem_frametypes.py +++ b/freedata_server/modem_frametypes.py @@ -22,9 +22,9 @@ class FRAME_TYPE(Enum): P2P_CONNECTION_PAYLOAD_ACK = 35 P2P_CONNECTION_DISCONNECT = 36 P2P_CONNECTION_DISCONNECT_ACK = 37 - #MESH_BROADCAST = 100 - #MESH_SIGNALLING_PING = 101 - #MESH_SIGNALLING_PING_ACK = 102 + # MESH_BROADCAST = 100 + # MESH_SIGNALLING_PING = 101 + # MESH_SIGNALLING_PING_ACK = 102 NORM_DATA = 100 NORM_NACK = 101 NORM_REPAIR = 102 diff --git a/freedata_server/norm/norm_transmission.py b/freedata_server/norm/norm_transmission.py index 89618e265..97e186742 100644 --- a/freedata_server/norm/norm_transmission.py +++ b/freedata_server/norm/norm_transmission.py @@ -8,21 +8,22 @@ from freedata_server.codec2 import FREEDV_MODE - class NORMMsgType(IntEnum): UNDEFINED = 0 - MESSAGE = 1 # Generic text/data message - POSITION = 2 # GPS or grid locator info - SITREP = 3 # Situation report - METAR = 4 # METAR Message + MESSAGE = 1 # Generic text/data message + POSITION = 2 # GPS or grid locator info + SITREP = 3 # Situation report + METAR = 4 # METAR Message + class NORMMsgPriority(IntEnum): - LOW = 0 - NORMAL = 1 - HIGH = 2 - CRITICAL = 3 - ALERT = 4 - EMERGENCY = 5 + LOW = 0 + NORMAL = 1 + HIGH = 2 + CRITICAL = 3 + ALERT = 4 + EMERGENCY = 5 + class NormTransmission: def __init__(self, ctx): @@ -57,7 +58,9 @@ def set_state(self, state): if self.state == state: self.log(f"{type(self).__name__} state {self.state.name} unchanged.") else: - self.log(f"{type(self).__name__} state change from {self.state.name} to {state.name} at {self.last_state_change_timestamp}") + self.log( + f"{type(self).__name__} state change from {self.state.name} to {state.name} at {self.last_state_change_timestamp}" + ) self.state = state def on_frame_received(self, frame): @@ -72,14 +75,15 @@ def on_frame_received(self, frame): """ self.event_frame_received.set() self.log(f"Received {frame['frame_type']}") - frame_type = frame['frame_type_int'] + frame_type = frame["frame_type_int"] if self.state in self.STATE_TRANSITION and frame_type in self.STATE_TRANSITION[self.state]: action_name = self.STATE_TRANSITION[self.state][frame_type] received_data, type_byte = getattr(self, action_name)(frame) if isinstance(received_data, bytearray) and isinstance(type_byte, int): - self.arq_data_type_handler.dispatch(type_byte, received_data, - self.update_histograms(len(received_data), len(received_data))) + self.arq_data_type_handler.dispatch( + type_byte, received_data, self.update_histograms(len(received_data), len(received_data)) + ) return self.log(f"Ignoring unknown transition from state {self.state.name} with frame {frame['frame_type']}") @@ -147,7 +151,6 @@ def decode_burst_info(self, burst_info): burst_total = burst_info & 0x0F return burst_number, burst_total - def create_broadcast_id(self, timestamp: int, domain: str, checksum: str, length: int = 10) -> str: """ Creates a deterministic broadcast ID using BLAKE2b. @@ -166,5 +169,5 @@ def create_broadcast_id(self, timestamp: int, domain: str, checksum: str, length return f"{digest}" def create_and_transmit_nack_burst(self, origin, id, burst_numbers): - burst = self.frame_factory.build_norm_nack(origin, id, burst_numbers) - self.ctx.rf_modem.transmit(FREEDV_MODE.datac4, 1, 200, burst) \ No newline at end of file + burst = self.frame_factory.build_norm_nack(origin, id, burst_numbers) + self.ctx.rf_modem.transmit(FREEDV_MODE.datac4, 1, 200, burst) diff --git a/freedata_server/norm/norm_transmission_irs.py b/freedata_server/norm/norm_transmission_irs.py index deeb370de..1a01dd499 100644 --- a/freedata_server/norm/norm_transmission_irs.py +++ b/freedata_server/norm/norm_transmission_irs.py @@ -4,6 +4,7 @@ import base64 from datetime import datetime, timezone, timedelta + class NormTransmissionIRS(NormTransmission): MAX_PAYLOAD_SIZE = 26 @@ -15,22 +16,20 @@ def __init__(self, ctx, frame): print("burst:", frame) - is_last, msg_type, priority = self.decode_flags(frame["flag"]) burst_number, total_bursts = self.decode_burst_info(frame["burst_info"]) payload_size = frame["payload_size"] payload_data = frame["payload_data"] - if total_bursts == 1: - payload_data = payload_data[:self.MAX_PAYLOAD_SIZE] + payload_data = payload_data[: self.MAX_PAYLOAD_SIZE] - if is_last:# + if is_last: # end = self.MAX_PAYLOAD_SIZE - ((total_bursts * self.MAX_PAYLOAD_SIZE) - payload_size) print(end) payload_data = payload_data[:end] - #payload_data = payload_data[:payload_size] + # payload_data = payload_data[:payload_size] self.origin = frame["origin"] self.domain = frame["domain"] @@ -51,7 +50,6 @@ def __init__(self, ctx, frame): print("checksum", self.checksum) print("timestamp", self.timestamp) - payload_b64 = base64.b64encode(payload_data).decode("ascii") print("payload_b64", payload_b64) @@ -81,9 +79,8 @@ def __init__(self, ctx, frame): nexttransmission_at=datetime.now(timezone.utc).timestamp(), is_read=False, direction="receive", - status="assembling" + status="assembling", ) if not success: print("Failed to process burst in database.") - diff --git a/freedata_server/norm/norm_transmission_iss.py b/freedata_server/norm/norm_transmission_iss.py index 86754dd34..d955a5ac3 100644 --- a/freedata_server/norm/norm_transmission_iss.py +++ b/freedata_server/norm/norm_transmission_iss.py @@ -12,6 +12,7 @@ import threading import numpy as np + class NORM_ISS_State(Enum): NEW = 0 TRANSMITTING = 1 @@ -20,6 +21,7 @@ class NORM_ISS_State(Enum): ABORTING = 4 ABORTED = 5 + class NormTransmissionISS(NormTransmission): MAX_PAYLOAD_SIZE = 26 @@ -33,7 +35,9 @@ def __init__(self, ctx): self.state = NORM_ISS_State.NEW self.log("Initialized") - def prepare_and_transmit_data(self, origin, domain, gridsquare, data, priority=NORMMsgPriority.NORMAL, message_type=NORMMsgType.UNDEFINED): + def prepare_and_transmit_data( + self, origin, domain, gridsquare, data, priority=NORMMsgPriority.NORMAL, message_type=NORMMsgType.UNDEFINED + ): self.origin = origin self.domain = domain self.gridsquare = gridsquare @@ -59,13 +63,14 @@ def create_data(self): if total_bursts <= 0: self.log( f"Invalid burst calculation (data length: {len(full_data)}, max payload: {self.MAX_PAYLOAD_SIZE})", - isWarning=True) + isWarning=True, + ) raise ValueError("Invalid burst calculation") bursts = [] for burst_number in range(1, total_bursts + 1): offset = (burst_number - 1) * self.MAX_PAYLOAD_SIZE - payload = full_data[offset: offset + self.MAX_PAYLOAD_SIZE] + payload = full_data[offset : offset + self.MAX_PAYLOAD_SIZE] if not payload: self.log(f"Empty payload at burst {burst_number}", isWarning=True) @@ -73,7 +78,7 @@ def create_data(self): burst_info = self.encode_burst_info(burst_number, total_bursts) checksum = freedata_server.helpers.get_crc_24(full_data) - is_last = (burst_number == total_bursts) + is_last = burst_number == total_bursts print("message type", self.message_type) print("priority", self.priority) print("is_last", is_last) @@ -87,11 +92,12 @@ def create_data(self): payload_size=len(full_data), payload_data=payload, flag=flags, - checksum=checksum + checksum=checksum, ) self.log( - f"Burst {burst_number}/{total_bursts} created (offset={offset}, payload_size={len(payload)}, is_last={is_last})") + f"Burst {burst_number}/{total_bursts} created (offset={offset}, payload_size={len(payload)}, is_last={is_last})" + ) bursts.append(burst_frame) @@ -128,14 +134,14 @@ def create_repair(self, db_msg_obj: dict, burst_numbers: list[int]): raise ValueError(f"Invalid burst number {burst_number}") offset = (burst_number - 1) * self.MAX_PAYLOAD_SIZE - payload = data[offset: offset + self.MAX_PAYLOAD_SIZE] + payload = data[offset : offset + self.MAX_PAYLOAD_SIZE] if not payload: self.log(f"Empty payload for burst {burst_number}", isWarning=True) raise ValueError(f"Empty payload for burst {burst_number}") burst_info = self.encode_burst_info(burst_number, total_bursts) - is_last = (burst_number == total_bursts) + is_last = burst_number == total_bursts flags = self.encode_flags(message_type, priority, is_last) burst_frame = self.frame_factory.build_norm_repair( @@ -147,11 +153,12 @@ def create_repair(self, db_msg_obj: dict, burst_numbers: list[int]): payload_size=len(data), payload_data=payload, flag=flags, - checksum=checksum + checksum=checksum, ) self.log( - f"Repair burst {burst_number}/{total_bursts} created (offset={offset}, payload_size={len(payload)}, is_last={is_last})") + f"Repair burst {burst_number}/{total_bursts} created (offset={offset}, payload_size={len(payload)}, is_last={is_last})" + ) repair_bursts.append(burst_frame) self.log(f"All repair bursts created successfully (count={len(repair_bursts)})") @@ -198,7 +205,7 @@ def add_to_database(self): for burst_index in range(1, total_bursts + 1): offset = (burst_index - 1) * self.MAX_PAYLOAD_SIZE - payload_data = self.data[offset: offset + self.MAX_PAYLOAD_SIZE] + payload_data = self.data[offset : offset + self.MAX_PAYLOAD_SIZE] if not payload_data: self.log(f"Empty payload at burst index {burst_index}", isWarning=True) continue @@ -210,7 +217,6 @@ def add_to_database(self): expires_at = datetime.now(timezone.utc) + timedelta(days=1) expires_at = expires_at.timestamp() - db.process_broadcast_message( id=broadcast_id, origin=self.origin, @@ -229,7 +235,7 @@ def add_to_database(self): expires_at=expires_at, is_read=True, direction="transmit", - status="assembling" + status="assembling", ) self.log(f"Stored burst {burst_index}/{total_bursts} in database (size={len(payload_data)})") @@ -251,6 +257,5 @@ def retransmit_data(self, msg): self.timestamp = int(msg.timestamp) bursts = self.create_data() - #self.add_to_database() + # self.add_to_database() self.transmit_bursts(bursts) - diff --git a/freedata_server/norm/norm_transmission_resend.py b/freedata_server/norm/norm_transmission_resend.py index cba14075d..a4c5339dc 100644 --- a/freedata_server/norm/norm_transmission_resend.py +++ b/freedata_server/norm/norm_transmission_resend.py @@ -1 +1 @@ -# file for "healing requested transmissions... \ No newline at end of file +# file for "healing requested transmissions... diff --git a/freedata_server/p2p_connection.py b/freedata_server/p2p_connection.py index bbf05a49f..7e4689955 100644 --- a/freedata_server/p2p_connection.py +++ b/freedata_server/p2p_connection.py @@ -129,9 +129,7 @@ def __init__(self, ctx, origin: str, destination: str): self.flag_has_data = False self.flag_announce_arq = False - self.transmission_in_progress = ( - False # indicatews, if we are waiting for an ongoing transmission - ) + self.transmission_in_progress = False # indicatews, if we are waiting for an ongoing transmission self.running_arq_session = None def start_data_processing_worker(self): @@ -141,17 +139,13 @@ def data_processing_worker(): last_isalive = 0 while True: now = time.time() - if ( - now > self.last_data_timestamp + self.ENTIRE_CONNECTION_TIMEOUT - and self.state - not in [ - States.DISCONNECTING, - States.DISCONNECTED, - States.ARQ_SESSION, - States.FAILED, - States.PAYLOAD_TRANSMISSION, - ] - ): + if now > self.last_data_timestamp + self.ENTIRE_CONNECTION_TIMEOUT and self.state not in [ + States.DISCONNECTING, + States.DISCONNECTED, + States.ARQ_SESSION, + States.FAILED, + States.PAYLOAD_TRANSMISSION, + ]: self.disconnect() return @@ -224,9 +218,7 @@ def on_frame_received(self, frame): _response = getattr(self, action_name)(frame) return - self.log( - f"Ignoring unknown transition from state {self.state.name} with frame {frame['frame_type']}" - ) + self.log(f"Ignoring unknown transition from state {self.state.name} with frame {frame['frame_type']}") def transmit_frame(self, frame: bytearray, mode="auto"): if mode in ["auto"]: @@ -272,9 +264,7 @@ def transmit_and_wait_irs(self, frame, timeout, mode): # self.transmission_failed() def launch_twr_irs(self, frame, timeout, mode): - thread_wait = threading.Thread( - target=self.transmit_and_wait_irs, args=[frame, timeout, mode], daemon=True - ) + thread_wait = threading.Thread(target=self.transmit_and_wait_irs, args=[frame, timeout, mode], daemon=True) thread_wait.start() def connect(self): @@ -328,9 +318,7 @@ def connected_irs(self, frame): session_open_frame = self.frame_factory.build_p2p_connection_connect_ack( self.destination, self.origin, self.session_id ) - self.launch_twr_irs( - session_open_frame, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling - ) + self.launch_twr_irs(session_open_frame, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling) def session_failed(self): self.set_state(States.FAILED) @@ -347,9 +335,7 @@ def process_data_queue(self, frame=None): self.is_Master = True buffer_size = self.get_tx_queue_buffer_size() - self.ctx.socket_interface_manager.command_server.command_handler.socket_respond_buffer_size( - buffer_size - ) + self.ctx.socket_interface_manager.command_server.command_handler.socket_respond_buffer_size(buffer_size) raw_data = self.p2p_data_tx_queue.get() sequence_id = random.randint(0, 255) @@ -391,9 +377,7 @@ def received_data(self, frame): self.log("received data...") ack_data = self.frame_factory.build_p2p_connection_payload_ack(self.session_id, 0) - self.launch_twr_irs( - ack_data, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling_ack - ) + self.launch_twr_irs(ack_data, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling_ack) if not frame["flag"]["HAS_DATA"]: self.set_state(States.CONNECTED) @@ -410,12 +394,8 @@ def received_data(self, frame): if self.ctx.socket_interface_manager and hasattr( self.ctx.socket_interface_manager.data_server, "data_handler" ): - self.log( - f"sending {len(received_data)} bytes to data socket client: {received_data}" - ) - self.ctx.socket_interface_manager.data_server.data_handler.send_data_to_client( - received_data - ) + self.log(f"sending {len(received_data)} bytes to data socket client: {received_data}") + self.ctx.socket_interface_manager.data_server.data_handler.send_data_to_client(received_data) except Exception as e: self.log(f"Error sending data to socket: {e}") @@ -430,9 +410,7 @@ def transmitted_data(self, frame): self.set_state(States.PAYLOAD_SENT) buffer_size = self.get_tx_queue_buffer_size() - self.ctx.socket_interface_manager.command_server.command_handler.socket_respond_buffer_size( - buffer_size - ) + self.ctx.socket_interface_manager.command_server.command_handler.socket_respond_buffer_size(buffer_size) def transmit_heartbeat(self, has_data=False, announce_arq=False): # heartbeats will be transmit by ISS only, therefore only IRS can reveice heartbeat ack @@ -458,9 +436,7 @@ def transmit_heartbeat_ack(self): flag_has_data=self.flag_has_data, flag_announce_arq=self.flag_announce_arq, ) - self.launch_twr_irs( - heartbeat_ack, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling - ) + self.launch_twr_irs(heartbeat_ack, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling) def received_heartbeat(self, frame): # we don't accept heartbeats as ISS @@ -480,9 +456,7 @@ def received_heartbeat(self, frame): else: if self.p2p_data_tx_queue.empty(): - self.log( - "Opposite station's data buffer is empty as well -- We won't become data master now" - ) + self.log("Opposite station's data buffer is empty as well -- We won't become data master now") self.is_Master = False self.flag_has_data = False else: @@ -562,12 +536,8 @@ def received_disconnect(self, frame): if self.ctx.socket_interface_manager: self.ctx.socket_interface_manager.command_server.command_handler.socket_respond_disconnected() self.is_ISS = False - disconnect_ack_frame = self.frame_factory.build_p2p_connection_disconnect_ack( - self.session_id - ) - self.launch_twr_irs( - disconnect_ack_frame, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling - ) + disconnect_ack_frame = self.frame_factory.build_p2p_connection_disconnect_ack(self.session_id) + self.launch_twr_irs(disconnect_ack_frame, self.ENTIRE_CONNECTION_TIMEOUT, mode=FREEDV_MODE.signalling) def received_disconnect_ack(self, frame): self.log("DISCONNECTED...............") @@ -589,9 +559,7 @@ def transmit_arq(self, data): threading.Event().wait(3) - prepared_data, type_byte = self.arq_data_type_handler.prepare( - data, ARQ_SESSION_TYPES.p2p_connection - ) + prepared_data, type_byte = self.arq_data_type_handler.prepare(data, ARQ_SESSION_TYPES.p2p_connection) iss = ARQSessionISS(self.ctx, arq_destination, prepared_data, type_byte) iss.id = self.session_id # register p2p connection to arq session @@ -621,9 +589,7 @@ def received_arq(self, received_data): self.ctx.socket_interface_manager.data_server, "data_handler" ): self.log(f"sending {len(received_data)} bytes to data socket client") - self.ctx.socket_interface_manager.data_server.data_handler.send_data_to_client( - received_data - ) + self.ctx.socket_interface_manager.data_server.data_handler.send_data_to_client(received_data) except Exception as e: self.log(f"Error sending data to socket: {e}") diff --git a/freedata_server/radio_manager.py b/freedata_server/radio_manager.py index 6977e0749..bb4a2b7e2 100644 --- a/freedata_server/radio_manager.py +++ b/freedata_server/radio_manager.py @@ -41,9 +41,7 @@ def set_ptt(self, state): self.ctx.config_manager.config["SOCKET_INTERFACE"]["enable"] and self.ctx.socket_interface_manager.command_server.command_handler ): - self.socket_interface_manager.command_server.command_handler.socket_respond_ptt( - state - ) + self.socket_interface_manager.command_server.command_handler.socket_respond_ptt(state) except Exception as e: print(e) diff --git a/freedata_server/rigctld.py b/freedata_server/rigctld.py index 28d867c0a..1915e3a7b 100644 --- a/freedata_server/rigctld.py +++ b/freedata_server/rigctld.py @@ -87,9 +87,7 @@ def connect(self): f"[RIGCTLD] Connection attempt {attempt}/{self.max_connection_attempts} " f"to {self.hostname}:{self.port}" ) - self.connection = socket.create_connection( - (self.hostname, self.port), timeout=self.timeout - ) + self.connection = socket.create_connection((self.hostname, self.port), timeout=self.timeout) self.connection.settimeout(self.timeout) # allow rigctld to warm up threading.Event().wait(2) @@ -114,9 +112,7 @@ def connect(self): and attempt < self.max_connection_attempts and self.ctx.config_manager.config["RADIO"]["control"] in ["rigctld_bundle"] ): - self.log.info( - f"[RIGCTLD] Reached {attempt} failures, restarting rigctld service." - ) + self.log.info(f"[RIGCTLD] Reached {attempt} failures, restarting rigctld service.") try: self.stop_service() self.start_service() @@ -130,10 +126,7 @@ def connect(self): # if still not connected after all attempts if not self.connected: - self.log.error( - f"[RIGCTLD] Could not establish connection after " - f"{self.max_connection_attempts} attempts" - ) + self.log.error(f"[RIGCTLD] Could not establish connection after {self.max_connection_attempts} attempts") def disconnect(self): """Disconnects from the rigctld server. @@ -208,9 +201,7 @@ def send_command(self, command): return stripped_result except socket.timeout: - self.log.warning( - f"[RIGCTLD] Timeout waiting for response from rigctld: [{command}]" - ) + self.log.warning(f"[RIGCTLD] Timeout waiting for response from rigctld: [{command}]") self.connected = False # Set connected to False if timeout occurs return None # Return None to indicate timeout except Exception as err: @@ -638,19 +629,13 @@ def start_service(self): if binary_paths: for binary_path in binary_paths: try: - self.log.info( - f"Attempting to start rigctld using binary found at: {binary_path}" - ) + self.log.info(f"Attempting to start rigctld using binary found at: {binary_path}") self.rigctld_process = helpers.kill_and_execute(binary_path, additional_args) self.log.info("Successfully executed rigctld", args=additional_args) return # Exit the function after successful execution except Exception as e: - self.log.warning( - f"Failed to start rigctld with binary at {binary_path}: {e}" - ) # Log the error - self.log.warning( - "Failed to start rigctld with all found binaries.", binaries=binary_paths - ) + self.log.warning(f"Failed to start rigctld with binary at {binary_path}: {e}") # Log the error + self.log.warning("Failed to start rigctld with all found binaries.", binaries=binary_paths) else: self.log.warning("Rigctld binary not found.") diff --git a/freedata_server/schedule_manager.py b/freedata_server/schedule_manager.py index c1188e7b5..0b3d895dc 100644 --- a/freedata_server/schedule_manager.py +++ b/freedata_server/schedule_manager.py @@ -3,8 +3,9 @@ import threading from freedata_server import command_message_send -#from freedata_server.context import AppContext -#from message_system_db_manager import DatabaseManager + +# from freedata_server.context import AppContext +# from message_system_db_manager import DatabaseManager from freedata_server.message_system_db_messages import DatabaseManagerMessages from freedata_server.message_system_db_beacon import DatabaseManagerBeacon from message_system_db_broadcasts import DatabaseManagerBroadcasts @@ -19,7 +20,6 @@ from freedata_server.arq_session_iss import ISS_State - class ScheduleManager: """Manages scheduled tasks for the FreeDATA modem. @@ -46,15 +46,13 @@ def __init__(self, ctx): self.scheduler = sched.scheduler(time.time, threading.Event().wait) self.events = { - 'check_for_queued_messages': {'function': self.check_for_queued_messages, 'interval': 15}, - 'explorer_publishing': {'function': self.push_to_explorer, 'interval': 60}, - 'transmitting_beacon': {'function': self.transmit_beacon, 'interval': 600}, - 'beacon_cleanup': {'function': self.delete_beacons, 'interval': 600}, - 'update_transmission_state': {'function': self.update_transmission_state, 'interval': 10}, - 'check_missing_broadcast_bursts': {'function': self.check_missing_broadcast_bursts, 'interval': 20}, - 'check_queued_messages': {'function': self.check_queued_messages, 'interval': 20}, - - + "check_for_queued_messages": {"function": self.check_for_queued_messages, "interval": 15}, + "explorer_publishing": {"function": self.push_to_explorer, "interval": 60}, + "transmitting_beacon": {"function": self.transmit_beacon, "interval": 600}, + "beacon_cleanup": {"function": self.delete_beacons, "interval": 600}, + "update_transmission_state": {"function": self.update_transmission_state, "interval": 10}, + "check_missing_broadcast_bursts": {"function": self.check_missing_broadcast_bursts, "interval": 20}, + "check_queued_messages": {"function": self.check_queued_messages, "interval": 20}, } self.running = False # Flag to control the running state self.scheduler_thread = None # Reference to the scheduler thread @@ -98,9 +96,7 @@ def start(self, modem): self.running = True # Set the running flag to True for event_info in self.events.values(): # Schedule each event for the first time - self.scheduler.enter( - 0, 1, self.schedule_event, (event_info["function"], event_info["interval"]) - ) + self.scheduler.enter(0, 1, self.schedule_event, (event_info["function"], event_info["interval"])) # Run the scheduler in a separate thread self.scheduler_thread = threading.Thread(target=self.scheduler.run, daemon=False) @@ -157,10 +153,7 @@ def delete_beacons(self): print(e) def push_to_explorer(self): - if ( - self.ctx.config_manager.config["STATION"]["enable_explorer"] - and self.ctx.state_manager.is_modem_running - ): + if self.ctx.config_manager.config["STATION"]["enable_explorer"] and self.ctx.state_manager.is_modem_running: try: explorer.Explorer(self.ctx).push() except Exception as e: @@ -181,12 +174,8 @@ def check_for_queued_messages(self): and self.ctx.state_manager.is_modem_running ): try: - if first_queued_message := DatabaseManagerMessages( - self.ctx - ).get_first_queued_message(): - command = command_message_send.SendMessageCommand( - self.ctx, first_queued_message - ) + if first_queued_message := DatabaseManagerMessages(self.ctx).get_first_queued_message(): + command = command_message_send.SendMessageCommand(self.ctx, first_queued_message) command.transmit() except Exception as e: print(e) @@ -248,23 +237,25 @@ def update_transmission_state(self): self.log.warning("[SCHEDULE] error deleting ARQ session", error=e) def check_missing_broadcast_bursts(self): - if ( - self.ctx.config_manager.config["EXP"]["enable_groupchat"] - and self.ctx.state_manager.is_modem_running - ): + if self.ctx.config_manager.config["EXP"]["enable_groupchat"] and self.ctx.state_manager.is_modem_running: missing_bursts = DatabaseManagerBroadcasts(self.ctx).check_missing_bursts() print("missing_bursts", missing_bursts) if missing_bursts: # Increment attempts - DatabaseManagerBroadcasts(self.ctx).increment_attempts_and_update_next_transmission(missing_bursts["id"]) - myfullcall = self.ctx.config_manager.config['STATION']['mycall'] + '-' + str(self.ctx.config_manager.config['STATION']['myssid']) - NormTransmission(self.ctx).create_and_transmit_nack_burst(myfullcall, missing_bursts["id"], missing_bursts["missing_bursts"]) + DatabaseManagerBroadcasts(self.ctx).increment_attempts_and_update_next_transmission( + missing_bursts["id"] + ) + myfullcall = ( + self.ctx.config_manager.config["STATION"]["mycall"] + + "-" + + str(self.ctx.config_manager.config["STATION"]["myssid"]) + ) + NormTransmission(self.ctx).create_and_transmit_nack_burst( + myfullcall, missing_bursts["id"], missing_bursts["missing_bursts"] + ) def check_queued_messages(self): - if ( - self.ctx.config_manager.config["EXP"]["enable_groupchat"] - and self.ctx.state_manager.is_modem_running - ): + if self.ctx.config_manager.config["EXP"]["enable_groupchat"] and self.ctx.state_manager.is_modem_running: msg = DatabaseManagerBroadcasts(self.ctx).get_first_queued_message() if msg: print(msg.payload_data) diff --git a/freedata_server/service_manager.py b/freedata_server/service_manager.py index a68e39bfd..56f226e84 100644 --- a/freedata_server/service_manager.py +++ b/freedata_server/service_manager.py @@ -35,9 +35,7 @@ def __init__(self, ctx): self.shutdown_flag = threading.Event() - self.runner_thread = threading.Thread( - target=self.runner, name="runner thread", daemon=False - ) + self.runner_thread = threading.Thread(target=self.runner, name="runner thread", daemon=False) self.runner_thread.start() @@ -62,9 +60,7 @@ def runner(self): self.start_modem() if self.ctx.config_manager.config["SOCKET_INTERFACE"]["enable"]: - self.ctx.socket_interface_manager = SocketInterfaceHandler( - self.ctx - ).start_servers() + self.ctx.socket_interface_manager = SocketInterfaceHandler(self.ctx).start_servers() else: self.ctx.socket_interface_manager = None @@ -102,9 +98,7 @@ def runner(self): self.start_radio_manager() if self.ctx.config_manager.config["SOCKET_INTERFACE"]["enable"]: - self.ctx.socket_interface_manager = SocketInterfaceHandler( - self.ctx - ).start_servers() + self.ctx.socket_interface_manager = SocketInterfaceHandler(self.ctx).start_servers() else: self.ctx.socket_interface_manager = None @@ -250,8 +244,6 @@ def shutdown(self): """ self.log.warning("[SHUTDOWN] stopping service manager....") self.ctx.modem_service.put("stop") - threading.Event().wait( - 2 - ) # we need some time before processing with the shutdown_event_flag + threading.Event().wait(2) # we need some time before processing with the shutdown_event_flag self.shutdown_flag.set() self.runner_thread.join(0.5) diff --git a/freedata_server/socket_interface.py b/freedata_server/socket_interface.py index 134b4b3e2..7c069d938 100644 --- a/freedata_server/socket_interface.py +++ b/freedata_server/socket_interface.py @@ -114,13 +114,9 @@ def handle(self): if not self.data: break try: - self.log( - f"Data received from {self.client_address}: [{len(self.data)}] - {self.data.decode()}" - ) + self.log(f"Data received from {self.client_address}: [{len(self.data)}] - {self.data.decode()}") except Exception: - self.log( - f"Data received from {self.client_address}: [{len(self.data)}] - {self.data}" - ) + self.log(f"Data received from {self.client_address}: [{len(self.data)}] - {self.data}") for session_id in self.ctx.state_manager.p2p_connection_sessions: session = self.ctx.state_manager.p2p_connection_sessions[session_id] @@ -210,9 +206,7 @@ def start_servers(self): def run_server(self, ip, port, handler): try: - with CustomThreadedTCPServer( - (ip, port), handler, ctx=self.ctx, socket_interface_manager=self - ) as server: + with CustomThreadedTCPServer((ip, port), handler, ctx=self.ctx, socket_interface_manager=self) as server: self.log(f"Server starting on ip:port: {ip}:{port}") if port == self.command_port: self.command_server = server diff --git a/freedata_server/state_manager.py b/freedata_server/state_manager.py index e5456014d..86c358003 100644 --- a/freedata_server/state_manager.py +++ b/freedata_server/state_manager.py @@ -472,10 +472,7 @@ def calculate_channel_busy_state(self): it sets the channel_busy_event, indicating the channel is available. Otherwise, it resets the channel_busy_event. """ - if ( - self.channel_busy_condition_traffic.is_set() - and self.channel_busy_condition_codec2.is_set() - ): + if self.channel_busy_condition_traffic.is_set() and self.channel_busy_condition_codec2.is_set(): self.channel_busy_event.set() else: self.channel_busy_event = threading.Event() diff --git a/freedata_server/wavelog_api_logger.py b/freedata_server/wavelog_api_logger.py index 68eff238d..32300e7c0 100644 --- a/freedata_server/wavelog_api_logger.py +++ b/freedata_server/wavelog_api_logger.py @@ -21,9 +21,7 @@ def send_wavelog_qso_data(ctx, wavelog_data): if not wavelog: return # exit as we don't want to log Wavelog - wavelog_host = ctx.config_manager.config["QSO_LOGGING"].get( - "adif_wavelog_host", "http://localhost/" - ) + wavelog_host = ctx.config_manager.config["QSO_LOGGING"].get("adif_wavelog_host", "http://localhost/") wavelog_api_key = ctx.config_manager.config["QSO_LOGGING"].get("adif_wavelog_api_key", "") # check if the last part in the HOST URL from the config is correct @@ -51,9 +49,7 @@ def send_api(): callsign_end = wavelog_data.find(" threading.Event().wait(tx_time) transmission = { - 'mode': mode, - 'bytes': frames, + "mode": mode, + "bytes": frames, } self.data_queue_received.put(transmission) class TestMessageProtocol(unittest.TestCase): - @classmethod def setUpClass(cls): cls.logger = structlog.get_logger("TESTS") # ISS - cls.ctx_ISS = AppContext('freedata_server/config.ini.example') + cls.ctx_ISS = AppContext("freedata_server/config.ini.example") cls.ctx_ISS.TESTMODE = True cls.ctx_ISS.startup() - # IRS - cls.ctx_IRS = AppContext('freedata_server/config.ini.example') + cls.ctx_IRS = AppContext("freedata_server/config.ini.example") cls.ctx_IRS.TESTMODE = True cls.ctx_IRS.startup() @@ -73,7 +71,6 @@ def setUpClass(cls): # Frame loss probability in % cls.loss_probability = 0 - cls.channels_running = False @classmethod @@ -81,7 +78,6 @@ def tearDownClass(cls): cls.ctx_IRS.shutdown() cls.ctx_ISS.shutdown() - def channelWorker(self, ctx_a, ctx_b): while self.channels_running: try: @@ -89,7 +85,7 @@ def channelWorker(self, ctx_a, ctx_b): transmission = ctx_a.TESTMODE_TRANSMIT_QUEUE.get(timeout=1) print(f"Station A sending: {transmission[1]}", len(transmission[1]), transmission[0]) - transmission[1] += bytes(2) # 2bytes crc simulation + transmission[1] += bytes(2) # 2bytes crc simulation if random.randint(0, 100) < self.loss_probability: self.logger.info(f"[{threading.current_thread().name}] Frame lost...") @@ -118,11 +114,11 @@ def channelWorker(self, ctx_a, ctx_b): self.logger.info(f"[{threading.current_thread().name}] Channel closed.") def waitForSession(self, event_queue, outbound=False): - key = 'arq-transfer-outbound' if outbound else 'arq-transfer-inbound' + key = "arq-transfer-outbound" if outbound else "arq-transfer-inbound" while self.channels_running: try: ev = event_queue.get(timeout=2) - if key in ev and ('success' in ev[key] or 'ABORTED' in ev[key]): + if key in ev and ("success" in ev[key] or "ABORTED" in ev[key]): self.logger.info(f"[{threading.current_thread().name}] {key} session ended.") break except queue.Empty: @@ -130,10 +126,10 @@ def waitForSession(self, event_queue, outbound=False): def establishChannels(self): self.channels_running = True - self.channelA = threading.Thread(target=self.channelWorker,args=[self.ctx_ISS, self.ctx_IRS],name = "channelA") + self.channelA = threading.Thread(target=self.channelWorker, args=[self.ctx_ISS, self.ctx_IRS], name="channelA") self.channelA.start() - self.channelB = threading.Thread(target=self.channelWorker,args=[self.ctx_IRS, self.ctx_ISS],name = "channelB") + self.channelB = threading.Thread(target=self.channelWorker, args=[self.ctx_IRS, self.ctx_ISS], name="channelB") self.channelB.start() def waitAndCloseChannels(self): @@ -147,13 +143,18 @@ def testNormBroadcast(self): self.establishChannels() params = { - 'origin': "AA1AAA-1", - 'domain': "BB1BBB-1", - 'gridsquare': "JN48ea", - 'type': 'MESSAGE', - 'priority': '1', + "origin": "AA1AAA-1", + "domain": "BB1BBB-1", + "gridsquare": "JN48ea", + "type": "MESSAGE", + "priority": "1", #'data': str(base64.b64encode(b"hello world!"), 'utf-8') - 'data': str(base64.b64encode(b"hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!"), 'utf-8') + "data": str( + base64.b64encode( + b"hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!" + ), + "utf-8", + ), } try: command = command_norm.Norm(self.ctx_ISS, params) @@ -161,15 +162,15 @@ def testNormBroadcast(self): except Exception as e: print(e) - - #del cmd - #print(self.ctx_ISS.TESTMODE_EVENTS.empty()) + # del cmd + # print(self.ctx_ISS.TESTMODE_EVENTS.empty()) while not self.ctx_ISS.TESTMODE_EVENTS.empty(): event = self.ctx_ISS.TESTMODE_EVENTS.get() - success = event.get('arq-transfer-outbound', {}).get('success', None) + success = event.get("arq-transfer-outbound", {}).get("success", None) if success is not None: self.assertTrue(success, f"Test failed because of wrong success: {success}") -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/tests/test_p2p_connection.py b/tests/test_p2p_connection.py index a6ae54ef8..2b3690a6c 100644 --- a/tests/test_p2p_connection.py +++ b/tests/test_p2p_connection.py @@ -138,9 +138,7 @@ def channelWorker(self, modem_transmit_queue, frame_dispatcher): transmission = modem_transmit_queue.get(timeout=1) if random.randint(0, 100) < self.loss_probability: continue - frame_dispatcher.process_data( - transmission["bytes"], None, len(transmission["bytes"]), 0, 0, "test" - ) + frame_dispatcher.process_data(transmission["bytes"], None, len(transmission["bytes"]), 0, 0, "test") except queue.Empty: continue diff --git a/tests/test_protocols.py b/tests/test_protocols.py index a530dcf07..ec55ccaf0 100755 --- a/tests/test_protocols.py +++ b/tests/test_protocols.py @@ -29,9 +29,7 @@ def tearDownClass(cls): def shortcutTransmission(self, frame_bytes): """Inject a frame directly into the frame dispatcher.""" - self.frame_dispatcher.process_data( - frame_bytes, None, len(frame_bytes), 0, 0, mode_name="TEST" - ) + self.frame_dispatcher.process_data(frame_bytes, None, len(frame_bytes), 0, 0, mode_name="TEST") def assertEventReceivedType(self, event_type): """Assert that an event with a specific type was received.""" diff --git a/tools/custom_mode_tests/run_mode_tests.py b/tools/custom_mode_tests/run_mode_tests.py index 6951eb54c..627cc52c4 100644 --- a/tools/custom_mode_tests/run_mode_tests.py +++ b/tools/custom_mode_tests/run_mode_tests.py @@ -57,9 +57,7 @@ def compute_audio_metrics(self, txbuffer): avg_volume = np.mean(np.abs(txbuffer)) avg_volume_db = 20 * np.log10(avg_volume) if avg_volume > 0 else -np.inf - max_possible_volume_db = 20 * np.log10( - 1.0 - ) # Max possible volume when signal is fully utilized + max_possible_volume_db = 20 * np.log10(1.0) # Max possible volume when signal is fully utilized max_val = np.max(np.abs(txbuffer)) # Prevent division by zero and ensure reasonable values @@ -70,9 +68,7 @@ def compute_audio_metrics(self, txbuffer): # Compute FFT fft_values = np.abs(fft(txbuffer))[: len(txbuffer) // 2] - freqs = np.fft.fftfreq(len(txbuffer), d=1 / 8000)[ - : len(txbuffer) // 2 - ] # Assuming 8 kHz sample rate + freqs = np.fft.fftfreq(len(txbuffer), d=1 / 8000)[: len(txbuffer) // 2] # Assuming 8 kHz sample rate return avg_volume_db, max_possible_volume_db, papr, freqs, fft_values @@ -152,9 +148,7 @@ def test_freedv_mode_pairs(mode_pairs, config_file="config.ini"): txbuffer = np.frombuffer(txbuffer, dtype=np.int16) result = freedv_rx.demodulate(txbuffer) - avg_volume_db, max_possible_volume_db, papr, freqs, fft_values = ( - freedv_tx.compute_audio_metrics(txbuffer) - ) + avg_volume_db, max_possible_volume_db, papr, freqs, fft_values = freedv_tx.compute_audio_metrics(txbuffer) results.append(( test_tx.name, test_rx.name, @@ -182,8 +176,8 @@ def test_freedv_mode_pairs(mode_pairs, config_file="config.ini"): (FREEDV_MODE.datac1, FREEDV_MODE.data_ofdm_1700), (FREEDV_MODE.data_ofdm_2438, FREEDV_MODE.data_ofdm_2438), ] - results, avg_volume_per_mode, avg_max_volume_per_mode, avg_papr_per_mode, fft_data = ( - test_freedv_mode_pairs(test_mode_pairs) + results, avg_volume_per_mode, avg_max_volume_per_mode, avg_papr_per_mode, fft_data = test_freedv_mode_pairs( + test_mode_pairs ) plot_audio_metrics(avg_volume_per_mode, avg_max_volume_per_mode, avg_papr_per_mode) plot_fft_per_mode(fft_data) From 8f7113fd3e2defec31eeb1e3c4750b6d1b9d58e3 Mon Sep 17 00:00:00 2001 From: as3ii Date: Thu, 8 Jan 2026 20:06:12 +0100 Subject: [PATCH 2/6] Fixed ruff E7 --- freedata_server/message_system_db_model.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/freedata_server/message_system_db_model.py b/freedata_server/message_system_db_model.py index bf044be8a..97bbe30ea 100644 --- a/freedata_server/message_system_db_model.py +++ b/freedata_server/message_system_db_model.py @@ -210,11 +210,6 @@ def to_dict(self): } -from sqlalchemy import Column, DateTime, String, Integer, Boolean, JSON, ForeignKey, Index -from sqlalchemy.orm import relationship -from datetime import datetime, timezone - - class BroadcastMessage(Base): __tablename__ = "broadcast_messages" From ed4c79cd2aaa0e5cab50aa1b2fe7f44e252f5d11 Mon Sep 17 00:00:00 2001 From: as3ii Date: Thu, 8 Jan 2026 20:08:33 +0100 Subject: [PATCH 3/6] Fixed ruff F541 --- freedata_server/api/freedata.py | 2 +- freedata_server/websocket_manager.py | 2 +- tests/test_norm_protocol.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freedata_server/api/freedata.py b/freedata_server/api/freedata.py index 6d56c6725..b4afab6d0 100644 --- a/freedata_server/api/freedata.py +++ b/freedata_server/api/freedata.py @@ -583,4 +583,4 @@ async def patch_freedata_broadcast_domain(id: str, payload: dict, ctx: AppContex @router.post("/broadcasts", summary="Transmit Broadcast", tags=["FreeDATA"], responses={}) async def post_freedata_broadcast(payload: dict, ctx: AppContext = Depends(get_ctx)): await enqueue_tx_command(ctx, command_norm.Norm, payload) - return api_response({"message": f"broadcast transmitted", "status": "success"}) + return api_response({"message": "broadcast transmitted", "status": "success"}) diff --git a/freedata_server/websocket_manager.py b/freedata_server/websocket_manager.py index fa5945649..6f8c42112 100644 --- a/freedata_server/websocket_manager.py +++ b/freedata_server/websocket_manager.py @@ -51,7 +51,7 @@ async def handle_connection(self, websocket, client_list, event_queue): event_queue (queue.Queue): The event queue. Currently unused. """ client_list.add(websocket) - self.log.info(f"Client websocket connection established", ws=websocket) + self.log.info("Client websocket connection established", ws=websocket) while not self.shutdown_flag.is_set(): try: await websocket.receive_text() diff --git a/tests/test_norm_protocol.py b/tests/test_norm_protocol.py index 7cb29fe94..5d051dee6 100644 --- a/tests/test_norm_protocol.py +++ b/tests/test_norm_protocol.py @@ -95,7 +95,7 @@ def channelWorker(self, ctx_a, ctx_b): if ctx_b: for burst in transmission: ctx_b.TESTMODE_RECEIVE_QUEUE.put(burst) - self.logger.info(f"Data forwarded to Station B") + self.logger.info("Data forwarded to Station B") frame_bytes = transmission[1] if len(frame_bytes) == 5: From bec3a28364fe1aeff28e207506831343bc6570cd Mon Sep 17 00:00:00 2001 From: as3ii Date: Thu, 8 Jan 2026 20:19:17 +0100 Subject: [PATCH 4/6] Fixed ruff F841 --- freedata_server/frame_handler_norm.py | 2 +- freedata_server/maidenhead.py | 2 +- freedata_server/norm/norm_transmission.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/freedata_server/frame_handler_norm.py b/freedata_server/frame_handler_norm.py index 5f8c99e88..ce16165a4 100644 --- a/freedata_server/frame_handler_norm.py +++ b/freedata_server/frame_handler_norm.py @@ -37,7 +37,7 @@ def follow_protocol(self): print("maximum attempts reached...") return DatabaseManagerBroadcasts(self.ctx).increment_attempts(broadcast["id"]) - data = base64.b64decode(broadcast["payload_data"]["final"]) + _data = base64.b64decode(broadcast["payload_data"]["final"]) print(broadcast) print("oring", broadcast["origin"]) print("domain", broadcast["domain"]) diff --git a/freedata_server/maidenhead.py b/freedata_server/maidenhead.py index 1becd1a1f..c8e5bf7dd 100644 --- a/freedata_server/maidenhead.py +++ b/freedata_server/maidenhead.py @@ -97,7 +97,7 @@ def latlon_to_maidenhead(lat, lon, precision=6): lat += 90 A = ord("A") - a = ord("a") + _a = ord("a") lon_field = int(lon // 20) lat_field = int(lat // 10) diff --git a/freedata_server/norm/norm_transmission.py b/freedata_server/norm/norm_transmission.py index 97e186742..c72f86e1f 100644 --- a/freedata_server/norm/norm_transmission.py +++ b/freedata_server/norm/norm_transmission.py @@ -6,6 +6,7 @@ from enum import IntEnum import hashlib from freedata_server.codec2 import FREEDV_MODE +from freedata_server.data_frame_factory import DataFrameFactory class NORMMsgType(IntEnum): @@ -36,7 +37,7 @@ def __init__(self, ctx): self.origin = None self.domain = None - self.frame_factory = freedata_server.data_frame_factory.DataFrameFactory(self.ctx) + self.frame_factory = DataFrameFactory(self.ctx) def log(self, message, isWarning=False): """Logs a message with session context. From 646174b75dabd84594c6793a41e197f85bbee566 Mon Sep 17 00:00:00 2001 From: as3ii Date: Sat, 10 Jan 2026 18:34:54 +0100 Subject: [PATCH 5/6] Fixed ruff F811 and F401 --- freedata_server/api/freedata.py | 8 ++------ freedata_server/command_norm.py | 3 --- freedata_server/frame_dispatcher.py | 10 +--------- freedata_server/frame_handler_norm.py | 16 +++++----------- freedata_server/message_system_db_broadcasts.py | 8 ++++---- freedata_server/schedule_manager.py | 6 +++--- freedata_server/websocket_manager.py | 2 -- tests/test_data_frame_factory.py | 2 +- tests/test_norm_protocol.py | 5 ----- 9 files changed, 16 insertions(+), 44 deletions(-) diff --git a/freedata_server/api/freedata.py b/freedata_server/api/freedata.py index b4afab6d0..c718772d1 100644 --- a/freedata_server/api/freedata.py +++ b/freedata_server/api/freedata.py @@ -1,10 +1,6 @@ -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Depends import command_norm -import command_message_send -import adif_udp_logger -import wavelog_api_logger -from context import AppContext, get_ctx import asyncio from freedata_server.api.common import api_response, api_abort @@ -549,7 +545,7 @@ async def get_freedata_broadcasts_per_domain(domain: str, ctx: AppContext = Depe @router.get("/broadcasts/domains", summary="Get All Broadcast Messages", tags=["FreeDATA"], responses={}) -async def get_freedata_broadcasts(ctx: AppContext = Depends(get_ctx)): +async def get_freedata_broadcasts(ctx: AppContext = Depends(get_ctx)): # noqa: F811 # same as line 534, but different path # filters = {k: v for k, v in ctx.config_manager.read().get('FILTERS', {}).items()} # use query params if needed # filters = dict(ctx.request.query_params) diff --git a/freedata_server/command_norm.py b/freedata_server/command_norm.py index 2cc10ad8d..053c23b0e 100644 --- a/freedata_server/command_norm.py +++ b/freedata_server/command_norm.py @@ -1,9 +1,6 @@ -import queue from command import TxCommand import api_validations import base64 -from queue import Queue -import numpy as np import threading from norm.norm_transmission_iss import NormTransmissionISS diff --git a/freedata_server/frame_dispatcher.py b/freedata_server/frame_dispatcher.py index f38853812..582153481 100644 --- a/freedata_server/frame_dispatcher.py +++ b/freedata_server/frame_dispatcher.py @@ -6,15 +6,6 @@ import threading import structlog -import event_manager - -from frame_handler import FrameHandler -from frame_handler_ping import PingFrameHandler -from frame_handler_cq import CQFrameHandler -from frame_handler_arq_session import ARQFrameHandler -from frame_handler_p2p_connection import P2PConnectionFrameHandler -from frame_handler_beacon import BeaconFrameHandler -from frame_handler_norm import NORMFrameHandler from freedata_server.modem_frametypes import FRAME_TYPE as FR_TYPE from freedata_server.data_frame_factory import DataFrameFactory @@ -25,6 +16,7 @@ from freedata_server.frame_handler_arq_session import ARQFrameHandler from freedata_server.frame_handler_p2p_connection import P2PConnectionFrameHandler from freedata_server.frame_handler_beacon import BeaconFrameHandler +from freedata_server.frame_handler_norm import NORMFrameHandler class DISPATCHER: diff --git a/freedata_server/frame_handler_norm.py b/freedata_server/frame_handler_norm.py index ce16165a4..1180623a5 100644 --- a/freedata_server/frame_handler_norm.py +++ b/freedata_server/frame_handler_norm.py @@ -1,16 +1,10 @@ import base64 -import threading -from modem_frametypes import FRAME_TYPE as FR -import frame_handler_ping -import helpers -import data_frame_factory -import frame_handler -from message_system_db_broadcasts import DatabaseManagerBroadcasts -import numpy as np - -from norm.norm_transmission_irs import NormTransmissionIRS -from norm.norm_transmission_iss import NormTransmissionISS +from freedata_server.modem_frametypes import FRAME_TYPE as FR +from freedata_server import frame_handler +from freedata_server.message_system_db_broadcasts import DatabaseManagerBroadcasts +from freedata_server.norm.norm_transmission_irs import NormTransmissionIRS +from freedata_server.norm.norm_transmission_iss import NormTransmissionISS class NORMFrameHandler(frame_handler.FrameHandler): diff --git a/freedata_server/message_system_db_broadcasts.py b/freedata_server/message_system_db_broadcasts.py index 73c83ebd8..fb7d4f690 100644 --- a/freedata_server/message_system_db_broadcasts.py +++ b/freedata_server/message_system_db_broadcasts.py @@ -1,9 +1,9 @@ -from message_system_db_manager import DatabaseManager -from message_system_db_model import Status, BroadcastMessage -from message_system_db_station import DatabaseManagerStations +from freedata_server.message_system_db_manager import DatabaseManager +from freedata_server.message_system_db_model import BroadcastMessage +from freedata_server.message_system_db_station import DatabaseManagerStations from sqlalchemy.orm.attributes import flag_modified from datetime import datetime, timedelta, timezone -import helpers +from freedata_server import helpers import base64 diff --git a/freedata_server/schedule_manager.py b/freedata_server/schedule_manager.py index 0b3d895dc..223537cf0 100644 --- a/freedata_server/schedule_manager.py +++ b/freedata_server/schedule_manager.py @@ -8,9 +8,9 @@ # from message_system_db_manager import DatabaseManager from freedata_server.message_system_db_messages import DatabaseManagerMessages from freedata_server.message_system_db_beacon import DatabaseManagerBeacon -from message_system_db_broadcasts import DatabaseManagerBroadcasts -from norm.norm_transmission import NormTransmission, NORMMsgPriority, NORMMsgType -from norm.norm_transmission_iss import NormTransmissionISS +from freedata_server.message_system_db_broadcasts import DatabaseManagerBroadcasts +from freedata_server.norm.norm_transmission import NormTransmission +from freedata_server.norm.norm_transmission_iss import NormTransmissionISS from freedata_server import explorer from freedata_server import command_beacon diff --git a/freedata_server/websocket_manager.py b/freedata_server/websocket_manager.py index 6f8c42112..8ee50b9f1 100644 --- a/freedata_server/websocket_manager.py +++ b/freedata_server/websocket_manager.py @@ -1,8 +1,6 @@ import threading import json import asyncio -from asyncio import run_coroutine_threadsafe - import numpy as np import structlog diff --git a/tests/test_data_frame_factory.py b/tests/test_data_frame_factory.py index 5d8bf4d40..dc3780a2a 100755 --- a/tests/test_data_frame_factory.py +++ b/tests/test_data_frame_factory.py @@ -3,6 +3,7 @@ from freedata_server.data_frame_factory import DataFrameFactory from freedata_server.codec2 import FREEDV_MODE +from freedata_server.config import CONFIG from freedata_server import helpers from freedata_server.modem_frametypes import FRAME_TYPE @@ -10,7 +11,6 @@ # Dummy Context with config class DummyCtx: def __init__(self, config_path): - from config import CONFIG self.config_manager = CONFIG(self, config_path) diff --git a/tests/test_norm_protocol.py b/tests/test_norm_protocol.py index 5d051dee6..e1d674c10 100644 --- a/tests/test_norm_protocol.py +++ b/tests/test_norm_protocol.py @@ -1,5 +1,4 @@ import sys -import time import unittest import unittest.mock import queue @@ -7,16 +6,12 @@ import random import structlog import base64 -import numpy as np sys.path.append("freedata_server") -from config import CONFIG from context import AppContext from event_manager import EventManager from state_manager import StateManager -from data_frame_factory import DataFrameFactory -from frame_dispatcher import DISPATCHER import codec2 import command_norm From e2b2c73f1af2ee6296c547c3a54ab724a51bba74 Mon Sep 17 00:00:00 2001 From: as3ii Date: Sat, 10 Jan 2026 20:27:19 +0100 Subject: [PATCH 6/6] Fixed other module's paths --- freedata_server/api/freedata.py | 2 +- freedata_server/command_norm.py | 6 +++--- freedata_server/data_frame_factory.py | 1 - freedata_server/message_system_db_broadcasts.py | 2 -- freedata_server/norm/norm_transmission.py | 1 - tests/test_data_frame_factory.py | 1 - tests/test_norm_protocol.py | 13 +++++-------- 7 files changed, 9 insertions(+), 17 deletions(-) diff --git a/freedata_server/api/freedata.py b/freedata_server/api/freedata.py index c718772d1..a85a9ccc9 100644 --- a/freedata_server/api/freedata.py +++ b/freedata_server/api/freedata.py @@ -1,6 +1,5 @@ from fastapi import APIRouter, Depends -import command_norm import asyncio from freedata_server.api.common import api_response, api_abort @@ -13,6 +12,7 @@ from freedata_server import command_message_send from freedata_server import adif_udp_logger from freedata_server import wavelog_api_logger +from freedata_server import command_norm from freedata_server.context import AppContext, get_ctx from freedata_server.norm.norm_transmission_iss import NormTransmissionISS diff --git a/freedata_server/command_norm.py b/freedata_server/command_norm.py index 053c23b0e..bd6e47920 100644 --- a/freedata_server/command_norm.py +++ b/freedata_server/command_norm.py @@ -1,8 +1,8 @@ -from command import TxCommand -import api_validations +from freedata_server.command import TxCommand +from freedata_server import api_validations import base64 import threading -from norm.norm_transmission_iss import NormTransmissionISS +from freedata_server.norm.norm_transmission_iss import NormTransmissionISS class Norm(TxCommand): diff --git a/freedata_server/data_frame_factory.py b/freedata_server/data_frame_factory.py index c2889ace4..1b3815b5b 100644 --- a/freedata_server/data_frame_factory.py +++ b/freedata_server/data_frame_factory.py @@ -725,7 +725,6 @@ def build_p2p_connection_disconnect_ack(self, session_id): def build_norm_data( self, origin, domain, gridsquare, timestamp, burst_info, payload_size, payload_data, flag, checksum ): - payload = { "origin": helpers.callsign_to_bytes(origin), "domain": helpers.callsign_to_bytes(domain), diff --git a/freedata_server/message_system_db_broadcasts.py b/freedata_server/message_system_db_broadcasts.py index fb7d4f690..c42c1e71b 100644 --- a/freedata_server/message_system_db_broadcasts.py +++ b/freedata_server/message_system_db_broadcasts.py @@ -251,7 +251,6 @@ def get_broadcast_domains_json(self) -> dict: session.remove() def get_broadcasts_per_domain_json(self, domain: str = None) -> dict: - if domain: self.mark_domain_as_read(domain) @@ -300,7 +299,6 @@ def get_broadcasts_per_domain_json(self, domain: str = None) -> dict: session.remove() def delete_broadcast_message_or_domain(self, id) -> dict: - session = self.get_thread_scoped_session() try: msg = session.query(BroadcastMessage).filter_by(id=id).first() diff --git a/freedata_server/norm/norm_transmission.py b/freedata_server/norm/norm_transmission.py index c72f86e1f..5aecf7106 100644 --- a/freedata_server/norm/norm_transmission.py +++ b/freedata_server/norm/norm_transmission.py @@ -54,7 +54,6 @@ def log(self, message, isWarning=False): logger(msg) def set_state(self, state): - self.last_state_change_timestamp = time.time() if self.state == state: self.log(f"{type(self).__name__} state {self.state.name} unchanged.") diff --git a/tests/test_data_frame_factory.py b/tests/test_data_frame_factory.py index dc3780a2a..0c6ba0de0 100755 --- a/tests/test_data_frame_factory.py +++ b/tests/test_data_frame_factory.py @@ -11,7 +11,6 @@ # Dummy Context with config class DummyCtx: def __init__(self, config_path): - self.config_manager = CONFIG(self, config_path) diff --git a/tests/test_norm_protocol.py b/tests/test_norm_protocol.py index e1d674c10..c6b6879a2 100644 --- a/tests/test_norm_protocol.py +++ b/tests/test_norm_protocol.py @@ -1,4 +1,3 @@ -import sys import unittest import unittest.mock import queue @@ -7,13 +6,11 @@ import structlog import base64 -sys.path.append("freedata_server") - -from context import AppContext -from event_manager import EventManager -from state_manager import StateManager -import codec2 -import command_norm +from freedata_server.context import AppContext +from freedata_server.event_manager import EventManager +from freedata_server.state_manager import StateManager +from freedata_server import codec2 +from freedata_server import command_norm class TestModem: