2023-12-05 14:40:04 +00:00
|
|
|
import threading
|
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-19 14:01:08 +00:00
|
|
|
from enum import Enum
|
2024-01-15 15:04:11 +00:00
|
|
|
import time
|
2024-01-20 12:52:35 +00:00
|
|
|
|
2023-12-19 14:01:08 +00:00
|
|
|
class IRS_State(Enum):
|
|
|
|
NEW = 0
|
|
|
|
OPEN_ACK_SENT = 1
|
|
|
|
INFO_ACK_SENT = 2
|
|
|
|
BURST_REPLY_SENT = 3
|
|
|
|
ENDED = 4
|
|
|
|
FAILED = 5
|
2023-12-20 10:28:06 +00:00
|
|
|
ABORTED = 6
|
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-30 21:44:18 +00:00
|
|
|
TIMEOUT_CONNECT = 55 #14.2
|
2024-03-24 18:30:56 +00:00
|
|
|
TIMEOUT_DATA = 120
|
2023-12-05 14:40:04 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
STATE_TRANSITION = {
|
2023-12-19 14:01:08 +00:00
|
|
|
IRS_State.NEW: {
|
2023-12-14 16:29:04 +00:00
|
|
|
FRAME_TYPE.ARQ_SESSION_OPEN.value : 'send_open_ack',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
2023-12-14 16:29:04 +00:00
|
|
|
},
|
2023-12-19 14:01:08 +00:00
|
|
|
IRS_State.OPEN_ACK_SENT: {
|
2023-12-14 16:29:04 +00:00
|
|
|
FRAME_TYPE.ARQ_SESSION_OPEN.value: 'send_open_ack',
|
|
|
|
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
},
|
2023-12-19 14:01:08 +00:00
|
|
|
IRS_State.INFO_ACK_SENT: {
|
2023-12-14 16:29:04 +00:00
|
|
|
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
|
|
|
|
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
},
|
2023-12-19 14:01:08 +00:00
|
|
|
IRS_State.BURST_REPLY_SENT: {
|
2023-12-14 16:29:04 +00:00
|
|
|
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
},
|
2023-12-19 22:01:18 +00:00
|
|
|
IRS_State.ENDED: {
|
|
|
|
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
|
|
|
|
2023-12-19 22:01:18 +00:00
|
|
|
},
|
2023-12-20 11:26:28 +00:00
|
|
|
IRS_State.FAILED: {
|
|
|
|
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
|
2023-12-21 14:05:22 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
|
2023-12-20 11:26:28 +00:00
|
|
|
},
|
2023-12-30 20:47:16 +00:00
|
|
|
IRS_State.ABORTED: {
|
2024-01-04 09:01:29 +00:00
|
|
|
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack',
|
|
|
|
FRAME_TYPE.ARQ_SESSION_OPEN.value: 'send_open_ack',
|
|
|
|
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
|
|
|
|
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
|
2023-12-30 20:47:16 +00:00
|
|
|
},
|
2023-12-14 16:29:04 +00:00
|
|
|
}
|
|
|
|
|
2023-12-15 23:51:57 +00:00
|
|
|
def __init__(self, config: dict, modem, dxcall: str, session_id: int):
|
|
|
|
super().__init__(config, modem, dxcall)
|
2023-12-05 18:01:48 +00:00
|
|
|
|
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-19 14:01:08 +00:00
|
|
|
self.state = IRS_State.NEW
|
2024-01-15 15:04:11 +00:00
|
|
|
self.state_enum = IRS_State # needed for access State enum from outside
|
2023-12-05 14:40:04 +00:00
|
|
|
|
2024-01-21 19:34:01 +00:00
|
|
|
self.type_byte = None
|
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
|
|
|
|
|
2024-03-24 20:39:44 +00:00
|
|
|
self.maximum_bandwidth = 0
|
|
|
|
|
2023-12-28 21:27:49 +00:00
|
|
|
self.abort = False
|
2023-12-14 21:53:32 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
def all_data_received(self):
|
2023-12-16 16:42:51 +00:00
|
|
|
return self.total_length == self.received_bytes
|
2023-12-13 13:33:09 +00:00
|
|
|
|
2023-12-18 12:56:49 +00:00
|
|
|
def final_crc_matches(self) -> bool:
|
2024-03-24 19:07:18 +00:00
|
|
|
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):
|
2023-12-19 22:32:04 +00:00
|
|
|
self.event_frame_received.clear()
|
2023-12-15 13:56:35 +00:00
|
|
|
self.transmit_frame(frame, mode)
|
2023-12-14 16:57:58 +00:00
|
|
|
self.log(f"Waiting {timeout} seconds...")
|
2023-12-17 11:54:25 +00:00
|
|
|
if not self.event_frame_received.wait(timeout):
|
2023-12-14 16:57:58 +00:00
|
|
|
self.log("Timeout waiting for ISS. Session failed.")
|
2024-02-18 14:06:13 +00:00
|
|
|
self.transmission_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,
|
2024-01-15 15:04:11 +00:00
|
|
|
args = [frame, timeout, mode], daemon=True)
|
2023-12-14 16:29:04 +00:00
|
|
|
thread_wait.start()
|
|
|
|
|
|
|
|
def send_open_ack(self, open_frame):
|
2024-03-24 20:39:44 +00:00
|
|
|
self.maximum_bandwidth = open_frame['maximum_bandwidth']
|
|
|
|
# check for maximum bandwidth. If ISS bandwidth is higher than own, then use own
|
|
|
|
if open_frame['maximum_bandwidth'] > self.config['MODEM']['maximum_bandwidth']:
|
|
|
|
self.maximum_bandwidth = self.config['MODEM']['maximum_bandwidth']
|
|
|
|
|
|
|
|
|
2024-01-04 19:55:33 +00:00
|
|
|
self.event_manager.send_arq_session_new(
|
|
|
|
False, self.id, self.dxcall, 0, self.state.name)
|
2023-12-14 16:29:04 +00:00
|
|
|
ack_frame = self.frame_factory.build_arq_session_open_ack(
|
|
|
|
self.id,
|
|
|
|
self.dxcall,
|
|
|
|
self.version,
|
2024-02-24 20:49:53 +00:00
|
|
|
self.snr, flag_abort=self.abort)
|
2023-12-16 09:28:30 +00:00
|
|
|
self.launch_transmit_and_wait(ack_frame, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling)
|
2024-01-04 09:01:29 +00:00
|
|
|
if not self.abort:
|
|
|
|
self.set_state(IRS_State.OPEN_ACK_SENT)
|
2024-01-21 19:34:01 +00:00
|
|
|
return None, None
|
2023-12-14 16:29:04 +00:00
|
|
|
|
|
|
|
def send_info_ack(self, info_frame):
|
|
|
|
# Get session info from ISS
|
|
|
|
self.received_data = bytearray(info_frame['total_length'])
|
2023-12-16 16:42:51 +00:00
|
|
|
self.total_length = info_frame['total_length']
|
2023-12-14 16:29:04 +00:00
|
|
|
self.total_crc = info_frame['total_crc']
|
|
|
|
self.dx_snr.append(info_frame['snr'])
|
2024-01-21 19:34:01 +00:00
|
|
|
self.type_byte = info_frame['type']
|
2023-12-14 16:29:04 +00:00
|
|
|
|
2024-02-25 20:23:15 +00:00
|
|
|
self.calibrate_speed_settings()
|
|
|
|
|
2023-12-18 12:56:49 +00:00
|
|
|
self.log(f"New transfer of {self.total_length} bytes")
|
2023-12-29 18:29:30 +00:00
|
|
|
self.event_manager.send_arq_session_new(False, self.id, self.dxcall, self.total_length, self.state.name)
|
2023-12-18 12:56:49 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
info_ack = self.frame_factory.build_arq_session_info_ack(
|
2024-02-24 20:49:53 +00:00
|
|
|
self.id, self.total_crc, self.snr,
|
2023-12-28 21:27:49 +00:00
|
|
|
self.speed_level, self.frames_per_burst, flag_abort=self.abort)
|
2023-12-16 09:28:30 +00:00
|
|
|
self.launch_transmit_and_wait(info_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling)
|
2024-01-04 09:01:29 +00:00
|
|
|
if not self.abort:
|
|
|
|
self.set_state(IRS_State.INFO_ACK_SENT)
|
2024-01-21 19:34:01 +00:00
|
|
|
return None, None
|
2023-12-15 15:22:38 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
def process_incoming_data(self, frame):
|
|
|
|
if frame['offset'] != self.received_bytes:
|
2023-12-18 12:56:49 +00:00
|
|
|
self.log(f"Discarding data offset {frame['offset']}")
|
2023-12-13 13:33:09 +00:00
|
|
|
return False
|
|
|
|
|
2023-12-16 17:04:04 +00:00
|
|
|
remaining_data_length = self.total_length - 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-13 21:25:22 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
self.received_data[frame['offset']:] = data_part
|
|
|
|
self.received_bytes += len(data_part)
|
2023-12-18 12:56:49 +00:00
|
|
|
self.log(f"Received {self.received_bytes}/{self.total_length} bytes")
|
2023-12-19 14:35:07 +00:00
|
|
|
self.event_manager.send_arq_session_progress(
|
2024-02-27 21:39:45 +00:00
|
|
|
False, self.id, self.dxcall, self.received_bytes, self.total_length, self.state.name, self.calculate_session_statistics(self.received_bytes, self.total_length))
|
2023-12-13 21:25:22 +00:00
|
|
|
|
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)
|
2024-02-24 20:49:53 +00:00
|
|
|
# update statistics
|
2024-02-27 21:39:45 +00:00
|
|
|
self.update_histograms(self.received_bytes, self.total_length)
|
2024-02-24 20:49:53 +00:00
|
|
|
|
2023-12-14 16:29:04 +00:00
|
|
|
if not self.all_data_received():
|
2024-02-22 20:15:43 +00:00
|
|
|
self.calibrate_speed_settings(burst_frame=burst_frame)
|
2023-12-20 15:43:08 +00:00
|
|
|
ack = self.frame_factory.build_arq_burst_ack(
|
2024-02-22 14:05:54 +00:00
|
|
|
self.id,
|
|
|
|
self.received_bytes,
|
|
|
|
self.speed_level,
|
|
|
|
self.frames_per_burst,
|
2024-02-24 20:49:53 +00:00
|
|
|
self.snr,
|
2024-02-22 20:15:43 +00:00
|
|
|
flag_abort=self.abort
|
2024-02-22 14:05:54 +00:00
|
|
|
)
|
2024-01-05 15:25:14 +00:00
|
|
|
|
2023-12-19 14:01:08 +00:00
|
|
|
self.set_state(IRS_State.BURST_REPLY_SENT)
|
2023-12-19 16:19:12 +00:00
|
|
|
self.launch_transmit_and_wait(ack, self.TIMEOUT_DATA, mode=FREEDV_MODE.signalling)
|
2024-01-21 19:34:01 +00:00
|
|
|
return None, None
|
2023-12-14 08:07:46 +00:00
|
|
|
|
2023-12-18 12:56:49 +00:00
|
|
|
if self.final_crc_matches():
|
2023-12-14 16:29:04 +00:00
|
|
|
self.log("All data received successfully!")
|
2023-12-20 15:43:08 +00:00
|
|
|
ack = self.frame_factory.build_arq_burst_ack(self.id,
|
|
|
|
self.received_bytes,
|
|
|
|
self.speed_level,
|
|
|
|
self.frames_per_burst,
|
2024-02-24 20:49:53 +00:00
|
|
|
self.snr,
|
2023-12-20 15:43:08 +00:00
|
|
|
flag_final=True,
|
|
|
|
flag_checksum=True)
|
2023-12-17 11:54:25 +00:00
|
|
|
self.transmit_frame(ack, mode=FREEDV_MODE.signalling)
|
2023-12-19 16:19:12 +00:00
|
|
|
self.log("ACK sent")
|
2024-01-15 15:04:11 +00:00
|
|
|
self.session_ended = time.time()
|
2023-12-19 14:01:08 +00:00
|
|
|
self.set_state(IRS_State.ENDED)
|
2023-12-19 14:35:07 +00:00
|
|
|
self.event_manager.send_arq_session_finished(
|
2024-02-27 21:39:45 +00:00
|
|
|
False, self.id, self.dxcall, True, self.state.name, data=self.received_data, statistics=self.calculate_session_statistics(self.received_bytes, self.total_length))
|
2024-01-21 19:34:01 +00:00
|
|
|
|
|
|
|
return self.received_data, self.type_byte
|
2023-12-14 16:29:04 +00:00
|
|
|
else:
|
2023-12-20 15:43:08 +00:00
|
|
|
|
|
|
|
ack = self.frame_factory.build_arq_burst_ack(self.id,
|
|
|
|
self.received_bytes,
|
|
|
|
self.speed_level,
|
|
|
|
self.frames_per_burst,
|
2024-02-24 20:49:53 +00:00
|
|
|
self.snr,
|
2023-12-20 15:43:08 +00:00
|
|
|
flag_final=True,
|
|
|
|
flag_checksum=False)
|
|
|
|
self.transmit_frame(ack, mode=FREEDV_MODE.signalling)
|
2023-12-14 16:29:04 +00:00
|
|
|
self.log("CRC fail at the end of transmission!")
|
2024-02-22 20:15:43 +00:00
|
|
|
return self.transmission_failed()
|
|
|
|
|
|
|
|
def calibrate_speed_settings(self, burst_frame=None):
|
|
|
|
if burst_frame:
|
|
|
|
received_speed_level = burst_frame['speed_level']
|
|
|
|
else:
|
|
|
|
received_speed_level = 0
|
2023-12-14 08:07:46 +00:00
|
|
|
|
2024-02-24 20:49:53 +00:00
|
|
|
latest_snr = self.snr if self.snr else -10
|
2024-03-24 20:39:44 +00:00
|
|
|
appropriate_speed_level = self.get_appropriate_speed_level(latest_snr, self.maximum_bandwidth)
|
2024-02-22 14:05:54 +00:00
|
|
|
modes_to_decode = {}
|
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
# Log the latest SNR, current, appropriate speed levels, and the previous speed level
|
2024-02-22 14:05:54 +00:00
|
|
|
self.log(
|
2024-02-22 20:15:43 +00:00
|
|
|
f"Latest SNR: {latest_snr}, Current Speed Level: {self.speed_level}, Appropriate Speed Level: {appropriate_speed_level}, Previous Speed Level: {self.previous_speed_level}",
|
2024-02-22 14:05:54 +00:00
|
|
|
isWarning=True)
|
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
# Adjust the speed level by one step towards the appropriate level, if needed
|
2024-02-22 14:30:21 +00:00
|
|
|
if appropriate_speed_level > self.speed_level and self.speed_level < len(self.SPEED_LEVEL_DICT) - 1:
|
2024-02-22 20:49:57 +00:00
|
|
|
# we need to ensure, the received data is equal to our speed level before changing it
|
2024-02-22 20:15:43 +00:00
|
|
|
if received_speed_level == self.speed_level:
|
|
|
|
self.speed_level += 1
|
2024-02-22 14:30:21 +00:00
|
|
|
elif appropriate_speed_level < self.speed_level and self.speed_level > 0:
|
2024-02-22 20:49:57 +00:00
|
|
|
# we need to ensure, the received data is equal to our speed level before changing it
|
2024-02-22 20:15:43 +00:00
|
|
|
if received_speed_level == self.speed_level:
|
|
|
|
self.speed_level -= 1
|
2024-02-22 14:46:15 +00:00
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
# Always decode the current mode
|
2024-02-22 14:46:15 +00:00
|
|
|
current_mode = self.get_mode_by_speed_level(self.speed_level).value
|
|
|
|
modes_to_decode[current_mode] = True
|
2024-02-22 14:30:21 +00:00
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
# Decode the previous speed level mode
|
|
|
|
if self.previous_speed_level != self.speed_level:
|
|
|
|
previous_mode = self.get_mode_by_speed_level(self.previous_speed_level).value
|
2024-02-22 14:46:15 +00:00
|
|
|
modes_to_decode[previous_mode] = True
|
2024-02-22 20:15:43 +00:00
|
|
|
self.previous_speed_level = self.speed_level # Update the previous speed level
|
2024-02-22 14:05:54 +00:00
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
self.log(f"Modes to Decode: {list(modes_to_decode.keys())}", isWarning=True)
|
|
|
|
# Apply the new decode mode based on the updated and previous speed levels
|
2024-02-22 14:05:54 +00:00
|
|
|
self.modem.demodulator.set_decode_mode(modes_to_decode)
|
|
|
|
|
2024-02-22 20:15:43 +00:00
|
|
|
return self.speed_level
|
2023-12-13 22:37:40 +00:00
|
|
|
|
2023-12-28 21:27:49 +00:00
|
|
|
def abort_transmission(self):
|
2024-03-24 19:07:18 +00:00
|
|
|
self.log("Aborting transmission... setting abort flag")
|
2023-12-28 21:27:49 +00:00
|
|
|
self.abort = True
|
2023-12-21 14:05:22 +00:00
|
|
|
|
|
|
|
def send_stop_ack(self, stop_frame):
|
|
|
|
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)
|
2023-12-25 12:26:51 +00:00
|
|
|
self.set_state(IRS_State.ABORTED)
|
2024-02-22 15:03:28 +00:00
|
|
|
self.states.setARQ(False)
|
2023-12-25 12:26:51 +00:00
|
|
|
self.event_manager.send_arq_session_finished(
|
2024-02-27 21:39:45 +00:00
|
|
|
False, self.id, self.dxcall, False, self.state.name, statistics=self.calculate_session_statistics(self.received_bytes, self.total_length))
|
2024-02-18 14:06:13 +00:00
|
|
|
return None, None
|
|
|
|
|
|
|
|
def transmission_failed(self, irs_frame=None):
|
|
|
|
# final function for failed transmissions
|
|
|
|
self.session_ended = time.time()
|
|
|
|
self.set_state(IRS_State.FAILED)
|
2024-03-24 19:07:18 +00:00
|
|
|
self.log("Transmission failed!")
|
2024-02-27 21:39:45 +00:00
|
|
|
self.event_manager.send_arq_session_finished(True, self.id, self.dxcall,False, self.state.name, statistics=self.calculate_session_statistics(self.received_bytes, self.total_length))
|
2024-02-18 14:06:13 +00:00
|
|
|
self.states.setARQ(False)
|
|
|
|
return None, None
|