adjusted arq timeouts...

This commit is contained in:
DJ2LS 2023-10-31 14:00:03 +01:00
parent e445fbb3a3
commit 3f49b63930
4 changed files with 60 additions and 32 deletions

View file

@ -56,10 +56,16 @@ class DATA:
self.length_sig0_frame = 14 self.length_sig0_frame = 14
self.length_sig1_frame = 14 self.length_sig1_frame = 14
# duration of signalling frame # duration of frames
self.duration_sig0_frame = 2.3 self.duration_datac4 = 5.17
self.duration_sig1_frame = 2.3 self.duration_datac13 = 2.0
self.longest_duration = 5.8 # datac5 self.duration_datac1 = 4.18
self.duration_datac3 = 3.19
self.duration_sig0_frame = self.duration_datac13
self.duration_sig1_frame = self.duration_datac13
self.longest_duration = self.duration_datac4
# hold session id # hold session id
self.session_id = bytes(1) self.session_id = bytes(1)
@ -123,7 +129,7 @@ class DATA:
# List for minimum SNR operating level for the corresponding mode in self.mode_list # List for minimum SNR operating level for the corresponding mode in self.mode_list
self.snr_list_low_bw = [-100] self.snr_list_low_bw = [-100]
# List for time to wait for corresponding mode in seconds # List for time to wait for corresponding mode in seconds
self.time_list_low_bw = [6 + self.duration_sig0_frame + 1] self.time_list_low_bw = [self.duration_datac4]
# --------------------- HIGH BANDWIDTH # --------------------- HIGH BANDWIDTH
@ -139,7 +145,7 @@ class DATA:
# test with 6,7 --> caused sometimes a frame timeout if ack frame takes longer # test with 6,7 --> caused sometimes a frame timeout if ack frame takes longer
# TODO Need to check why ACK frames needs more time # TODO Need to check why ACK frames needs more time
# TODO Adjust these times # TODO Adjust these times
self.time_list_high_bw = [6 + self.duration_sig0_frame + 1, 6 + self.duration_sig0_frame + 1, 6 + self.duration_sig0_frame + 1] self.time_list_high_bw = [self.duration_datac4, self.duration_datac3, self.duration_datac1]
# -------------- AVAILABLE MODES END----------- # -------------- AVAILABLE MODES END-----------
# Mode list for selecting between low bandwidth ( 500Hz ) and modes with higher bandwidth # Mode list for selecting between low bandwidth ( 500Hz ) and modes with higher bandwidth
@ -566,11 +572,7 @@ class DATA:
if ModemParam.channel_busy: if ModemParam.channel_busy:
self.channel_busy_handler() self.channel_busy_handler()
# reset burst timeout in case we had to wait too long
self.burst_last_received = time.time() + self.channel_busy_timeout + 8
# Transmit frame # Transmit frame
# TODO Do we have to send , self.send_ident_frame(False) ?
# self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0)
self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0) self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0)
def send_retransmit_request_frame(self) -> None: def send_retransmit_request_frame(self) -> None:
@ -614,7 +616,7 @@ class DATA:
# reset burst timeout in case we had to wait too long # reset burst timeout in case we had to wait too long
self.burst_last_received = time.time() self.burst_last_received = time.time()
def send_burst_nack_frame_watchdog(self, snr: bytes, tx_n_frames_per_burst) -> None: def send_burst_nack_frame_watchdog(self, tx_n_frames_per_burst) -> None:
"""Build and send NACK frame for watchdog timeout""" """Build and send NACK frame for watchdog timeout"""
# increment nack counter for transmission stats # increment nack counter for transmission stats
@ -628,7 +630,7 @@ class DATA:
nack_frame = bytearray(self.length_sig1_frame) nack_frame = bytearray(self.length_sig1_frame)
nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value]) nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value])
nack_frame[1:2] = self.session_id nack_frame[1:2] = self.session_id
nack_frame[2:3] = helpers.snr_to_bytes(snr) nack_frame[2:3] = helpers.snr_to_bytes(0)
nack_frame[3:4] = bytes([int(self.speed_level)]) nack_frame[3:4] = bytes([int(self.speed_level)])
nack_frame[4:5] = bytes([int(tx_n_frames_per_burst)]) nack_frame[4:5] = bytes([int(tx_n_frames_per_burst)])
nack_frame[5:9] = len(ARQ.rx_frame_buffer).to_bytes(4, byteorder="big") nack_frame[5:9] = len(ARQ.rx_frame_buffer).to_bytes(4, byteorder="big")
@ -649,11 +651,6 @@ class DATA:
disconnection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_CLOSE.value]) disconnection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_CLOSE.value])
disconnection_frame[1:2] = self.session_id disconnection_frame[1:2] = self.session_id
disconnection_frame[2:5] = Station.dxcallsign_crc disconnection_frame[2:5] = Station.dxcallsign_crc
# TODO Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign)
# self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.sig0.value, copies=5, repeat_delay=0)
# TODO We need to add the ident frame feature with a seperate PR after publishing latest protocol
# TODO We need to wait some time between last arq related signalling frame and ident frame
# TODO Maybe about 500ms - 1500ms to avoid confusion and too much PTT toggles
# wait if we have a channel busy condition # wait if we have a channel busy condition
if ModemParam.channel_busy: if ModemParam.channel_busy:
@ -809,8 +806,12 @@ class DATA:
): ):
self.arq_calculate_speed_level(snr) self.arq_calculate_speed_level(snr)
self.data_channel_last_received = int(time.time()) + 6 + 6 # TIMING TEST
self.burst_last_received = int(time.time()) + 6 + 6 #self.data_channel_last_received = int(time.time()) + 6 + 6
#self.burst_last_received = int(time.time()) + 6 + 6
self.data_channel_last_received = int(time.time())
self.burst_last_received = int(time.time())
# Create and send ACK frame # Create and send ACK frame
self.log.info("[Modem] ARQ | RX | SENDING ACK", finished=ARQ.arq_seconds_until_finish, self.log.info("[Modem] ARQ | RX | SENDING ACK", finished=ARQ.arq_seconds_until_finish,
bytesperminute=ARQ.bytes_per_minute) bytesperminute=ARQ.bytes_per_minute)
@ -2393,6 +2394,7 @@ class DATA:
) )
# Reset data_channel/burst timestamps # Reset data_channel/burst timestamps
# TIMING TEST
self.data_channel_last_received = int(time.time()) self.data_channel_last_received = int(time.time())
self.burst_last_received = int(time.time() + 10) # we might need some more time so lets increase this self.burst_last_received = int(time.time() + 10) # we might need some more time so lets increase this
@ -2441,7 +2443,9 @@ class DATA:
# set start of transmission for our statistics # set start of transmission for our statistics
self.rx_start_of_transmission = time.time() self.rx_start_of_transmission = time.time()
# TIMING TEST
# Reset data_channel/burst timestamps once again for avoiding running into timeout # Reset data_channel/burst timestamps once again for avoiding running into timeout
# and therefore sending a NACK
self.data_channel_last_received = int(time.time()) self.data_channel_last_received = int(time.time())
self.burst_last_received = int(time.time() + 10) # we might need some more time so lets increase this self.burst_last_received = int(time.time() + 10) # we might need some more time so lets increase this
@ -2783,6 +2787,8 @@ class DATA:
else: else:
self.enqueue_frame_for_tx([beacon_frame], c2_mode=FREEDV_MODE.sig0.value, copies=1, self.enqueue_frame_for_tx([beacon_frame], c2_mode=FREEDV_MODE.sig0.value, copies=1,
repeat_delay=0) repeat_delay=0)
if Modem.transmit_morse_identifier:
modem.MODEM_TRANSMIT_QUEUE.put(["morse", 1, 0, self.mycallsign])
self.beacon_interval_timer = time.time() + self.beacon_interval self.beacon_interval_timer = time.time() + self.beacon_interval
while ( while (
@ -2860,8 +2866,7 @@ class DATA:
self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value)
else: else:
self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.sig0.value, copies=1, repeat_delay=0) self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.sig0.value, copies=1, repeat_delay=0)
if Modem.transmit_morse_identifier:
modem.MODEM_TRANSMIT_QUEUE.put(["morse", 1, 0, self.mycallsign])
def received_cq(self, data_in: bytes) -> None: def received_cq(self, data_in: bytes) -> None:
""" """
@ -3329,10 +3334,18 @@ class DATA:
if frames_left == 0: if frames_left == 0:
frames_left = 1 frames_left = 1
timeout = self.burst_last_received + (self.time_list[self.speed_level] * frames_left) # timeout is reached, if we didnt receive data, while we waited
# for the corresponding data frame + the transmitted signalling frame of ack/nack
# + a small offset of about 1 second
timeout = self.burst_last_received + (self.time_list[self.speed_level] * frames_left) + self.duration_sig0_frame + self.channel_busy_timeout + 1
# TODO Enable this for development # TODO Enable this for development
# print(f"timeout expected in:{round(timeout - time.time())} | frames left: {frames_left} of {self.rx_n_frames_per_burst} | speed level: {self.speed_level}") print(f"timeout expected in:{round(timeout - time.time())} | frames left: {frames_left} of {self.rx_n_frames_per_burst} | speed level: {self.speed_level}")
if timeout <= time.time() or modem_error_state: # if timeout is expired, but we are receiving codec2 data,
# better wait some more time because data might be important for us
# reason for this situation can be delays on IRS and ISS, maybe because both had a busy channel condition.
# Nevertheless, we need to keep timeouts short for efficiency
if timeout <= time.time() or modem_error_state and not ModemParam.is_codec2_traffic and not Modem.transmitting:
self.log.warning( self.log.warning(
"[Modem] Burst decoding error or timeout", "[Modem] Burst decoding error or timeout",
attempt=self.n_retries_per_burst, attempt=self.n_retries_per_burst,
@ -3343,7 +3356,7 @@ class DATA:
print( print(
f"frames_per_burst {self.rx_n_frame_of_burst} / {self.rx_n_frames_per_burst}, Repeats: {self.burst_rpt_counter} Nones: {ARQ.rx_burst_buffer.count(None)}") f"frames_per_burst {self.rx_n_frame_of_burst} / {self.rx_n_frames_per_burst}, Repeats: {self.burst_rpt_counter} Nones: {ARQ.rx_burst_buffer.count(None)}")
# check if we have N frames per burst > 1
if self.rx_n_frames_per_burst > 1 and self.burst_rpt_counter < 3 and ARQ.rx_burst_buffer.count(None) > 0: if self.rx_n_frames_per_burst > 1 and self.burst_rpt_counter < 3 and ARQ.rx_burst_buffer.count(None) > 0:
# reset self.burst_last_received # reset self.burst_last_received
self.burst_last_received = time.time() + self.time_list[self.speed_level] * frames_left self.burst_last_received = time.time() + self.time_list[self.speed_level] * frames_left
@ -3352,8 +3365,8 @@ class DATA:
else: else:
# reset self.burst_last_received # reset self.burst_last_received counter
self.burst_last_received = time.time() + self.time_list[self.speed_level] self.burst_last_received = time.time()
# reduce speed level if nack counter increased # reduce speed level if nack counter increased
self.frame_received_counter = 0 self.frame_received_counter = 0
@ -3374,13 +3387,14 @@ class DATA:
self.set_listening_modes(True, True, self.mode_list[self.speed_level]) self.set_listening_modes(True, True, self.mode_list[self.speed_level])
# TODO Does SNR make sense for NACK if we dont have an actual SNR information? # TODO Does SNR make sense for NACK if we dont have an actual SNR information?
self.send_burst_nack_frame_watchdog(0, tx_n_frames_per_burst) self.send_burst_nack_frame_watchdog(tx_n_frames_per_burst)
# Update data_channel timestamp # Update data_channel timestamp
# TODO Disabled this one for testing. # TODO Disabled this one for testing.
# self.data_channel_last_received = time.time() # self.data_channel_last_received = time.time()
self.n_retries_per_burst += 1 self.n_retries_per_burst += 1
else: else:
# debugging output
# print((self.data_channel_last_received + self.time_list[self.speed_level])-time.time()) # print((self.data_channel_last_received + self.time_list[self.speed_level])-time.time())
pass pass

View file

@ -265,7 +265,7 @@ if __name__ == "__main__":
"--morse", "--morse",
dest="transmit_morse_identifier", dest="transmit_morse_identifier",
action="store_true", action="store_true",
default=True, default=False,
help="Enable and send a morse identifier on disconnect an beacon", help="Enable and send a morse identifier on disconnect an beacon",
) )

