diff --git a/modem/arq_session.py b/modem/arq_session.py index d089daa1..5703afb4 100644 --- a/modem/arq_session.py +++ b/modem/arq_session.py @@ -24,11 +24,6 @@ class ARQSession(): self.id = None - # 3 bytes for the BOF Beginning of File indicator in a data frame - self.data_frame_bof = b"BOF" - # 3 bytes for the EOF End of File indicator in a data frame - self.data_frame_eof = b"EOF" - def log(self, message, isWarning = False): msg = f"[{type(self).__name__}]: {message}" logger = self.logger.warn if isWarning else self.logger.info diff --git a/modem/arq_session_irs.py b/modem/arq_session_irs.py index 875f055f..4647d307 100644 --- a/modem/arq_session_irs.py +++ b/modem/arq_session_irs.py @@ -94,7 +94,8 @@ class ARQSessionIRS(arq_session.ARQSession): def run(self): self.set_state(self.STATE_WAITING_DATA) - self.thread = threading.Thread(target=self.runner, name=f"ARQ IRS Session {self.id}", daemon=False) + self.thread = threading.Thread(target=self.runner, + name=f"ARQ IRS Session {self.id}", daemon=False) self.thread.start() def send_open_ack(self): @@ -123,6 +124,10 @@ class ARQSessionIRS(arq_session.ARQSession): self.frames_per_burst = self.frames_per_burst def on_info_received(self, frame): + if self.state != self.STATE_CONN_REQ_RECEIVED: + self.logger.warning("Discarding received INFO.") + return + self.received_data = bytearray(frame['total_length']) self.received_crc = frame['total_crc'] self.dx_snr = frame['snr'] @@ -134,7 +139,8 @@ class ARQSessionIRS(arq_session.ARQSession): def on_data_received(self, frame): if self.state != self.STATE_WAITING_DATA: - raise RuntimeError(f"ARQ Session: Received data while in state {self.state}, expected {self.STATE_WAITING_DATA}") + self.logger.warning(f"ARQ Session: Received data while in state {self.state}. Ignoring.") + return self.received_frame = frame self.event_data_received.set() @@ -144,10 +150,10 @@ class ARQSessionIRS(arq_session.ARQSession): self.logger.info(f"Discarding data frame due to wrong offset", frame=self.frame_received) return False - remaining_data_length = len(self.receive_data) - self.received_bytes + remaining_data_length = len(self.received_data) - self.received_bytes # Is this the last data part? - if len(self.received_frame['data']) <= remaining_data_length: + if remaining_data_length <= len(self.received_frame['data']): # we only want the remaining length, not the entire frame data data_part = self.received_frame['data'][:remaining_data_length] else: diff --git a/modem/data_frame_factory.py b/modem/data_frame_factory.py index 04030582..e6174802 100644 --- a/modem/data_frame_factory.py +++ b/modem/data_frame_factory.py @@ -199,7 +199,7 @@ class DataFrameFactory: if key in ["origin", "destination"]: extracted_data[key] = helpers.bytes_to_callsign(data).decode() - elif key in ["origin_crc", "destination_crc"]: + elif key in ["origin_crc", "destination_crc", "total_crc"]: extracted_data[key] = data.hex() elif key == "gridsquare": @@ -207,7 +207,7 @@ class DataFrameFactory: elif key in ["session_id", "speed_level", "frames_per_burst", "version", - "snr", "offset"]: + "snr", "offset", "total_length"]: extracted_data[key] = int.from_bytes(data, 'big') else: @@ -333,7 +333,7 @@ class DataFrameFactory: payload = { "frame_length": self.LENGTH_SIG0_FRAME, "session_id": session_id.to_bytes(1, 'big'), - "total_crc": total_crc, + "total_crc": bytes.fromhex(total_crc), "snr": snr.to_bytes(1, 'big'), "speed_level": speed_level.to_bytes(1, 'big'), "frames_per_burst": frames_per_burst.to_bytes(1, 'big'), diff --git a/modem/frame_handler_arq_session.py b/modem/frame_handler_arq_session.py index bdf7ae21..7c0cdca7 100644 --- a/modem/frame_handler_arq_session.py +++ b/modem/frame_handler_arq_session.py @@ -9,19 +9,27 @@ from arq_session_iss import ARQSessionISS class ARQFrameHandler(frame_handler.FrameHandler): def follow_protocol(self): - # self.details == {'frame': {'frame_type': 'BURST_01', 'frame_type_int': 1, 'n_frames_per_burst': 1, 'session_id': 31, 'data': b'Hello world!'}, 'snr': 0, 'frequency_offset': 0, 'freedv_inst': None, 'bytes_per_frame': 15} frame = self.details['frame'] snr = self.details["snr"] frequency_offset = self.details["frequency_offset"] if frame['frame_type_int'] == FR.ARQ_SESSION_OPEN.value: - session = ARQSessionIRS(self.config, - self.tx_frame_queue, - frame['origin'], - frame['session_id']) - self.states.register_arq_irs_session(session) - session.set_details(snr, frequency_offset) - session.run() + # Lost OPEN_ACK case .. ISS will retry opening a session + if frame['session_id'] in self.states.arq_irs_sessions: + session = self.states.arq_irs_sessions[frame['session_id']] + if session.state == ARQSessionIRS.STATE_CONN_REQ_RECEIVED: + session.set_details(snr, frequency_offset) + else: + self.logger.warning(f"IRS Session conflict for session {session.id}") + # Normal case when receiving a SESSION_OPEN for the first time + else: + session = ARQSessionIRS(self.config, + self.tx_frame_queue, + frame['origin'], + frame['session_id']) + self.states.register_arq_irs_session(session) + session.set_details(snr, frequency_offset) + session.run() elif frame['frame_type_int'] == FR.ARQ_SESSION_OPEN_ACK.value: session:ARQSessionISS = self.states.get_arq_iss_session(frame['session_id']) diff --git a/tests/test_arq_session.py b/tests/test_arq_session.py index 668de4d7..6027f530 100644 --- a/tests/test_arq_session.py +++ b/tests/test_arq_session.py @@ -72,7 +72,7 @@ class TestARQSession(unittest.TestCase): def testARQSession(self): # set Packet Error Rate (PER) / frame loss probability - self.loss_probability = 50 + self.loss_probability = 20 self.establishChannels() params = {