FreeDATA/modem/arq_session_irs.py

163 lines
4.8 KiB
Python
Raw Normal View History

2023-12-05 14:40:04 +00:00
import threading
import data_frame_factory
import queue
2023-12-05 18:01:48 +00:00
import arq_session
2023-12-05 14:40:04 +00:00
2023-12-05 18:01:48 +00:00
class ARQSessionIRS(arq_session.ARQSession):
2023-12-05 14:40:04 +00:00
STATE_CONN_REQ_RECEIVED = 0
STATE_WAITING_DATA = 1
STATE_FAILED = 2
STATE_ENDED = 10
RETRIES_CONNECT = 3
RETRIES_TRANSFER = 3
2023-12-13 13:33:09 +00:00
TIMEOUT_CONNECT = 6
2023-12-09 12:28:32 +00:00
TIMEOUT_DATA = 6
2023-12-05 14:40:04 +00:00
2023-12-12 19:46:22 +00:00
def __init__(self, config: dict, tx_frame_queue: queue.Queue, dxcall: str, session_id: int):
2023-12-05 18:01:48 +00:00
super().__init__(config, tx_frame_queue, dxcall)
2023-12-05 17:50:39 +00:00
self.id = session_id
2023-12-11 18:02:50 +00:00
self.speed = 0
2023-12-12 21:33:17 +00:00
self.frames_per_burst = 3
2023-12-11 18:02:50 +00:00
self.version = 1
self.snr = 0
2023-12-12 21:33:17 +00:00
self.dx_snr = 0
2023-12-05 14:40:04 +00:00
self.state = self.STATE_CONN_REQ_RECEIVED
2023-12-13 13:33:09 +00:00
self.event_info_received = threading.Event()
2023-12-05 14:40:04 +00:00
self.event_data_received = threading.Event()
2023-12-13 13:33:09 +00:00
2023-12-05 14:40:04 +00:00
self.frame_factory = data_frame_factory.DataFrameFactory(self.config)
2023-12-13 13:33:09 +00:00
self.received_frame = None
self.received_data = None
self.received_bytes = 0
self.received_crc = None
2023-12-05 14:40:04 +00:00
def generate_id(self):
pass
def set_state(self, state):
2023-12-09 12:28:32 +00:00
self.log(f"ARQ Session IRS {self.id} state {self.state}")
2023-12-05 14:40:04 +00:00
self.state = state
def set_modem_decode_modes(self, modes):
pass
2023-12-13 13:33:09 +00:00
def _all_data_received(self):
return self.received_bytes == len(self.received_data)
def handshake(self):
self.send_open_ack()
if not self.event_info_received.wait(self.TIMEOUT_CONNECT):
return False
self.send_info_ack()
self.set_state(self.STATE_WAITING_DATA)
return True
def send_info_ack(self):
info_ack = self.frame_factory.build_arq_session_info_ack(
self.id, self.received_crc, self.snr,
self.speed_level, self.frames_per_burst)
self.transmit_frame(info_ack)
def receive_data(self):
2023-12-11 18:02:50 +00:00
retries = self.RETRIES_TRANSFER
2023-12-13 13:33:09 +00:00
while retries > 0 and not self._all_data_received():
2023-12-11 18:02:50 +00:00
if self.event_data_received.wait(self.TIMEOUT_DATA):
2023-12-13 13:33:09 +00:00
self.process_incoming_data()
self.send_data_ack_nack(True)
2023-12-11 18:02:50 +00:00
retries = self.RETRIES_TRANSFER
2023-12-13 10:51:54 +00:00
else:
2023-12-13 13:33:09 +00:00
self.send_data_ack_nack(False)
retries -= 1
if self._all_data_received():
self.set_state(self.STATE_ENDED)
else:
self.set_state(self.STATE_FAILED)
2023-12-05 14:40:04 +00:00
2023-12-13 13:33:09 +00:00
def runner(self):
if not self.handshake():
return False
if not self.receive_data():
return False
2023-12-09 13:16:53 +00:00
2023-12-05 14:40:04 +00:00
def run(self):
2023-12-13 13:33:09 +00:00
self.set_state(self.STATE_WAITING_DATA)
2023-12-05 14:40:04 +00:00
self.thread = threading.Thread(target=self.runner, name=f"ARQ IRS Session {self.id}", daemon=True)
2023-12-09 13:16:53 +00:00
self.thread.start()
2023-12-13 13:33:09 +00:00
def send_open_ack(self):
2023-12-12 21:05:32 +00:00
ack_frame = self.frame_factory.build_arq_session_open_ack(
self.id,
self.dxcall,
self.version,
self.snr)
2023-12-11 18:02:50 +00:00
self.transmit_frame(ack_frame)
2023-12-05 14:40:04 +00:00
2023-12-13 10:51:54 +00:00
def send_data_ack_nack(self, ack: bool):
2023-12-13 13:33:09 +00:00
if ack:
builder = self.frame_factory.build_arq_burst_ack
else:
builder = self.frame_factory.build_arq_burst_nack
frame = builder (
2023-12-13 13:59:22 +00:00
self.id, self.received_bytes,
2023-12-13 13:33:09 +00:00
self.speed_level, self.frames_per_burst, self.snr)
self.transmit_frame(frame)
2023-12-11 18:02:50 +00:00
2023-12-12 21:33:17 +00:00
def calibrate_speed_settings(self):
# TODO use some heuristics here
self.speed = self.speed
self.frames_per_burst = self.frames_per_burst
def on_info_received(self, frame):
2023-12-13 13:33:09 +00:00
self.received_data = bytearray(frame['total_length'])
self.received_crc = frame['total_crc']
2023-12-12 21:33:17 +00:00
self.dx_snr = frame['snr']
self.calibrate_speed_settings()
2023-12-13 13:33:09 +00:00
self.set_modem_decode_modes(None)
2023-12-13 13:59:22 +00:00
2023-12-13 13:33:09 +00:00
self.event_info_received.set()
2023-12-12 21:33:17 +00:00
2023-12-11 18:02:50 +00:00
def on_data_received(self, frame):
2023-12-05 14:40:04 +00:00
if self.state != self.STATE_WAITING_DATA:
2023-12-09 12:28:32 +00:00
raise RuntimeError(f"ARQ Session: Received data while in state {self.state}, expected {self.STATE_WAITING_DATA}")
2023-12-13 13:33:09 +00:00
2023-12-13 13:59:22 +00:00
self.received_frame = frame
2023-12-05 14:40:04 +00:00
self.event_data_received.set()
2023-12-13 13:33:09 +00:00
def process_incoming_data(self):
if self.received_frame['offset'] != self.received_bytes:
self.logger.info(f"Discarding data frame", frame=self.frame_received)
return False
self.received_data[self.received_frame['offset']:] = self.received_frame['data']
self.received_bytes += len(self.received_frame['data'])
return True
2023-12-12 21:05:32 +00:00
def on_burst_ack_received(self, ack):
2023-12-05 14:40:04 +00:00
self.event_transfer_ack_received.set()
self.speed_level = ack['speed_level']
2023-12-12 21:05:32 +00:00
def on_burst_nack_received(self, nack):
2023-12-05 14:40:04 +00:00
self.speed_level = nack['speed_level']
def on_disconnect_received(self):
self.abort()
def abort(self):
self.state = self.STATE_DISCONNECTED