View file

@ -80,6 +80,8 @@ class RF:
self.AUDIO_CHANNELS = 1 self.AUDIO_CHANNELS = 1
self.MODE = 0 self.MODE = 0
self.is_codec2_traffic_cooldown = 20
self.is_codec2_traffic_counter = 0
# Locking state for mod out so buffer will be filled before we can use it # Locking state for mod out so buffer will be filled before we can use it
# https://github.com/DJ2LS/FreeDATA/issues/127 # https://github.com/DJ2LS/FreeDATA/issues/127
# https://github.com/DJ2LS/FreeDATA/issues/99 # https://github.com/DJ2LS/FreeDATA/issues/99
@ -845,6 +847,8 @@ class RF:
:return: NIN from freedv instance :return: NIN from freedv instance
:rtype: int :rtype: int
""" """
nbytes = 0 nbytes = 0
try: try:
while self.stream.active: while self.stream.active:
@ -862,10 +866,11 @@ class RF:
# 10 error decoding == NACK # 10 error decoding == NACK
rx_status = codec2.api.freedv_get_rx_status(freedv) rx_status = codec2.api.freedv_get_rx_status(freedv)
if rx_status != 0: if rx_status not in [0]:
# we need to disable this if in testmode as its causing problems with FIFO it seems # we need to disable this if in testmode as its causing problems with FIFO it seems
if not TESTMODE: if not TESTMODE:
ModemParam.is_codec2_traffic = True ModemParam.is_codec2_traffic = True
self.is_codec2_traffic_counter = self.is_codec2_traffic_cooldown
if not ModemParam.channel_busy: if not ModemParam.channel_busy:
self.log.debug("[MDM] Setting channel_busy since codec2 data detected") self.log.debug("[MDM] Setting channel_busy since codec2 data detected")
ModemParam.channel_busy=True ModemParam.channel_busy=True
@ -877,6 +882,15 @@ class RF:
else: else:
ModemParam.is_codec2_traffic = False ModemParam.is_codec2_traffic = False
# decrement codec traffic counter for making state smoother
print(f"{mode_name}: {self.is_codec2_traffic_counter}")
if self.is_codec2_traffic_counter > 0:
self.is_codec2_traffic_counter -= 1
ModemParam.is_codec2_traffic = True
else:
ModemParam.is_codec2_traffic = False
if rx_status == 10: if rx_status == 10:
state_buffer.append(rx_status) state_buffer.append(rx_status)
@ -1357,7 +1371,7 @@ class RF:
ModemParam.channel_busy_slot[slot] = False ModemParam.channel_busy_slot[slot] = False
# increment slot # increment slot
slot += 1 slot += 1
if (addDelay): if addDelay:
# Limit delay counter to a maximum of 200. The higher this value, # Limit delay counter to a maximum of 200. The higher this value,
# the longer we will wait until releasing state # the longer we will wait until releasing state
ModemParam.channel_busy = True ModemParam.channel_busy = True

View file

@ -136,7 +136,7 @@ class TCIParam:
@dataclass @dataclass
class Modem: class Modem:
version = "0.11.2-alpha.1" version = "0.11.2-alpha.2"
host: str = "0.0.0.0" host: str = "0.0.0.0"
port: int = 3000 port: int = 3000
SOCKET_TIMEOUT: int = 1 # seconds SOCKET_TIMEOUT: int = 1 # seconds