FreeDATA/modem/arq_session_irs.py

176 lines
6 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-13 22:07:06 +00:00
import helpers
2023-12-14 16:29:04 +00:00
from modem_frametypes import FRAME_TYPE
2023-12-15 13:41:11 +00:00
from codec2 import FREEDV_MODE
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
2023-12-14 16:29:04 +00:00
STATE_NEW = 0
STATE_OPEN_ACK_SENT = 1
STATE_INFO_ACK_SENT = 2
STATE_BURST_REPLY_SENT = 3
STATE_ENDED = 4
STATE_FAILED = 5
2023-12-05 14:40:04 +00:00
RETRIES_CONNECT = 3
RETRIES_TRANSFER = 3 # we need to increase this
2023-12-05 14:40:04 +00:00
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-14 16:29:04 +00:00
STATE_TRANSITION = {
STATE_NEW: {
FRAME_TYPE.ARQ_SESSION_OPEN.value : 'send_open_ack',
},
STATE_OPEN_ACK_SENT: {
FRAME_TYPE.ARQ_SESSION_OPEN.value: 'send_open_ack',
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
},
STATE_INFO_ACK_SENT: {
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
},
STATE_BURST_REPLY_SENT: {
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
},
}
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-14 16:29:04 +00:00
self.dxcall = dxcall
2023-12-11 18:02:50 +00:00
self.version = 1
2023-12-05 14:40:04 +00:00
2023-12-14 16:29:04 +00:00
self.state = self.STATE_NEW
2023-12-05 14:40:04 +00:00
2023-12-14 16:29:04 +00:00
self.total_length = 0
self.total_crc = ''
2023-12-13 13:33:09 +00:00
self.received_data = None
self.received_bytes = 0
self.received_crc = None
2023-12-14 21:53:32 +00:00
self.transmitted_acks = 0
2023-12-05 14:40:04 +00:00
def set_modem_decode_modes(self, modes):
pass
2023-12-14 16:29:04 +00:00
def all_data_received(self):
2023-12-13 13:33:09 +00:00
return self.received_bytes == len(self.received_data)
2023-12-14 16:29:04 +00:00
def final_crc_check(self):
return self.total_crc == helpers.get_crc_32(bytes(self.received_data)).hex()
2023-12-13 22:07:06 +00:00
2023-12-15 13:56:35 +00:00
def transmit_and_wait(self, frame, timeout, mode):
self.transmit_frame(frame, mode)
2023-12-14 16:57:58 +00:00
self.log(f"Waiting {timeout} seconds...")
2023-12-14 16:29:04 +00:00
if not self.event_frame_received.wait(timeout):
2023-12-14 21:53:32 +00:00
# use case: data burst got lost, we want to send a NACK with updated speed level
if self.state in [self.STATE_BURST_REPLY_SENT, self.STATE_INFO_ACK_SENT]:
self.transmitted_acks = 0
self.calibrate_speed_settings()
self.send_burst_nack()
return
2023-12-14 16:57:58 +00:00
self.log("Timeout waiting for ISS. Session failed.")
2023-12-14 16:29:04 +00:00
self.set_state(self.STATE_FAILED)
2023-12-13 13:33:09 +00:00
2023-12-15 13:41:11 +00:00
def launch_transmit_and_wait(self, frame, timeout, mode):
2023-12-14 16:29:04 +00:00
thread_wait = threading.Thread(target = self.transmit_and_wait,
2023-12-15 13:41:11 +00:00
args = [frame, timeout, mode])
2023-12-14 16:29:04 +00:00
thread_wait.start()
def send_open_ack(self, open_frame):
ack_frame = self.frame_factory.build_arq_session_open_ack(
self.id,
self.dxcall,
self.version,
self.snr[0])
2023-12-15 13:41:11 +00:00
self.launch_transmit_and_wait(ack_frame, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.datac13)
2023-12-14 16:29:04 +00:00
self.set_state(self.STATE_OPEN_ACK_SENT)
def send_info_ack(self, info_frame):
# Get session info from ISS
self.received_data = bytearray(info_frame['total_length'])
self.total_crc = info_frame['total_crc']
self.dx_snr.append(info_frame['snr'])
2023-12-15 13:41:11 +00:00
self.calibrate_speed_settings()
2023-12-15 15:22:38 +00:00
self.set_modem_listening_modes(self.speed_level)
2023-12-14 16:29:04 +00:00
info_ack = self.frame_factory.build_arq_session_info_ack(
self.id, self.total_crc, self.snr[0],
self.speed_level, self.frames_per_burst)
2023-12-15 13:41:11 +00:00
self.launch_transmit_and_wait(info_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.datac13)
2023-12-14 16:29:04 +00:00
self.set_state(self.STATE_INFO_ACK_SENT)
2023-12-14 21:53:32 +00:00
def send_burst_nack(self):
self.calibrate_speed_settings()
2023-12-15 15:22:38 +00:00
self.set_modem_listening_modes(self.speed_level)
2023-12-14 21:53:32 +00:00
nack = self.frame_factory.build_arq_burst_ack(self.id, self.received_bytes, self.speed_level, self.frames_per_burst, self.snr[0])
self.transmit_and_wait(nack)
2023-12-15 15:22:38 +00:00
def set_modem_listening_modes(self, speed_level):
# TODO
# We want to set the modems listening modes somehow...
return
2023-12-14 21:53:32 +00:00
2023-12-14 16:29:04 +00:00
def process_incoming_data(self, frame):
if frame['offset'] != self.received_bytes:
self.logger.info(f"Discarding data frame due to wrong offset", frame=self.frame_received)
2023-12-13 13:33:09 +00:00
return False
2023-12-14 16:29:04 +00:00
remaining_data_length = len(self.received_data) - self.received_bytes
2023-12-13 22:07:06 +00:00
2023-12-14 16:29:04 +00:00
# Is this the last data part?
if remaining_data_length <= len(frame['data']):
# we only want the remaining length, not the entire frame data
data_part = frame['data'][:remaining_data_length]
2023-12-13 22:07:06 +00:00
else:
2023-12-14 16:29:04 +00:00
# we want the entire frame data
data_part = frame['data']
2023-12-14 16:29:04 +00:00
self.received_data[frame['offset']:] = data_part
self.received_bytes += len(data_part)
2023-12-13 15:56:11 +00:00
return True
2023-12-09 13:16:53 +00:00
2023-12-14 16:29:04 +00:00
def receive_data(self, burst_frame):
self.process_incoming_data(burst_frame)
2023-12-14 21:53:32 +00:00
self.calibrate_speed_settings()
2023-12-14 16:29:04 +00:00
ack = self.frame_factory.build_arq_burst_ack(
2023-12-13 13:59:22 +00:00
self.id, self.received_bytes,
2023-12-14 16:29:04 +00:00
self.speed_level, self.frames_per_burst, self.snr[0])
2023-12-11 18:02:50 +00:00
2023-12-14 16:29:04 +00:00
if not self.all_data_received():
2023-12-14 21:53:32 +00:00
# increase ack counter
self.transmitted_acks += 1
2023-12-14 16:29:04 +00:00
self.transmit_and_wait(ack)
self.set_state(self.STATE_BURST_REPLY_SENT)
return
2023-12-14 16:29:04 +00:00
if self.final_crc_check():
self.log("All data received successfully!")
self.transmit_frame(ack)
self.set_state(self.STATE_ENDED)
2023-12-14 16:29:04 +00:00
else:
self.log("CRC fail at the end of transmission!")
self.set_state(self.STATE_FAILED)
2023-12-12 21:33:17 +00:00
def calibrate_speed_settings(self):
2023-12-14 21:53:32 +00:00
# if we have two ACKS, then consider increasing speed level
if self.transmitted_acks >= 2:
self.transmitted_acks = 0
new_speed_level = min(self.speed_level + 1, len(self.SPEED_LEVEL_DICT) - 1)
2023-12-14 21:53:32 +00:00
# check first if the next mode supports the actual snr
if self.snr >= self.SPEED_LEVEL_DICT[new_speed_level]["min_snr"]:
self.speed_level = new_speed_level