From 0ad6deb3b4a757b483657d7e86398cd2248610c2 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:06:00 +0100 Subject: [PATCH 01/23] first run with improving arq code --- tnc/data_handler.py | 279 +++++++++++++++++++++----------------------- 1 file changed, 135 insertions(+), 144 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index e06af2d4..01a6844b 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -638,15 +638,6 @@ class DATA: # is intended for this station. data_in = bytes(data_in) - # TODO: this seems not to work anymore - # get received crc for different mycall ssids - # check if callsign ssid override - # _, mycallsign = helpers.check_callsign( - # self.mycallsign, data_in[2:5] - # ) - # attempt fixing this - mycallsign = self.mycallsign - # only process data if we are in ARQ and BUSY state else return to quit if not static.ARQ_STATE and static.TNC_STATE not in ["BUSY"]: self.log.warning("[TNC] wrong tnc state - dropping data", arq_state=static.ARQ_STATE, tnc_state=static.TNC_STATE) @@ -704,10 +695,10 @@ class DATA: # catch possible modem error which leads into false byteorder # modem possibly decodes too late - data then is pushed to buffer # which leads into wrong byteorder - # Lets put this in try/except so we are not crashing tnc as its hihgly experimental + # Lets put this in try/except so we are not crashing tnc as its highly experimental # This might only work for datac1 and datac3 try: - #area_of_interest = (modem.get_bytes_per_frame(self.mode_list[speed_level] - 1) -3) * 2 + # area_of_interest = (modem.get_bytes_per_frame(self.mode_list[speed_level] - 1) -3) * 2 if static.RX_FRAME_BUFFER.endswith(temp_burst_buffer[:246]) and len(temp_burst_buffer) >= 246: self.log.warning( "[TNC] ARQ | RX | wrong byteorder received - dropping data" @@ -719,7 +710,6 @@ class DATA: "[TNC] ARQ | RX | wrong byteorder check failed", e=e ) - # if frame buffer ends not with the current frame, we are going to append new data # if data already exists, we received the frame correctly, # but the ACK frame didn't receive its destination (ISS) @@ -737,10 +727,9 @@ class DATA: # temp_burst_buffer --> new data # search_area --> area where we want to search - - #data_mode = self.mode_list[self.speed_level] - #payload_per_frame = modem.get_bytes_per_frame(data_mode) - 2 - #search_area = payload_per_frame - 3 # (3 bytes arq frame header) + # data_mode = self.mode_list[self.speed_level] + # payload_per_frame = modem.get_bytes_per_frame(data_mode) - 2 + # search_area = payload_per_frame - 3 # (3 bytes arq frame header) search_area = 510 - 3 # (3 bytes arq frame header) search_position = len(static.RX_FRAME_BUFFER) - search_area @@ -786,9 +775,9 @@ class DATA: self.speed_level = new_speed_level else: self.log.info("[TNC] ARQ | increasing speed level not possible because of SNR limit", - given_snr=static.SNR, - needed_snr=self.snr_list[new_speed_level] - ) + given_snr=static.SNR, + needed_snr=self.snr_list[new_speed_level] + ) static.ARQ_SPEED_LEVEL = self.speed_level # Update modes we are listening to @@ -896,131 +885,7 @@ class DATA: # Check if data_frame_crc is equal with received crc if data_frame_crc == data_frame_crc_received: - - # transmittion duration - duration = time.time() - self.rx_start_of_transmission - self.calculate_transfer_rate_rx( - self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) - ) - self.log.info("[TNC] ARQ | RX | DATA FRAME SUCCESSFULLY RECEIVED", nacks=self.frame_nack_counter,bytesperminute=static.ARQ_BYTES_PER_MINUTE, total_bytes=static.TOTAL_BYTES, duration=duration) - - # Decompress the data frame - data_frame_decompressed = lzma.decompress(data_frame) - static.ARQ_COMPRESSION_FACTOR = len(data_frame_decompressed) / len( - data_frame - ) - data_frame = data_frame_decompressed - - self.transmission_uuid = str(uuid.uuid4()) - timestamp = int(time.time()) - - # Re-code data_frame in base64, UTF-8 for JSON UI communication. - base64_data = base64.b64encode(data_frame).decode("UTF-8") - - # check if RX_BUFFER isn't full - if not RX_BUFFER.full(): - # make sure we have always the correct buffer size - RX_BUFFER.maxsize = int(static.RX_BUFFER_SIZE) - else: - # if full, free space by getting an item - self.log.info( - "[TNC] ARQ | RX | RX_BUFFER FULL - dropping old data", - buffer_size=RX_BUFFER.qsize(), - maxsize=int(static.RX_BUFFER_SIZE) - ) - RX_BUFFER.get() - - # add item to RX_BUFFER - self.log.info( - "[TNC] ARQ | RX | saving data to rx buffer", - buffer_size=RX_BUFFER.qsize() + 1, - maxsize=RX_BUFFER.maxsize - ) - try: - RX_BUFFER.put( - [ - self.transmission_uuid, - timestamp, - static.DXCALLSIGN, - static.DXGRID, - base64_data, - ] - ) - except Exception as e: - # File "/usr/lib/python3.7/queue.py", line 133, in put - # if self.maxsize > 0 - # TypeError: '>' not supported between instances of 'str' and 'int' - # - # Occurs on Raspberry Pi and Python 3.7 - self.log.error( - "[TNC] ARQ | RX | error occurred when saving data!", - e=e, - uuid=self.transmission_uuid, - timestamp=timestamp, - dxcall=static.DXCALLSIGN, - dxgrid=static.DXGRID, - data=base64_data - ) - - if static.ARQ_SAVE_TO_FOLDER: - try: - self.save_data_to_folder( - self.transmission_uuid, - timestamp, - mycallsign, - static.DXCALLSIGN, - static.DXGRID, - data_frame - ) - except Exception as e: - self.log.error( - "[TNC] ARQ | RX | can't save file to folder", - e=e, - uuid=self.transmission_uuid, - timestamp=timestamp, - dxcall=static.DXCALLSIGN, - dxgrid=static.DXGRID, - data=base64_data - ) - - self.send_data_to_socket_queue( - freedata="tnc-message", - arq="transmission", - status="received", - uuid=self.transmission_uuid, - timestamp=timestamp, - mycallsign=str(mycallsign, "UTF-8"), - dxcallsign=str(static.DXCALLSIGN, "UTF-8"), - dxgrid=str(static.DXGRID, "UTF-8"), - data=base64_data, - irs=helpers.bool_to_string(self.is_IRS) - ) - - if static.ENABLE_STATS: - duration = time.time() - self.rx_start_of_transmission - self.stats.push(frame_nack_counter=self.frame_nack_counter, status="received", duration=duration) - - self.log.info( - "[TNC] ARQ | RX | SENDING DATA FRAME ACK", - snr=snr, - crc=data_frame_crc.hex(), - ) - - self.send_data_ack_frame(snr) - # Update statistics AFTER the frame ACK is sent - self.calculate_transfer_rate_rx( - self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) - ) - - self.log.info( - "[TNC] | RX | DATACHANNEL [" - + str(self.mycallsign, "UTF-8") - + "]<< >>[" - + str(static.DXCALLSIGN, "UTF-8") - + "]", - snr=snr, - ) - + self.arq_process_received_data_frame(data_frame, snr) else: self.send_data_to_socket_queue( freedata="tnc-message", @@ -1058,6 +923,132 @@ class DATA: # Finally cleanup our buffers and states, self.arq_cleanup() + def arq_process_received_data_frame(self, data_frame, snr): + """ + + + """ + # transmittion duration + duration = time.time() - self.rx_start_of_transmission + self.calculate_transfer_rate_rx( + self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) + ) + self.log.info("[TNC] ARQ | RX | DATA FRAME SUCCESSFULLY RECEIVED", nacks=self.frame_nack_counter, + bytesperminute=static.ARQ_BYTES_PER_MINUTE, total_bytes=static.TOTAL_BYTES, duration=duration) + + # Decompress the data frame + data_frame_decompressed = lzma.decompress(data_frame) + static.ARQ_COMPRESSION_FACTOR = len(data_frame_decompressed) / len( + data_frame + ) + data_frame = data_frame_decompressed + + self.transmission_uuid = str(uuid.uuid4()) + timestamp = int(time.time()) + + # Re-code data_frame in base64, UTF-8 for JSON UI communication. + base64_data = base64.b64encode(data_frame).decode("UTF-8") + + # check if RX_BUFFER isn't full + if not RX_BUFFER.full(): + # make sure we have always the correct buffer size + RX_BUFFER.maxsize = int(static.RX_BUFFER_SIZE) + else: + # if full, free space by getting an item + self.log.info( + "[TNC] ARQ | RX | RX_BUFFER FULL - dropping old data", + buffer_size=RX_BUFFER.qsize(), + maxsize=int(static.RX_BUFFER_SIZE) + ) + RX_BUFFER.get() + + # add item to RX_BUFFER + self.log.info( + "[TNC] ARQ | RX | saving data to rx buffer", + buffer_size=RX_BUFFER.qsize() + 1, + maxsize=RX_BUFFER.maxsize + ) + try: + RX_BUFFER.put( + [ + self.transmission_uuid, + timestamp, + static.DXCALLSIGN, + static.DXGRID, + base64_data, + ] + ) + except Exception as e: + # File "/usr/lib/python3.7/queue.py", line 133, in put + # if self.maxsize > 0 + # TypeError: '>' not supported between instances of 'str' and 'int' + # + # Occurs on Raspberry Pi and Python 3.7 + self.log.error( + "[TNC] ARQ | RX | error occurred when saving data!", + e=e, + uuid=self.transmission_uuid, + timestamp=timestamp, + dxcall=static.DXCALLSIGN, + dxgrid=static.DXGRID, + data=base64_data + ) + + if static.ARQ_SAVE_TO_FOLDER: + try: + self.save_data_to_folder( + self.transmission_uuid, + timestamp, + self.mycallsign, + static.DXCALLSIGN, + static.DXGRID, + data_frame + ) + except Exception as e: + self.log.error( + "[TNC] ARQ | RX | can't save file to folder", + e=e, + uuid=self.transmission_uuid, + timestamp=timestamp, + dxcall=static.DXCALLSIGN, + dxgrid=static.DXGRID, + data=base64_data + ) + + self.send_data_to_socket_queue( + freedata="tnc-message", + arq="transmission", + status="received", + uuid=self.transmission_uuid, + timestamp=timestamp, + mycallsign=str(self.mycallsign, "UTF-8"), + dxcallsign=str(static.DXCALLSIGN, "UTF-8"), + dxgrid=str(static.DXGRID, "UTF-8"), + data=base64_data, + irs=helpers.bool_to_string(self.is_IRS) + ) + + if static.ENABLE_STATS: + duration = time.time() - self.rx_start_of_transmission + self.stats.push(frame_nack_counter=self.frame_nack_counter, status="received", duration=duration) + + self.log.info( + "[TNC] ARQ | RX | SENDING DATA FRAME ACK") + + self.send_data_ack_frame(snr) + # Update statistics AFTER the frame ACK is sent + self.calculate_transfer_rate_rx( + self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) + ) + + self.log.info( + "[TNC] | RX | DATACHANNEL [" + + str(self.mycallsign, "UTF-8") + + "]<< >>[" + + str(static.DXCALLSIGN, "UTF-8") + + "]", + snr=snr, + ) def arq_transmit(self, data_out: bytes, mode: int, n_frames_per_burst: int): """ Transmit ARQ frame From ea2883a85a166d6dbba023b6171d577242067cb5 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:15:00 +0100 Subject: [PATCH 02/23] second run with improving arq code --- tnc/data_handler.py | 77 ++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 01a6844b..3efe173c 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -763,28 +763,11 @@ class DATA: and data_in.find(self.data_frame_eof) < 0 ): - self.frame_received_counter += 1 - # try increasing speed level only if we had two successful decodes - if self.frame_received_counter >= 2: - self.frame_received_counter = 0 - - # make sure new speed level isn't higher than available modes - new_speed_level = min(self.speed_level + 1, len(self.mode_list) - 1) - # check if actual snr is higher than minimum snr for next mode - if static.SNR >= self.snr_list[new_speed_level]: - self.speed_level = new_speed_level - else: - self.log.info("[TNC] ARQ | increasing speed level not possible because of SNR limit", - given_snr=static.SNR, - needed_snr=self.snr_list[new_speed_level] - ) - static.ARQ_SPEED_LEVEL = self.speed_level - - # Update modes we are listening to - self.set_listening_modes(False, True, self.mode_list[self.speed_level]) + self.arq_calculate_speed_level(snr) # Create and send ACK frame - self.log.info("[TNC] ARQ | RX | SENDING ACK", finished=static.ARQ_SECONDS_UNTIL_FINISH, bytesperminute=static.ARQ_BYTES_PER_MINUTE) + self.log.info("[TNC] ARQ | RX | SENDING ACK", finished=static.ARQ_SECONDS_UNTIL_FINISH, + bytesperminute=static.ARQ_BYTES_PER_MINUTE) self.send_burst_ack_frame(snr) # Reset n retries per burst counter @@ -809,7 +792,7 @@ class DATA: finished=static.ARQ_SECONDS_UNTIL_FINISH, irs=helpers.bool_to_string(self.is_IRS) ) - + elif rx_n_frame_of_burst == rx_n_frames_per_burst - 1: # We have "Nones" in our rx buffer, # Check if we received last frame of burst - this is an indicator for missed frames. @@ -826,7 +809,6 @@ class DATA: self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) ) - # Should never reach this point else: self.log.error( "[TNC] data_handler: Should not reach this point...", @@ -843,19 +825,7 @@ class DATA: # get total bytes per transmission information as soon we received a frame with a BOF if bof_position >= 0: - payload = static.RX_FRAME_BUFFER[ - bof_position + len(self.data_frame_bof): eof_position - ] - frame_length = int.from_bytes(payload[4:8], "big") # 4:8 4bytes - static.TOTAL_BYTES = frame_length - compression_factor = int.from_bytes(payload[8:9], "big") # 4:8 4bytes - # limit to max value of 255 - compression_factor = np.clip(compression_factor, 0, 255) - static.ARQ_COMPRESSION_FACTOR = compression_factor / 10 - self.calculate_transfer_rate_rx( - self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) - ) - + self.arq_extract_statistics_from_data_frame(bof_position, eof_position) if ( bof_position >= 0 and eof_position > 0 @@ -923,6 +893,43 @@ class DATA: # Finally cleanup our buffers and states, self.arq_cleanup() + def arq_extract_statistics_from_data_frame(self, bof_position, eof_position): + payload = static.RX_FRAME_BUFFER[ + bof_position + len(self.data_frame_bof): eof_position + ] + frame_length = int.from_bytes(payload[4:8], "big") # 4:8 4bytes + static.TOTAL_BYTES = frame_length + compression_factor = int.from_bytes(payload[8:9], "big") # 4:8 4bytes + # limit to max value of 255 + compression_factor = np.clip(compression_factor, 0, 255) + static.ARQ_COMPRESSION_FACTOR = compression_factor / 10 + self.calculate_transfer_rate_rx( + self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) + ) + + def arq_calculate_speed_level(self, snr): + self.frame_received_counter += 1 + # try increasing speed level only if we had two successful decodes + if self.frame_received_counter >= 2: + self.frame_received_counter = 0 + + # make sure new speed level isn't higher than available modes + new_speed_level = min(self.speed_level + 1, len(self.mode_list) - 1) + # check if actual snr is higher than minimum snr for next mode + if static.SNR >= self.snr_list[new_speed_level]: + self.speed_level = new_speed_level + else: + self.log.info("[TNC] ARQ | increasing speed level not possible because of SNR limit", + given_snr=static.SNR, + needed_snr=self.snr_list[new_speed_level] + ) + static.ARQ_SPEED_LEVEL = self.speed_level + + # Update modes we are listening to + self.set_listening_modes(False, True, self.mode_list[self.speed_level]) + + + def arq_process_received_data_frame(self, data_frame, snr): """ From 1e3314627b02d9b9bae29dc8edeef765e2d0ece8 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:24:37 +0100 Subject: [PATCH 03/23] third run with improving arq code --- tnc/data_handler.py | 71 +++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 3efe173c..cd2a4a56 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1492,28 +1492,28 @@ class DATA: """ # Only process data if we are in ARQ and BUSY state - if static.ARQ_STATE and static.TNC_STATE == "BUSY": - static.DXGRID = b'------' - helpers.add_to_heard_stations( - static.DXCALLSIGN, - static.DXGRID, - "DATA-CHANNEL", - static.SNR, - static.FREQ_OFFSET, - static.HAMLIB_FREQUENCY, - ) + if not static.ARQ_STATE or static.TNC_STATE != "BUSY": + return + static.DXGRID = b'------' + helpers.add_to_heard_stations( + static.DXCALLSIGN, + static.DXGRID, + "DATA-CHANNEL", + static.SNR, + static.FREQ_OFFSET, + static.HAMLIB_FREQUENCY, + ) - self.rpt_request_received = True - # Update data_channel timestamp - self.data_channel_last_received = int(time.time()) - self.rpt_request_buffer = [] + self.rpt_request_received = True + # Update data_channel timestamp + self.data_channel_last_received = int(time.time()) + self.rpt_request_buffer = [] - missing_area = bytes(data_in[3:12]) # 1:9 + missing_area = bytes(data_in[3:12]) # 1:9 - for i in range(0, 6, 2): - if not missing_area[i: i + 2].endswith(b"\x00\x00"): - missing = missing_area[i: i + 2] - self.rpt_request_buffer.insert(0, missing) + for i in range(0, 6, 2): + if not missing_area[i: i + 2].endswith(b"\x00\x00"): + self.rpt_request_buffer.insert(0, missing_area[i: i + 2]) ############################################################################################################ # ARQ SESSION HANDLER @@ -2167,7 +2167,7 @@ class DATA: self.mode_list = self.mode_list_high_bw self.time_list = self.time_list_high_bw self.snr_list = self.snr_list_high_bw - elif frametype == FR_TYPE.ARQ_DC_OPEN_W.value and static.LOW_BANDWIDTH_MODE: + elif frametype == FR_TYPE.ARQ_DC_OPEN_W.value: # ISS(w) <-> IRS(n) constellation = "ISS(w) <-> IRS(n)" self.received_LOW_BANDWIDTH_MODE = False @@ -2181,7 +2181,7 @@ class DATA: self.mode_list = self.mode_list_low_bw self.time_list = self.time_list_low_bw self.snr_list = self.snr_list_low_bw - elif frametype == FR_TYPE.ARQ_DC_OPEN_N.value and static.LOW_BANDWIDTH_MODE: + elif frametype == FR_TYPE.ARQ_DC_OPEN_N.value: # ISS(n) <-> IRS(n) constellation = "ISS(n) <-> IRS(n)" self.received_LOW_BANDWIDTH_MODE = True @@ -2459,17 +2459,25 @@ class DATA: snr=str(static.SNR), ) if static.RESPOND_TO_CALL: - ping_frame = bytearray(self.length_sig0_frame) - ping_frame[:1] = bytes([FR_TYPE.PING_ACK.value]) - ping_frame[1:4] = static.DXCALLSIGN_CRC - ping_frame[4:7] = static.MYCALLSIGN_CRC - ping_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) - ping_frame[13:14] = helpers.snr_to_bytes(static.SNR) + self.transmit_ping_ack() - if static.ENABLE_FSK: - self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) - else: - self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.datac0.value) + def transmit_ping_ack(self): + """ + + transmit a ping ack frame + called by def received_ping + """ + ping_frame = bytearray(self.length_sig0_frame) + ping_frame[:1] = bytes([FR_TYPE.PING_ACK.value]) + ping_frame[1:4] = static.DXCALLSIGN_CRC + ping_frame[4:7] = static.MYCALLSIGN_CRC + ping_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) + ping_frame[13:14] = helpers.snr_to_bytes(static.SNR) + + if static.ENABLE_FSK: + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) + else: + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.datac0.value) def received_ping_ack(self, data_in: bytes) -> None: """ @@ -3013,6 +3021,7 @@ class DATA: self.data_frame_ack_received = state def set_listening_modes(self, enable_sig0: bool, enable_sig1: bool, mode: int) -> None: + # sourcery skip: extract-duplicate-method """ Function for setting the data modes we are listening to for saving cpu power From bd496fae3f0af48b6090f93c07cfe920e93e40fd Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:27:06 +0100 Subject: [PATCH 04/23] disabled ctest for python 3.12-dev --- .github/workflows/ctest.yml | 2 +- tnc/data_handler.py | 29 ++++++++++------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index c671babd..fcba1b26 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -21,7 +21,7 @@ jobs: - python-version: "3.9" - python-version: "3.10" - python-version: "3.11" - - python-version: "3.12-dev" + #- python-version: "3.12-dev" steps: - uses: actions/checkout@v3 diff --git a/tnc/data_handler.py b/tnc/data_handler.py index cd2a4a56..be8ba810 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1066,8 +1066,6 @@ class DATA: n_frames_per_burst:int: """ - self.arq_file_transfer = True - # set signalling modes we want to listen to # we are in an ongoing arq transmission, so we don't need sig0 actually modem.RECEIVE_SIG0 = False @@ -1079,6 +1077,7 @@ class DATA: # save len of data_out to TOTAL_BYTES for our statistics --> kBytes # static.TOTAL_BYTES = round(len(data_out) / 1024, 2) static.TOTAL_BYTES = len(data_out) + self.arq_file_transfer = True frame_total_size = len(data_out).to_bytes(4, byteorder="big") # Compress data frame @@ -1167,9 +1166,6 @@ class DATA: # Payload information payload_per_frame = modem.get_bytes_per_frame(data_mode) - 2 - # Tempbuffer list for storing our data frames - tempbuffer = [] - # Append data frames with n_frames_per_burst to tempbuffer # TODO: this part needs a complete rewrite! # n_frames_per_burst = 1 is working @@ -1195,9 +1191,7 @@ class DATA: ) frame = arqheader + extended_data_out - # Append frame to tempbuffer for transmission - tempbuffer.append(frame) - + tempbuffer = [frame] self.log.debug("[TNC] tempbuffer:", tempbuffer=tempbuffer) self.log.info( "[TNC] ARQ | TX | FRAMES", @@ -1217,11 +1211,12 @@ class DATA: # threading.Event().wait(0.01) # burstacktimeout = time.time() + self.burst_ack_timeout_seconds + 100 - while static.ARQ_STATE and not ( - self.burst_ack - or self.burst_nack - or self.rpt_request_received - or self.data_frame_ack_received + while ( + static.ARQ_STATE + and not self.burst_ack + and not self.burst_nack + and not self.rpt_request_received + and not self.data_frame_ack_received ): threading.Event().wait(0.01) @@ -1237,10 +1232,6 @@ class DATA: if self.burst_nack: self.burst_nack = False # reset nack state - # not yet implemented - if self.rpt_request_received: - pass - if self.data_frame_ack_received: self.log.debug( "[TNC] arq_transmit: Received FRAME ACK. Sending next chunk." @@ -1266,7 +1257,7 @@ class DATA: maxretries=self.tx_n_max_retries_per_burst, overflows=static.BUFFER_OVERFLOW_COUNTER, ) - # End of FOR loop + # End of FOR loop # update buffer position bufferposition = bufferposition_end @@ -1297,7 +1288,7 @@ class DATA: if self.data_frame_ack_received and bufferposition > len(data_out): self.log.debug("[TNC] arq_tx: Last fragment sent and acknowledged.") break - # GOING TO NEXT ITERATION + # GOING TO NEXT ITERATION if self.data_frame_ack_received: # we need to wait until sending "transmitted" state From ee0060f460d21825d34daf1141f728b99d5fddad Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:45:09 +0100 Subject: [PATCH 05/23] removed some comments --- tnc/data_handler.py | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index be8ba810..e0a8687c 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1074,8 +1074,7 @@ class DATA: self.tx_n_retry_of_burst = 0 # retries we already sent data # Maximum number of retries to send before declaring a frame is lost - # save len of data_out to TOTAL_BYTES for our statistics --> kBytes - # static.TOTAL_BYTES = round(len(data_out) / 1024, 2) + # save len of data_out to TOTAL_BYTES for our statistics static.TOTAL_BYTES = len(data_out) self.arq_file_transfer = True frame_total_size = len(data_out).to_bytes(4, byteorder="big") @@ -1132,21 +1131,6 @@ class DATA: while not self.data_frame_ack_received and static.ARQ_STATE: # we have self.tx_n_max_retries_per_burst attempts for sending a burst for self.tx_n_retry_of_burst in range(self.tx_n_max_retries_per_burst): - # data_mode = mode - # self.log.debug("[TNC] FIXED MODE:", mode=FREEDV_MODE(data_mode).name) - - # we are doing a modulo check of transmission retries of the actual burst - # every 2nd retry which fails, decreases speedlevel by 1. - # as soon as we received an ACK for the current burst, speed_level will increase - # by 1. - # The intent is to optimize speed by adapting to the current RF conditions. - # if not self.tx_n_retry_of_burst % 2 and self.tx_n_retry_of_burst > 0: - # self.speed_level = max(self.speed_level - 1, 0) - - # if self.tx_n_retry_of_burst <= 1: - # self.speed_level += 1 - # self.speed_level = max(self.speed_level + 1, len(self.mode_list) - 1) - # Bound speed level to: # - minimum of either the speed or the length of mode list - 1 # - maximum of either the speed or zero @@ -1204,13 +1188,6 @@ class DATA: self.enqueue_frame_for_tx([t_buf_item], c2_mode=data_mode) # After transmission finished, wait for an ACK or RPT frame - # burstacktimeout = time.time() + self.burst_ack_timeout_seconds + 100 - # while (not self.burst_ack and not self.burst_nack and - # not self.rpt_request_received and not self.data_frame_ack_received and - # time.time() < burstacktimeout and static.ARQ_STATE): - # threading.Event().wait(0.01) - - # burstacktimeout = time.time() + self.burst_ack_timeout_seconds + 100 while ( static.ARQ_STATE and not self.burst_ack @@ -1257,7 +1234,6 @@ class DATA: maxretries=self.tx_n_max_retries_per_burst, overflows=static.BUFFER_OVERFLOW_COUNTER, ) - # End of FOR loop # update buffer position bufferposition = bufferposition_end @@ -1340,7 +1316,6 @@ class DATA: overflows=static.BUFFER_OVERFLOW_COUNTER, ) - self.stop_transmission() if TESTMODE: @@ -2187,7 +2162,7 @@ class DATA: self.snr_list = self.snr_list_low_bw # get mode which fits to given SNR - # initially set speed_level 0 in case of really bad SNR and no matching mode + # initially set speed_level 0 in case of bad SNR and no matching mode self.speed_level = 0 for i in range(len(self.mode_list)): if static.SNR >= self.snr_list[i]: @@ -2228,7 +2203,7 @@ class DATA: # Reset data_channel/burst timestamps self.data_channel_last_received = int(time.time()) - self.burst_last_received = int(time.time() + 6) # we might need some more time so lets increase this + self.burst_last_received = int(time.time() + 6) # we might need some more time so lets increase this # Set ARQ State AFTER resetting timeouts # this avoids timeouts starting too early @@ -2249,8 +2224,6 @@ class DATA: connection_frame[:1] = frametype connection_frame[1:2] = self.session_id connection_frame[8:9] = bytes([self.speed_level]) - - # For checking protocol version on the receiving side connection_frame[13:14] = bytes([static.ARQ_PROTOCOL_VERSION]) self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) @@ -2279,7 +2252,7 @@ class DATA: # Reset data_channel/burst timestamps once again for avoiding running into timeout self.data_channel_last_received = int(time.time()) - self.burst_last_received = int(time.time() + 6) # we might need some more time so lets increase this + self.burst_last_received = int(time.time() + 6) # we might need some more time so lets increase this def arq_received_channel_is_open(self, data_in: bytes) -> None: """ From 8d7df97a92bb8c8fb25e8331b1449db6902c5a94 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 20:32:21 +0100 Subject: [PATCH 06/23] removed some comments --- tnc/data_handler.py | 136 +++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index e0a8687c..7698f0c8 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1056,6 +1056,7 @@ class DATA: + "]", snr=snr, ) + def arq_transmit(self, data_out: bytes, mode: int, n_frames_per_burst: int): """ Transmit ARQ frame @@ -1211,14 +1212,13 @@ class DATA: if self.data_frame_ack_received: self.log.debug( - "[TNC] arq_transmit: Received FRAME ACK. Sending next chunk." + "[TNC] arq_transmit: Received FRAME ACK. Braking retry loop." ) break # break retry loop # We need this part for leaving the repeat loop # static.ARQ_STATE == "DATA" --> when stopping transmission manually if not static.ARQ_STATE: - # print("not ready for data...leaving loop....") self.log.debug( "[TNC] arq_transmit: ARQ State changed to FALSE. Breaking retry loop." ) @@ -1267,62 +1267,74 @@ class DATA: # GOING TO NEXT ITERATION if self.data_frame_ack_received: - # we need to wait until sending "transmitted" state - # gui database is too slow for handling this within 0.001 seconds - # so let's sleep a little - threading.Event().wait(0.2) - self.send_data_to_socket_queue( - freedata="tnc-message", - arq="transmission", - status="transmitted", - uuid=self.transmission_uuid, - percent=static.ARQ_TRANSMISSION_PERCENT, - bytesperminute=static.ARQ_BYTES_PER_MINUTE, - compression=static.ARQ_COMPRESSION_FACTOR, - finished=static.ARQ_SECONDS_UNTIL_FINISH, - mycallsign=str(self.mycallsign, 'UTF-8'), - dxcallsign=str(self.dxcallsign, 'UTF-8'), - irs=helpers.bool_to_string(self.is_IRS) - ) - - self.log.info( - "[TNC] ARQ | TX | DATA TRANSMITTED!", - BytesPerMinute=static.ARQ_BYTES_PER_MINUTE, - total_bytes=static.TOTAL_BYTES, - BitsPerSecond=static.ARQ_BITS_PER_SECOND, - overflows=static.BUFFER_OVERFLOW_COUNTER, - - ) - - # finally do an arq cleanup - self.arq_cleanup() - + self.arq_transmit_success() else: - self.send_data_to_socket_queue( - freedata="tnc-message", - arq="transmission", - status="failed", - uuid=self.transmission_uuid, - percent=static.ARQ_TRANSMISSION_PERCENT, - bytesperminute=static.ARQ_BYTES_PER_MINUTE, - compression=static.ARQ_COMPRESSION_FACTOR, - mycallsign=str(self.mycallsign, 'UTF-8'), - dxcallsign=str(self.dxcallsign, 'UTF-8'), - irs=helpers.bool_to_string(self.is_IRS) - ) - - self.log.info( - "[TNC] ARQ | TX | TRANSMISSION FAILED OR TIME OUT!", - overflows=static.BUFFER_OVERFLOW_COUNTER, - ) - - self.stop_transmission() + self.arq_transmit_failed() if TESTMODE: # Quit after transmission self.log.debug("[TNC] TESTMODE: arq_transmit exiting.") sys.exit(0) + def arq_transmit_success(self): + """ + will be called if we successfully transmitted all of queued data + + """ + # we need to wait until sending "transmitted" state + # gui database is too slow for handling this within 0.001 seconds + # so let's sleep a little + threading.Event().wait(0.2) + self.send_data_to_socket_queue( + freedata="tnc-message", + arq="transmission", + status="transmitted", + uuid=self.transmission_uuid, + percent=static.ARQ_TRANSMISSION_PERCENT, + bytesperminute=static.ARQ_BYTES_PER_MINUTE, + compression=static.ARQ_COMPRESSION_FACTOR, + finished=static.ARQ_SECONDS_UNTIL_FINISH, + mycallsign=str(self.mycallsign, 'UTF-8'), + dxcallsign=str(self.dxcallsign, 'UTF-8'), + irs=helpers.bool_to_string(self.is_IRS) + ) + + self.log.info( + "[TNC] ARQ | TX | DATA TRANSMITTED!", + BytesPerMinute=static.ARQ_BYTES_PER_MINUTE, + total_bytes=static.TOTAL_BYTES, + BitsPerSecond=static.ARQ_BITS_PER_SECOND, + overflows=static.BUFFER_OVERFLOW_COUNTER, + + ) + + # finally do an arq cleanup + self.arq_cleanup() + + def arq_transmit_failed(self): + """ + will be called if we not successfully transmitted all of queued data + """ + self.send_data_to_socket_queue( + freedata="tnc-message", + arq="transmission", + status="failed", + uuid=self.transmission_uuid, + percent=static.ARQ_TRANSMISSION_PERCENT, + bytesperminute=static.ARQ_BYTES_PER_MINUTE, + compression=static.ARQ_COMPRESSION_FACTOR, + mycallsign=str(self.mycallsign, 'UTF-8'), + dxcallsign=str(self.dxcallsign, 'UTF-8'), + irs=helpers.bool_to_string(self.is_IRS) + ) + + self.log.info( + "[TNC] ARQ | TX | TRANSMISSION FAILED OR TIME OUT!", + overflows=static.BUFFER_OVERFLOW_COUNTER, + ) + + self.stop_transmission() + def burst_ack_nack_received(self, data_in: bytes) -> None: """ Received an ACK/NACK for a transmitted frame, keep track and @@ -3061,20 +3073,14 @@ class DATA: print(time.time() - (self.burst_last_received + self.time_list[self.speed_level])) print("-----------------------") - if modem_error_state: - self.log.warning( - "[TNC] Decoding Error", - attempt=self.n_retries_per_burst, - max_attempts=self.rx_n_max_retries_per_burst, - speed_level=self.speed_level, - ) - else: - self.log.warning( - "[TNC] Burst timeout", - attempt=self.n_retries_per_burst, - max_attempts=self.rx_n_max_retries_per_burst, - speed_level=self.speed_level, - ) + + self.log.warning( + "[TNC] Burst decoding error or timeout", + attempt=self.n_retries_per_burst, + max_attempts=self.rx_n_max_retries_per_burst, + speed_level=self.speed_level, + modem_error_state=modem_error_state + ) # reset self.burst_last_received self.burst_last_received = time.time() + self.time_list[self.speed_level] From 0199ed67cf7b7dac22f79d7e6a31e7bdd09b3bc3 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:43:49 +0100 Subject: [PATCH 07/23] socket refactoring --- tnc/sock.py | 1134 +++++++++++++++++++++++++++------------------------ 1 file changed, 590 insertions(+), 544 deletions(-) diff --git a/tnc/sock.py b/tnc/sock.py index acd8d12a..34f6752c 100644 --- a/tnc/sock.py +++ b/tnc/sock.py @@ -127,9 +127,9 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): # iterate thorugh data list for commands in data: if self.server.server_address[1] == static.PORT: - process_tnc_commands(commands) + self.process_tnc_commands(commands) else: - process_daemon_commands(commands) + self.process_daemon_commands(commands) # wait some time between processing multiple commands # this is only a first test to avoid doubled transmission @@ -190,213 +190,222 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): client=self.request, ) + # ------------------------ TNC COMMANDS + def process_tnc_commands(self, data): + """ + process tnc commands -def process_tnc_commands(data): - """ - process tnc commands + Args: + data: - Args: - data: + Returns: - Returns: + """ + log = structlog.get_logger("process_tnc_commands") - """ - log = structlog.get_logger("process_tnc_commands") + # we need to do some error handling in case of socket timeout or decoding issue + try: + # convert data to json object + received_json = json.loads(data) + log.debug("[SCK] CMD", command=received_json) - # we need to do some error handling in case of socket timeout or decoding issue - try: - # convert data to json object - received_json = json.loads(data) - log.debug("[SCK] CMD", command=received_json) + # ENABLE TNC LISTENING STATE + if received_json["type"] == "set" and received_json["command"] == "listen": + self.tnc_set_listen(received_json) - # ENABLE TNC LISTENING STATE ----------------------------------------------------- - if received_json["type"] == "set" and received_json["command"] == "listen": - try: - static.LISTEN = received_json["state"] in ['true', 'True', True, "ON", "on"] - command_response("listen", True) + # START STOP AUDIO RECORDING + if received_json["type"] == "set" and received_json["command"] == "record_audio": + self.tnc_set_record_audio(received_json) - # if tnc is connected, force disconnect when static.LISTEN == False - if not static.LISTEN and static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]: - DATA_QUEUE_TRANSMIT.put(["DISCONNECT"]) - # set early disconnecting state so we can interrupt connection attempts - static.ARQ_SESSION_STATE = "disconnecting" - command_response("disconnect", True) + # SET ENABLE/DISABLE RESPOND TO CALL + if received_json["type"] == "set" and received_json["command"] == "respond_to_call": + self.tnc_set_respond_to_call(received_json) - except Exception as err: - command_response("listen", False) - log.warning( - "[SCK] CQ command execution error", e=err, command=received_json - ) + # SET ENABLE RESPOND TO CQ + if received_json["type"] == "set" and received_json["command"] == "respond_to_cq": + self.tnc_set_record_audio(received_json) + # SET TX AUDIO LEVEL + if received_json["type"] == "set" and received_json["command"] == "tx_audio_level": + self.tnc_set_tx_audio_level(received_json) + # TRANSMIT TEST FRAME + if received_json["type"] == "set" and received_json["command"] == "send_test_frame": + self.tnc_set_send_test_frame(received_json) - # START STOP AUDIO RECORDING ----------------------------------------------------- - if received_json["type"] == "set" and received_json["command"] == "record_audio": - try: - if not static.AUDIO_RECORD: - static.AUDIO_RECORD_FILE = wave.open(f"{int(time.time())}_audio_recording.wav", 'w') - static.AUDIO_RECORD_FILE.setnchannels(1) - static.AUDIO_RECORD_FILE.setsampwidth(2) - static.AUDIO_RECORD_FILE.setframerate(8000) - static.AUDIO_RECORD = True - else: - static.AUDIO_RECORD = False - static.AUDIO_RECORD_FILE.close() + # CQ CQ CQ + if received_json["command"] == "cqcqcq": + self.tnc_cqcqcq(received_json) + # START_BEACON + if received_json["command"] == "start_beacon": + self.tnc_start_beacon(received_json) - command_response("respond_to_call", True) + # STOP_BEACON + if received_json["command"] == "stop_beacon": + self.tnc_stop_beacon(received_json) - except Exception as err: - command_response("respond_to_call", False) - log.warning( - "[SCK] CQ command execution error", e=err, command=received_json - ) + # PING + if received_json["type"] == "ping" and received_json["command"] == "ping": + self.tnc_ping_ping(received_json) + # CONNECT + if received_json["type"] == "arq" and received_json["command"] == "connect": + self.tnc_arq_connect(received_json) + # DISCONNECT + if received_json["type"] == "arq" and received_json["command"] == "disconnect": + self.tnc_arq_disconnect(received_json) + # TRANSMIT RAW DATA + if received_json["type"] == "arq" and received_json["command"] == "send_raw": + self.tnc_arq_send_raw(received_json) + # STOP TRANSMISSION + if received_json["type"] == "arq" and received_json["command"] == "stop_transmission": + self.tnc_arq_stop_transmission(received_json) + # GET RX BUFFER + if received_json["type"] == "get" and received_json["command"] == "rx_buffer": + self.tnc_get_rx_buffer(received_json) + # DELETE RX BUFFER + if received_json["type"] == "set" and received_json["command"] == "del_rx_buffer": + self.tnc_set_del_rx_buffer(received_json) + # SET FREQUENCY + if received_json["type"] == "set" and received_json["command"] == "frequency": + self.tnc_set_frequency(received_json) - # SET ENABLE/DISABLE RESPOND TO CALL ----------------------------------------------------- - if received_json["type"] == "set" and received_json["command"] == "respond_to_call": - try: - static.RESPOND_TO_CALL = received_json["state"] in ['true', 'True', True] - command_response("respond_to_call", True) + # SET MODE + if received_json["type"] == "set" and received_json["command"] == "mode": + self.tnc_set_mode(received_json) - except Exception as err: - command_response("respond_to_call", False) - log.warning( - "[SCK] CQ command execution error", e=err, command=received_json - ) + except Exception as err: + log.error("[SCK] JSON decoding error", e=err) + def tnc_set_listen(self, received_json): + try: + static.LISTEN = received_json["state"] in ['true', 'True', True, "ON", "on"] + command_response("listen", True) - # SET ENABLE RESPOND TO CQ ----------------------------------------------------- - if received_json["type"] == "set" and received_json["command"] == "respond_to_cq": - try: - static.RESPOND_TO_CQ = received_json["state"] in ['true', 'True', True] - command_response("respond_to_cq", True) + # if tnc is connected, force disconnect when static.LISTEN == False + if not static.LISTEN and static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]: + DATA_QUEUE_TRANSMIT.put(["DISCONNECT"]) + # set early disconnecting state so we can interrupt connection attempts + static.ARQ_SESSION_STATE = "disconnecting" + command_response("disconnect", True) - except Exception as err: - command_response("respond_to_cq", False) - log.warning( - "[SCK] CQ command execution error", e=err, command=received_json - ) + except Exception as err: + command_response("listen", False) + log.warning( + "[SCK] CQ command execution error", e=err, command=received_json + ) + def tnc_set_record_audio(self, received_json): + try: + if not static.AUDIO_RECORD: + static.AUDIO_RECORD_FILE = wave.open(f"{int(time.time())}_audio_recording.wav", 'w') + static.AUDIO_RECORD_FILE.setnchannels(1) + static.AUDIO_RECORD_FILE.setsampwidth(2) + static.AUDIO_RECORD_FILE.setframerate(8000) + static.AUDIO_RECORD = True + else: + static.AUDIO_RECORD = False + static.AUDIO_RECORD_FILE.close() - # SET TX AUDIO LEVEL ----------------------------------------------------- - if ( - received_json["type"] == "set" - and received_json["command"] == "tx_audio_level" - ): - try: - static.TX_AUDIO_LEVEL = int(received_json["value"]) - command_response("tx_audio_level", True) + command_response("respond_to_call", True) - except Exception as err: - command_response("tx_audio_level", False) - log.warning( - "[SCK] TX audio command execution error", - e=err, - command=received_json, - ) + except Exception as err: + command_response("respond_to_call", False) + log.warning( + "[SCK] CQ command execution error", e=err, command=received_json + ) - # TRANSMIT TEST FRAME ---------------------------------------------------- - if ( - received_json["type"] == "set" - and received_json["command"] == "send_test_frame" - ): - try: - DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"]) - command_response("send_test_frame", True) - except Exception as err: - command_response("send_test_frame", False) - log.warning( - "[SCK] Send test frame command execution error", - e=err, - command=received_json, - ) + def tnc_set_respond_to_call(self, received_json): + try: + static.RESPOND_TO_CALL = received_json["state"] in ['true', 'True', True] + command_response("respond_to_call", True) - # CQ CQ CQ ----------------------------------------------------- - if received_json["command"] == "cqcqcq": - try: - DATA_QUEUE_TRANSMIT.put(["CQ"]) - command_response("cqcqcq", True) + except Exception as err: + command_response("respond_to_call", False) + log.warning( + "[SCK] CQ command execution error", e=err, command=received_json + ) - except Exception as err: - command_response("cqcqcq", False) - log.warning( - "[SCK] CQ command execution error", e=err, command=received_json - ) + def tnc_set_respond_to_cq(self, received_json): + try: + static.RESPOND_TO_CQ = received_json["state"] in ['true', 'True', True] + command_response("respond_to_cq", True) - # START_BEACON ----------------------------------------------------- - if received_json["command"] == "start_beacon": - try: - static.BEACON_STATE = True - interval = int(received_json["parameter"]) - DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True]) - command_response("start_beacon", True) - except Exception as err: - command_response("start_beacon", False) - log.warning( - "[SCK] Start beacon command execution error", - e=err, - command=received_json, - ) + except Exception as err: + command_response("respond_to_cq", False) + log.warning( + "[SCK] CQ command execution error", e=err, command=received_json + ) - # STOP_BEACON ----------------------------------------------------- - if received_json["command"] == "stop_beacon": - try: - log.warning("[SCK] Stopping beacon!") - static.BEACON_STATE = False - DATA_QUEUE_TRANSMIT.put(["BEACON", None, False]) - command_response("stop_beacon", True) - except Exception as err: - command_response("stop_beacon", False) - log.warning( - "[SCK] Stop beacon command execution error", - e=err, - command=received_json, - ) + def tnc_set_tx_audio_level(self, received_json): + try: + static.TX_AUDIO_LEVEL = int(received_json["value"]) + command_response("tx_audio_level", True) - # PING ---------------------------------------------------------- - if received_json["type"] == "ping" and received_json["command"] == "ping": - # send ping frame and wait for ACK - try: - dxcallsign = received_json["dxcallsign"] - if not str(dxcallsign).strip(): - raise NoCallsign + except Exception as err: + command_response("tx_audio_level", False) + log.warning( + "[SCK] TX audio command execution error", + e=err, + command=received_json, + ) - # additional step for being sure our callsign is correctly - # in case we are not getting a station ssid - # then we are forcing a station ssid = 0 - dxcallsign = helpers.callsign_to_bytes(dxcallsign) - dxcallsign = helpers.bytes_to_callsign(dxcallsign) + def tnc_set_send_test_frame(self, received_json): + try: + DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"]) + command_response("send_test_frame", True) + except Exception as err: + command_response("send_test_frame", False) + log.warning( + "[SCK] Send test frame command execution error", + e=err, + command=received_json, + ) + def tnc_cqcqcq(self, received_json): + try: + DATA_QUEUE_TRANSMIT.put(["CQ"]) + command_response("cqcqcq", True) - # check if specific callsign is set with different SSID than the TNC is initialized - try: - mycallsign = received_json["mycallsign"] - mycallsign = helpers.callsign_to_bytes(mycallsign) - mycallsign = helpers.bytes_to_callsign(mycallsign) - - except Exception: - mycallsign = static.MYCALLSIGN - - DATA_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign]) - command_response("ping", True) - except NoCallsign: - command_response("ping", False) - log.warning("[SCK] callsign required for ping", command=received_json) - except Exception as err: - command_response("ping", False) - log.warning( - "[SCK] PING command execution error", e=err, command=received_json - ) - - # CONNECT ---------------------------------------------------------- - if received_json["type"] == "arq" and received_json["command"] == "connect": - - # pause our beacon first - static.BEACON_PAUSE = True - - # check for connection attempts key - try: - attempts = int(received_json["attempts"]) - except Exception: - # 15 == self.session_connect_max_retries - attempts = 15 + except Exception as err: + command_response("cqcqcq", False) + log.warning( + "[SCK] CQ command execution error", e=err, command=received_json + ) + def tnc_start_beacon(self, received_json): + try: + static.BEACON_STATE = True + interval = int(received_json["parameter"]) + DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True]) + command_response("start_beacon", True) + except Exception as err: + command_response("start_beacon", False) + log.warning( + "[SCK] Start beacon command execution error", + e=err, + command=received_json, + ) + def tnc_stop_beacon(self, received_json): + try: + log.warning("[SCK] Stopping beacon!") + static.BEACON_STATE = False + DATA_QUEUE_TRANSMIT.put(["BEACON", None, False]) + command_response("stop_beacon", True) + except Exception as err: + command_response("stop_beacon", False) + log.warning( + "[SCK] Stop beacon command execution error", + e=err, + command=received_json, + ) + def tnc_ping_ping(self, received_json): + # send ping frame and wait for ACK + try: dxcallsign = received_json["dxcallsign"] + if not str(dxcallsign).strip(): + raise NoCallsign + + # additional step for being sure our callsign is correctly + # in case we are not getting a station ssid + # then we are forcing a station ssid = 0 + dxcallsign = helpers.callsign_to_bytes(dxcallsign) + dxcallsign = helpers.bytes_to_callsign(dxcallsign) # check if specific callsign is set with different SSID than the TNC is initialized try: @@ -407,159 +416,187 @@ def process_tnc_commands(data): except Exception: mycallsign = static.MYCALLSIGN - # additional step for being sure our callsign is correctly - # in case we are not getting a station ssid - # then we are forcing a station ssid = 0 - dxcallsign = helpers.callsign_to_bytes(dxcallsign) - dxcallsign = helpers.bytes_to_callsign(dxcallsign) + DATA_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign]) + command_response("ping", True) + except NoCallsign: + command_response("ping", False) + log.warning("[SCK] callsign required for ping", command=received_json) + except Exception as err: + command_response("ping", False) + log.warning( + "[SCK] PING command execution error", e=err, command=received_json + ) - if static.ARQ_SESSION_STATE not in ["disconnected", "failed"]: + def tnc_arq_connect(self, received_json): + + # pause our beacon first + static.BEACON_PAUSE = True + + # check for connection attempts key + try: + attempts = int(received_json["attempts"]) + except Exception: + # 15 == self.session_connect_max_retries + attempts = 15 + + dxcallsign = received_json["dxcallsign"] + + # check if specific callsign is set with different SSID than the TNC is initialized + try: + mycallsign = received_json["mycallsign"] + mycallsign = helpers.callsign_to_bytes(mycallsign) + mycallsign = helpers.bytes_to_callsign(mycallsign) + + except Exception: + mycallsign = static.MYCALLSIGN + + # additional step for being sure our callsign is correctly + # in case we are not getting a station ssid + # then we are forcing a station ssid = 0 + dxcallsign = helpers.callsign_to_bytes(dxcallsign) + dxcallsign = helpers.bytes_to_callsign(dxcallsign) + + if static.ARQ_SESSION_STATE not in ["disconnected", "failed"]: + command_response("connect", False) + log.warning( + "[SCK] Connect command execution error", + e=f"already connected to station:{static.DXCALLSIGN}", + command=received_json, + ) + else: + + # finally check again if we are disconnected or failed + + # try connecting + try: + + DATA_QUEUE_TRANSMIT.put(["CONNECT", mycallsign, dxcallsign, attempts]) + command_response("connect", True) + except Exception as err: command_response("connect", False) log.warning( "[SCK] Connect command execution error", - e=f"already connected to station:{static.DXCALLSIGN}", + e=err, command=received_json, ) - else: - - # finally check again if we are disconnected or failed - - # try connecting - try: - - DATA_QUEUE_TRANSMIT.put(["CONNECT", mycallsign, dxcallsign, attempts]) - command_response("connect", True) - except Exception as err: - command_response("connect", False) - log.warning( - "[SCK] Connect command execution error", - e=err, - command=received_json, - ) - # allow beacon transmission again - static.BEACON_PAUSE = False - # allow beacon transmission again static.BEACON_PAUSE = False - # DISCONNECT ---------------------------------------------------------- - if received_json["type"] == "arq" and received_json["command"] == "disconnect": - try: - if static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]: - DATA_QUEUE_TRANSMIT.put(["DISCONNECT"]) + # allow beacon transmission again + static.BEACON_PAUSE = False - # set early disconnecting state so we can interrupt connection attempts - static.ARQ_SESSION_STATE = "disconnecting" - command_response("disconnect", True) - else: - command_response("disconnect", False) - log.warning( - "[SCK] Disconnect command not possible", - state=static.ARQ_SESSION_STATE, - command=received_json, - ) - except Exception as err: + def tnc_arq_disconnect(self, received_json): + try: + if static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]: + DATA_QUEUE_TRANSMIT.put(["DISCONNECT"]) + + # set early disconnecting state so we can interrupt connection attempts + static.ARQ_SESSION_STATE = "disconnecting" + command_response("disconnect", True) + else: command_response("disconnect", False) log.warning( - "[SCK] Disconnect command execution error", - e=err, + "[SCK] Disconnect command not possible", + state=static.ARQ_SESSION_STATE, command=received_json, ) + except Exception as err: + command_response("disconnect", False) + log.warning( + "[SCK] Disconnect command execution error", + e=err, + command=received_json, + ) - # TRANSMIT RAW DATA ------------------------------------------- - if received_json["type"] == "arq" and received_json["command"] == "send_raw": - static.BEACON_PAUSE = True + def tnc_arq_send_raw(self, received_json): + static.BEACON_PAUSE = True - # wait some random time - helpers.wait(randrange(5, 25, 5) / 10.0) + # wait some random time + helpers.wait(randrange(5, 25, 5) / 10.0) - # we need to warn if already in arq state - if static.ARQ_STATE: - command_response("send_raw", False) - log.warning( - "[SCK] Send raw command execution warning", - e="already in arq state", - i="command queued", - command=received_json, - ) + # we need to warn if already in arq state + if static.ARQ_STATE: + command_response("send_raw", False) + log.warning( + "[SCK] Send raw command execution warning", + e="already in arq state", + i="command queued", + command=received_json, + ) + try: + if not static.ARQ_SESSION: + dxcallsign = received_json["parameter"][0]["dxcallsign"] + # additional step for being sure our callsign is correctly + # in case we are not getting a station ssid + # then we are forcing a station ssid = 0 + dxcallsign = helpers.callsign_to_bytes(dxcallsign) + dxcallsign = helpers.bytes_to_callsign(dxcallsign) + static.DXCALLSIGN = dxcallsign + static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) + command_response("send_raw", True) + else: + dxcallsign = static.DXCALLSIGN + static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) + + mode = int(received_json["parameter"][0]["mode"]) + n_frames = int(received_json["parameter"][0]["n_frames"]) + base64data = received_json["parameter"][0]["data"] + + # check if specific callsign is set with different SSID than the TNC is initialized try: - if not static.ARQ_SESSION: - dxcallsign = received_json["parameter"][0]["dxcallsign"] - # additional step for being sure our callsign is correctly - # in case we are not getting a station ssid - # then we are forcing a station ssid = 0 - dxcallsign = helpers.callsign_to_bytes(dxcallsign) - dxcallsign = helpers.bytes_to_callsign(dxcallsign) - static.DXCALLSIGN = dxcallsign - static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) - command_response("send_raw", True) - else: - dxcallsign = static.DXCALLSIGN - static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) + mycallsign = received_json["parameter"][0]["mycallsign"] + mycallsign = helpers.callsign_to_bytes(mycallsign) + mycallsign = helpers.bytes_to_callsign(mycallsign) - mode = int(received_json["parameter"][0]["mode"]) - n_frames = int(received_json["parameter"][0]["n_frames"]) - base64data = received_json["parameter"][0]["data"] + except Exception: + mycallsign = static.MYCALLSIGN - # check if specific callsign is set with different SSID than the TNC is initialized - try: - mycallsign = received_json["parameter"][0]["mycallsign"] - mycallsign = helpers.callsign_to_bytes(mycallsign) - mycallsign = helpers.bytes_to_callsign(mycallsign) - - except Exception: - mycallsign = static.MYCALLSIGN - - # check for connection attempts key - try: - attempts = int(received_json["parameter"][0]["attempts"]) - - except Exception: - attempts = 10 - - # check if transmission uuid provided else set no-uuid - try: - arq_uuid = received_json["uuid"] - except Exception: - arq_uuid = "no-uuid" - - if len(base64data) % 4: - raise TypeError - - binarydata = base64.b64decode(base64data) - - DATA_QUEUE_TRANSMIT.put( - ["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign, dxcallsign, attempts] - ) - - except Exception as err: - command_response("send_raw", False) - log.warning( - "[SCK] Send raw command execution error", - e=err, - command=received_json, - ) - - # STOP TRANSMISSION ---------------------------------------------------------- - if ( - received_json["type"] == "arq" - and received_json["command"] == "stop_transmission" - ): + # check for connection attempts key try: - if static.TNC_STATE == "BUSY" or static.ARQ_STATE: - DATA_QUEUE_TRANSMIT.put(["STOP"]) - log.warning("[SCK] Stopping transmission!") - static.TNC_STATE = "IDLE" - static.ARQ_STATE = False - command_response("stop_transmission", True) - except Exception as err: - command_response("stop_transmission", False) - log.warning( - "[SCK] STOP command execution error", e=err, command=received_json - ) + attempts = int(received_json["parameter"][0]["attempts"]) - if received_json["type"] == "get" and received_json["command"] == "rx_buffer": + except Exception: + attempts = 10 + + # check if transmission uuid provided else set no-uuid + try: + arq_uuid = received_json["uuid"] + except Exception: + arq_uuid = "no-uuid" + + if len(base64data) % 4: + raise TypeError + + binarydata = base64.b64decode(base64data) + + DATA_QUEUE_TRANSMIT.put( + ["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign, dxcallsign, attempts] + ) + + except Exception as err: + command_response("send_raw", False) + log.warning( + "[SCK] Send raw command execution error", + e=err, + command=received_json, + ) + + def tnc_arq_stop_transmission(self, received_json): + try: + if static.TNC_STATE == "BUSY" or static.ARQ_STATE: + DATA_QUEUE_TRANSMIT.put(["STOP"]) + log.warning("[SCK] Stopping transmission!") + static.TNC_STATE = "IDLE" + static.ARQ_STATE = False + command_response("stop_transmission", True) + except Exception as err: + command_response("stop_transmission", False) + log.warning( + "[SCK] STOP command execution error", e=err, command=received_json + ) + + def tnc_get_rx_buffer(self, received_json): try: if not RX_BUFFER.empty(): output = { @@ -591,50 +628,257 @@ def process_tnc_commands(data): command=received_json, ) + def tnc_set_del_rx_buffer(self, received_json): + try: + RX_BUFFER.queue.clear() + command_response("del_rx_buffer", True) + except Exception as err: + command_response("del_rx_buffer", False) + log.warning( + "[SCK] Delete RX buffer command execution error", + e=err, + command=received_json, + ) + + def tnc_set_mode(self, received_json): + try: + RIGCTLD_COMMAND_QUEUE.put(["set_mode", received_json["mode"]]) + command_response("set_mode", True) + except Exception as err: + command_response("set_mode", False) + log.warning( + "[SCK] Set mode command execution error", + e=err, + command=received_json, + ) + + def tnc_set_frequency(self, received_json): + try: + RIGCTLD_COMMAND_QUEUE.put(["set_frequency", received_json["frequency"]]) + command_response("set_frequency", True) + except Exception as err: + command_response("set_frequency", False) + log.warning( + "[SCK] Set frequency command execution error", + e=err, + command=received_json, + ) + + + + + + + # ------------------------ DAEMON COMMANDS + def process_daemon_commands(self, data): + """ + process daemon commands + + Args: + data: + + Returns: + + """ + log = structlog.get_logger("process_daemon_commands") + + # convert data to json object + received_json = json.loads(data) + log.debug("[SCK] CMD", command=received_json) + + if received_json["type"] == "set" and received_json["command"] == "mycallsign": + self.daemon_set_mycallsign(received_json) + + if received_json["type"] == "set" and received_json["command"] == "mygrid": + self.daemon_set_mygrid(received_json) + if ( received_json["type"] == "set" - and received_json["command"] == "del_rx_buffer" + and received_json["command"] == "start_tnc" + and not static.TNCSTARTED ): - try: - RX_BUFFER.queue.clear() - command_response("del_rx_buffer", True) - except Exception as err: - command_response("del_rx_buffer", False) + self.daemon_start_tnc(received_json) + + if received_json["type"] == "get" and received_json["command"] == "test_hamlib": + self.daemon_test_hamlib(received_json) + + if received_json["type"] == "set" and received_json["command"] == "stop_tnc": + self.daemon_stop_tnc(received_json) + + def daemon_set_mycallsign(self, received_json): + try: + callsign = received_json["parameter"] + + if bytes(callsign, "utf-8") == b"": + self.request.sendall(b"INVALID CALLSIGN") log.warning( - "[SCK] Delete RX buffer command execution error", - e=err, - command=received_json, + "[SCK] SET MYCALL FAILED", + call=static.MYCALLSIGN, + crc=static.MYCALLSIGN_CRC.hex(), + ) + else: + static.MYCALLSIGN = bytes(callsign, "utf-8") + static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN) + + command_response("mycallsign", True) + log.info( + "[SCK] SET MYCALL", + call=static.MYCALLSIGN, + crc=static.MYCALLSIGN_CRC.hex(), + ) + except Exception as err: + command_response("mycallsign", False) + log.warning("[SCK] command execution error", e=err, command=received_json) + + def daemon_set_mygrid(self, received_json): + try: + mygrid = received_json["parameter"] + + if bytes(mygrid, "utf-8") == b"": + self.request.sendall(b"INVALID GRID") + command_response("mygrid", False) + else: + static.MYGRID = bytes(mygrid, "utf-8") + log.info("[SCK] SET MYGRID", grid=static.MYGRID) + command_response("mygrid", True) + except Exception as err: + command_response("mygrid", False) + log.warning("[SCK] command execution error", e=err, command=received_json) + + def daemon_start_tnc(self, received_json): + try: + startparam = received_json["parameter"][0] + + mycall = str(helpers.return_key_from_object("AA0AA", startparam, "mycall")) + mygrid = str(helpers.return_key_from_object("JN12ab", startparam, "mygrid")) + rx_audio = str(helpers.return_key_from_object("0", startparam, "rx_audio")) + tx_audio = str(helpers.return_key_from_object("0", startparam, "tx_audio")) + radiocontrol = str(helpers.return_key_from_object("disabled", startparam, "radiocontrol")) + rigctld_ip = str(helpers.return_key_from_object("127.0.0.1", startparam, "rigctld_ip")) + rigctld_port = str(helpers.return_key_from_object("4532", startparam, "rigctld_port")) + enable_scatter = str(helpers.return_key_from_object("True", startparam, "enable_scatter")) + enable_fft = str(helpers.return_key_from_object("True", startparam, "enable_fft")) + enable_fsk = str(helpers.return_key_from_object("False", startparam, "enable_fsk")) + low_bandwidth_mode = str(helpers.return_key_from_object("False", startparam, "low_bandwidth_mode")) + tuning_range_fmin = str(helpers.return_key_from_object("-50", startparam, "tuning_range_fmin")) + tuning_range_fmax = str(helpers.return_key_from_object("50", startparam, "tuning_range_fmax")) + tx_audio_level = str(helpers.return_key_from_object("100", startparam, "tx_audio_level")) + respond_to_cq = str(helpers.return_key_from_object("False", startparam, "respond_to_cq")) + rx_buffer_size = str(helpers.return_key_from_object("16", startparam, "rx_buffer_size")) + enable_explorer = str(helpers.return_key_from_object("False", startparam, "enable_explorer")) + enable_auto_tune = str(helpers.return_key_from_object("False", startparam, "enable_auto_tune")) + enable_stats = str(helpers.return_key_from_object("False", startparam, "enable_stats")) + try: + # convert ssid list to python list + ssid_list = str(helpers.return_key_from_object("0, 1, 2, 3, 4, 5, 6, 7, 8, 9", startparam, "ssid_list")) + ssid_list = ssid_list.replace(" ", "") + ssid_list = ssid_list.split(",") + # convert str to int + ssid_list = list(map(int, ssid_list)) + except KeyError: + ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + # print some debugging parameters + for item in startparam: + log.debug( + f"[SCK] TNC Startup Config : {item}", + value=startparam[item], ) - # SET FREQUENCY ----------------------------------------------------- - if received_json["command"] == "frequency" and received_json["type"] == "set": - try: - RIGCTLD_COMMAND_QUEUE.put(["set_frequency", received_json["frequency"]]) - command_response("set_frequency", True) - except Exception as err: - command_response("set_frequency", False) - log.warning( - "[SCK] Set frequency command execution error", - e=err, - command=received_json, - ) + DAEMON_QUEUE.put( + [ + "STARTTNC", + mycall, + mygrid, + rx_audio, + tx_audio, + radiocontrol, + rigctld_ip, + rigctld_port, + enable_scatter, + enable_fft, + low_bandwidth_mode, + tuning_range_fmin, + tuning_range_fmax, + enable_fsk, + tx_audio_level, + respond_to_cq, + rx_buffer_size, + enable_explorer, + ssid_list, + enable_auto_tune, + enable_stats + ] + ) + command_response("start_tnc", True) - # SET MODE ----------------------------------------------------- - if received_json["command"] == "mode" and received_json["type"] == "set": - try: - RIGCTLD_COMMAND_QUEUE.put(["set_mode", received_json["mode"]]) - command_response("set_mode", True) - except Exception as err: - command_response("set_mode", False) - log.warning( - "[SCK] Set mode command execution error", - e=err, - command=received_json, - ) + except Exception as err: + command_response("start_tnc", False) + log.warning("[SCK] command execution error", e=err, command=received_json) + def daemon_stop_tnc(self, received_json): + try: + static.TNCPROCESS.kill() + # unregister process from atexit to avoid process zombies + atexit.unregister(static.TNCPROCESS.kill) + + log.warning("[SCK] Stopping TNC") + static.TNCSTARTED = False + command_response("stop_tnc", True) + except Exception as err: + command_response("stop_tnc", False) + log.warning("[SCK] command execution error", e=err, command=received_json) + + def daemon_test_hamlib(self, received_json): + try: + radiocontrol = str(received_json["parameter"][0]["radiocontrol"]) + rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"]) + rigctld_port = str(received_json["parameter"][0]["rigctld_port"]) + + DAEMON_QUEUE.put( + [ + "TEST_HAMLIB", + radiocontrol, + rigctld_ip, + rigctld_port, + ] + ) + command_response("test_hamlib", True) + except Exception as err: + command_response("test_hamlib", False) + log.warning("[SCK] command execution error", e=err, command=received_json) + + +def send_daemon_state(): + """ + send the daemon state to network + """ + log = structlog.get_logger("send_daemon_state") + + try: + python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}" + + output = { + "command": "daemon_state", + "daemon_state": [], + "python_version": str(python_version), + "input_devices": static.AUDIO_INPUT_DEVICES, + "output_devices": static.AUDIO_OUTPUT_DEVICES, + "serial_devices": static.SERIAL_DEVICES, + #'cpu': str(psutil.cpu_percent()), + #'ram': str(psutil.virtual_memory().percent), + "version": "0.1", + } + + if static.TNCSTARTED: + output["daemon_state"].append({"status": "running"}) + else: + output["daemon_state"].append({"status": "stopped"}) + + return json.dumps(output) except Exception as err: - log.error("[SCK] JSON decoding error", e=err) - + log.warning("[SCK] error", e=err) + return None def send_tnc_state(): """ @@ -699,204 +943,6 @@ def send_tnc_state(): return json.dumps(output) -# This appears to have been taken out of a class, but is never called because -# the `self.request.sendall` call is a syntax error as `self` is undefined and -# we don't see errors in use. -def process_daemon_commands(data): - """ - process daemon commands - - Args: - data: - - Returns: - - """ - log = structlog.get_logger("process_daemon_commands") - - # convert data to json object - received_json = json.loads(data) - log.debug("[SCK] CMD", command=received_json) - if received_json["type"] == "set" and received_json["command"] == "mycallsign": - try: - callsign = received_json["parameter"] - - if bytes(callsign, "utf-8") == b"": - self.request.sendall(b"INVALID CALLSIGN") - log.warning( - "[SCK] SET MYCALL FAILED", - call=static.MYCALLSIGN, - crc=static.MYCALLSIGN_CRC.hex(), - ) - else: - static.MYCALLSIGN = bytes(callsign, "utf-8") - static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN) - - command_response("mycallsign", True) - log.info( - "[SCK] SET MYCALL", - call=static.MYCALLSIGN, - crc=static.MYCALLSIGN_CRC.hex(), - ) - except Exception as err: - command_response("mycallsign", False) - log.warning("[SCK] command execution error", e=err, command=received_json) - - if received_json["type"] == "set" and received_json["command"] == "mygrid": - try: - mygrid = received_json["parameter"] - - if bytes(mygrid, "utf-8") == b"": - self.request.sendall(b"INVALID GRID") - command_response("mygrid", False) - else: - static.MYGRID = bytes(mygrid, "utf-8") - log.info("[SCK] SET MYGRID", grid=static.MYGRID) - command_response("mygrid", True) - except Exception as err: - command_response("mygrid", False) - log.warning("[SCK] command execution error", e=err, command=received_json) - - if ( - received_json["type"] == "set" - and received_json["command"] == "start_tnc" - and not static.TNCSTARTED - ): - try: - startparam = received_json["parameter"][0] - - mycall = str(helpers.return_key_from_object("AA0AA", startparam,"mycall")) - mygrid = str(helpers.return_key_from_object("JN12ab", startparam,"mygrid")) - rx_audio = str(helpers.return_key_from_object("0", startparam,"rx_audio")) - tx_audio = str(helpers.return_key_from_object("0", startparam,"tx_audio")) - radiocontrol = str(helpers.return_key_from_object("disabled", startparam,"radiocontrol")) - rigctld_ip = str(helpers.return_key_from_object("127.0.0.1", startparam,"rigctld_ip")) - rigctld_port = str(helpers.return_key_from_object("4532", startparam,"rigctld_port")) - enable_scatter = str(helpers.return_key_from_object("True", startparam,"enable_scatter")) - enable_fft = str(helpers.return_key_from_object("True", startparam,"enable_fft")) - enable_fsk = str(helpers.return_key_from_object("False", startparam,"enable_fsk")) - low_bandwidth_mode = str(helpers.return_key_from_object("False", startparam,"low_bandwidth_mode")) - tuning_range_fmin = str(helpers.return_key_from_object("-50", startparam,"tuning_range_fmin")) - tuning_range_fmax = str(helpers.return_key_from_object("50", startparam,"tuning_range_fmax")) - tx_audio_level = str(helpers.return_key_from_object("100", startparam,"tx_audio_level")) - respond_to_cq = str(helpers.return_key_from_object("False", startparam,"respond_to_cq")) - rx_buffer_size = str(helpers.return_key_from_object("16", startparam,"rx_buffer_size")) - enable_explorer = str(helpers.return_key_from_object("False", startparam,"enable_explorer")) - enable_auto_tune = str(helpers.return_key_from_object("False", startparam,"enable_auto_tune")) - enable_stats = str(helpers.return_key_from_object("False", startparam,"enable_stats")) - try: - # convert ssid list to python list - ssid_list = str(helpers.return_key_from_object("0, 1, 2, 3, 4, 5, 6, 7, 8, 9", startparam, "ssid_list")) - ssid_list = ssid_list.replace(" ", "") - ssid_list = ssid_list.split(",") - # convert str to int - ssid_list = list(map(int, ssid_list)) - except KeyError: - ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - - # print some debugging parameters - for item in startparam: - log.debug( - f"[SCK] TNC Startup Config : {item}", - value=startparam[item], - ) - - DAEMON_QUEUE.put( - [ - "STARTTNC", - mycall, - mygrid, - rx_audio, - tx_audio, - radiocontrol, - rigctld_ip, - rigctld_port, - enable_scatter, - enable_fft, - low_bandwidth_mode, - tuning_range_fmin, - tuning_range_fmax, - enable_fsk, - tx_audio_level, - respond_to_cq, - rx_buffer_size, - enable_explorer, - ssid_list, - enable_auto_tune, - enable_stats - ] - ) - command_response("start_tnc", True) - - except Exception as err: - command_response("start_tnc", False) - log.warning("[SCK] command execution error", e=err, command=received_json) - - if received_json["type"] == "get" and received_json["command"] == "test_hamlib": - try: - radiocontrol = str(received_json["parameter"][0]["radiocontrol"]) - rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"]) - rigctld_port = str(received_json["parameter"][0]["rigctld_port"]) - - DAEMON_QUEUE.put( - [ - "TEST_HAMLIB", - radiocontrol, - rigctld_ip, - rigctld_port, - ] - ) - command_response("test_hamlib", True) - except Exception as err: - command_response("test_hamlib", False) - log.warning("[SCK] command execution error", e=err, command=received_json) - - if received_json["type"] == "set" and received_json["command"] == "stop_tnc": - try: - static.TNCPROCESS.kill() - # unregister process from atexit to avoid process zombies - atexit.unregister(static.TNCPROCESS.kill) - - log.warning("[SCK] Stopping TNC") - static.TNCSTARTED = False - command_response("stop_tnc", True) - except Exception as err: - command_response("stop_tnc", False) - log.warning("[SCK] command execution error", e=err, command=received_json) - - -def send_daemon_state(): - """ - send the daemon state to network - """ - log = structlog.get_logger("send_daemon_state") - - try: - python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}" - - output = { - "command": "daemon_state", - "daemon_state": [], - "python_version": str(python_version), - "input_devices": static.AUDIO_INPUT_DEVICES, - "output_devices": static.AUDIO_OUTPUT_DEVICES, - "serial_devices": static.SERIAL_DEVICES, - #'cpu': str(psutil.cpu_percent()), - #'ram': str(psutil.virtual_memory().percent), - "version": "0.1", - } - - if static.TNCSTARTED: - output["daemon_state"].append({"status": "running"}) - else: - output["daemon_state"].append({"status": "stopped"}) - - return json.dumps(output) - except Exception as err: - log.warning("[SCK] error", e=err) - return None - - def command_response(command, status): s_status = "OK" if status else "Failed" jsondata = {"command_response": command, "status": s_status} From eaff3210ed16f557fcd76d0316122f279822f6a7 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:48:55 +0100 Subject: [PATCH 08/23] adjusted alc tuning --- tnc/modem.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tnc/modem.py b/tnc/modem.py index bfa632da..891c97c1 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -537,17 +537,18 @@ class RF: x = np.frombuffer(txbuffer, dtype=np.int16) if static.AUDIO_AUTO_TUNE: if static.HAMLIB_ALC == 0.0: - static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + 30 - elif 0.0 < static.HAMLIB_ALC <= 0.8: - print("0.001 > static.HAMLIB_ALC <= 0.8") static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + 20 - self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) - elif 0.8 < static.HAMLIB_ALC < 0.99: - print("0.8 > static.HAMLIB_ALC <= 0.99") + elif 0.0 < static.HAMLIB_ALC <= 0.1: + print("0.0 < static.HAMLIB_ALC <= 0.1") static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + 2 self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) - elif 1.0 <= static.HAMLIB_ALC: - static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 2 + elif 0.1 < static.HAMLIB_ALC < 0.2: + print("0.1 < static.HAMLIB_ALC < 0.2") + static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) + elif 0.2 < static.HAMLIB_ALC < 0.99: + print("0.2 < static.HAMLIB_ALC < 0.99") + static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 20 self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) else: self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) From 4b83838eb90c90433996bb840a5d9b314c491d85 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:49:52 +0100 Subject: [PATCH 09/23] adjusted alc tuning --- tnc/modem.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tnc/modem.py b/tnc/modem.py index 891c97c1..78abd7fe 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -550,6 +550,10 @@ class RF: print("0.2 < static.HAMLIB_ALC < 0.99") static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 20 self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) + elif 1.0 >=static.HAMLIB_ALC: + print("1.0 >= static.HAMLIB_ALC") + static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 40 + self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) else: self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL), alc_level=str(static.HAMLIB_ALC)) x = set_audio_volume(x, static.TX_AUDIO_LEVEL) From 34b888e5c8f10eea5580cfc81b9525bef2466b54 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:50:33 +0100 Subject: [PATCH 10/23] small cleanup --- tnc/data_handler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 7698f0c8..d266f81f 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1779,7 +1779,6 @@ class DATA: data_in:bytes: """ - print(static.ARQ_SESSION_STATE) # We've arrived here from process_data which already checked that the frame # is intended for this station. # Close the session if the CRC matches the remote station in static. From 568c6b9f4b14703807e4d4e9adbf5742215b7e69 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:56:20 +0100 Subject: [PATCH 11/23] refactored daemon --- tnc/daemon.py | 346 ++++++++++++++++++++++++-------------------------- 1 file changed, 164 insertions(+), 182 deletions(-) diff --git a/tnc/daemon.py b/tnc/daemon.py index 6c9b2cc1..05df8493 100755 --- a/tnc/daemon.py +++ b/tnc/daemon.py @@ -135,197 +135,179 @@ class DAEMON: # data[2] mygrid # data[3] rx_audio # data[4] tx_audio - # REMOVED - data[5] devicename - # REMOVED - data[6] deviceport - # REMOVED - data[7] serialspeed - # REMOVED - data[8] pttprotocol - # REMOVED - data[9] pttport - # REMOVED - data[10] data_bits - # REMOVED - data[11] stop_bits - # REMOVED - data[12] handshake - # data[13] radiocontrol - # data[14] rigctld_ip - # data[15] rigctld_port - # data[16] send_scatter - # data[17] send_fft - # data[18] low_bandwidth_mode - # data[19] tuning_range_fmin - # data[20] tuning_range_fmax - # data[21] enable FSK - # data[22] tx-audio-level - # data[23] respond_to_cq - # data[24] rx_buffer_size - # data[25] explorer - # data[26] ssid_list - # data[27] auto_tune - # data[28] stats - # TODO: We need to remove 5-12 and adjust the list number for other paramters - # This is only a dirty fix + # data[5] radiocontrol + # data[6] rigctld_ip + # data[7] rigctld_port + # data[8] send_scatter + # data[9] send_fft + # data[10] low_bandwidth_mode + # data[11] tuning_range_fmin + # data[12] tuning_range_fmax + # data[13] enable FSK + # data[14] tx-audio-level + # data[15] respond_to_cq + # data[16] rx_buffer_size + # data[17] explorer + # data[18] ssid_list + # data[19] auto_tune + # data[20] stats if data[0] == "STARTTNC": - self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6]) + self.start_tnc(data) - # list of parameters, necessary for running subprocess command as a list - options = ["--port", str(static.DAEMONPORT - 1)] - - # create an additional list entry for parameters not covered by gui - data[50] = int(static.DAEMONPORT - 1) - - options.append("--mycall") - options.extend((data[1], "--mygrid")) - options.extend((data[2], "--rx")) - options.extend((data[3], "--tx")) - options.append(data[4]) - - # if radiocontrol != disabled - # this should hopefully avoid a ton of problems if we are just running in - # disabled mode - - if data[5] != "disabled": - - options.append("--radiocontrol") - options.append(data[5]) - - if data[5] == "rigctld": - options.append("--rigctld_ip") - options.extend((data[6], "--rigctld_port")) - options.append(data[7]) - - if data[8] == "True": - options.append("--scatter") - - if data[9] == "True": - options.append("--fft") - - if data[10] == "True": - options.append("--500hz") - - options.append("--tuning_range_fmin") - options.extend((data[11], "--tuning_range_fmax")) - options.extend((data[12], "--tx-audio-level")) - options.append(data[14]) - - if data[15] == "True": - options.append("--qrv") - - options.append("--rx-buffer-size") - options.append(data[16]) - - if data[17] == "True": - options.append("--explorer") - - options.append("--ssid") - options.extend(str(i) for i in data[18]) - if data[19] == "True": - options.append("--tune") - - if data[20] == "True": - options.append("--stats") - - # safe data to config file - config.write_entire_config(data) - - - - - # Try running tnc from binary, else run from source - # This helps running the tnc in a developer environment - try: - command = [] - - if (getattr(sys, 'frozen', False) or hasattr(sys, "_MEIPASS")) and sys.platform in ["darwin"]: - # If the application is run as a bundle, the PyInstaller bootloader - # extends the sys module by a flag frozen=True and sets the app - # path into variable _MEIPASS'. - application_path = sys._MEIPASS - command.append(f'{application_path}/freedata-tnc') - - elif sys.platform in ["linux", "darwin"]: - command.append("./freedata-tnc") - elif sys.platform in ["win32", "win64"]: - command.append("freedata-tnc.exe") - - command += options - proc = subprocess.Popen(command) - - atexit.register(proc.kill) - - self.log.info("[DMN] TNC started", path="binary") - except FileNotFoundError as err1: - self.log.info("[DMN] worker: ", e=err1) - command = [] - - if sys.platform in ["linux", "darwin"]: - command.append("python3") - elif sys.platform in ["win32", "win64"]: - command.append("python") - - command.append("main.py") - command += options - print(command) - proc = subprocess.Popen(command) - atexit.register(proc.kill) - - self.log.info("[DMN] TNC started", path="source") - - static.TNCPROCESS = proc - static.TNCSTARTED = True - """ - # WE HAVE THIS PART in SOCKET - if data[0] == "STOPTNC": - static.TNCPROCESS.kill() - self.log.warning("[DMN] Stopping TNC") - #os.kill(static.TNCPROCESS, signal.SIGKILL) - static.TNCSTARTED = False - """ - - # data[9] radiocontrol - # data[10] rigctld_ip - # data[11] rigctld_port if data[0] == "TEST_HAMLIB": - - radiocontrol = data[1] - rigctld_ip = data[2] - rigctld_port = data[3] - - # check how we want to control the radio - if radiocontrol == "direct": - print("direct hamlib support deprecated - not usable anymore") - sys.exit(1) - elif radiocontrol == "rigctl": - print("rigctl support deprecated - not usable anymore") - sys.exit(1) - elif radiocontrol == "rigctld": - import rigctld as rig - else: - import rigdummy as rig - - hamlib = rig.radio() - hamlib.open_rig( - rigctld_ip=rigctld_ip, - rigctld_port=rigctld_port, - ) - - # hamlib_version = rig.hamlib_version - - hamlib.set_ptt(True) - if pttstate := hamlib.get_ptt(): - self.log.info("[DMN] Hamlib PTT", status="SUCCESS") - response = {"command": "test_hamlib", "result": "SUCCESS"} - else: - self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS") - response = {"command": "test_hamlib", "result": "NOSUCCESS"} - - hamlib.set_ptt(False) - hamlib.close_rig() - - jsondata = json.dumps(response) - sock.SOCKET_QUEUE.put(jsondata) + # data[9] radiocontrol + # data[10] rigctld_ip + # data[11] rigctld_port + self.test_hamlib_ptt(data) except Exception as err1: self.log.error("[DMN] worker: Exception: ", e=err1) + def test_hamlib_ptt(self, data): + radiocontrol = data[1] + rigctld_ip = data[2] + rigctld_port = data[3] + # check how we want to control the radio + if radiocontrol == "direct": + print("direct hamlib support deprecated - not usable anymore") + sys.exit(1) + elif radiocontrol == "rigctl": + print("rigctl support deprecated - not usable anymore") + sys.exit(1) + elif radiocontrol == "rigctld": + import rigctld as rig + else: + import rigdummy as rig + + hamlib = rig.radio() + hamlib.open_rig( + rigctld_ip=rigctld_ip, + rigctld_port=rigctld_port, + ) + + # hamlib_version = rig.hamlib_version + + hamlib.set_ptt(True) + if hamlib.get_ptt(): + self.log.info("[DMN] Hamlib PTT", status="SUCCESS") + response = {"command": "test_hamlib", "result": "SUCCESS"} + else: + self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS") + response = {"command": "test_hamlib", "result": "NOSUCCESS"} + + hamlib.set_ptt(False) + hamlib.close_rig() + + jsondata = json.dumps(response) + sock.SOCKET_QUEUE.put(jsondata) + + def start_tnc(self, data): + self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6]) + + # list of parameters, necessary for running subprocess command as a list + options = ["--port", str(static.DAEMONPORT - 1)] + + # create an additional list entry for parameters not covered by gui + data[50] = int(static.DAEMONPORT - 1) + + options.append("--mycall") + options.extend((data[1], "--mygrid")) + options.extend((data[2], "--rx")) + options.extend((data[3], "--tx")) + options.append(data[4]) + + # if radiocontrol != disabled + # this should hopefully avoid a ton of problems if we are just running in + # disabled mode + + if data[5] != "disabled": + + options.append("--radiocontrol") + options.append(data[5]) + + if data[5] == "rigctld": + options.append("--rigctld_ip") + options.extend((data[6], "--rigctld_port")) + options.append(data[7]) + + if data[8] == "True": + options.append("--scatter") + + if data[9] == "True": + options.append("--fft") + + if data[10] == "True": + options.append("--500hz") + + options.append("--tuning_range_fmin") + options.extend((data[11], "--tuning_range_fmax")) + options.extend((data[12], "--tx-audio-level")) + options.append(data[14]) + + if data[15] == "True": + options.append("--qrv") + + options.append("--rx-buffer-size") + options.append(data[16]) + + if data[17] == "True": + options.append("--explorer") + + options.append("--ssid") + options.extend(str(i) for i in data[18]) + if data[19] == "True": + options.append("--tune") + + if data[20] == "True": + options.append("--stats") + + # safe data to config file + config.write_entire_config(data) + + # Try running tnc from binary, else run from source + # This helps running the tnc in a developer environment + try: + command = [] + + if (getattr(sys, 'frozen', False) or hasattr(sys, "_MEIPASS")) and sys.platform in ["darwin"]: + # If the application is run as a bundle, the PyInstaller bootloader + # extends the sys module by a flag frozen=True and sets the app + # path into variable _MEIPASS'. + application_path = sys._MEIPASS + command.append(f'{application_path}/freedata-tnc') + + elif sys.platform in ["linux", "darwin"]: + command.append("./freedata-tnc") + elif sys.platform in ["win32", "win64"]: + command.append("freedata-tnc.exe") + + command += options + proc = subprocess.Popen(command) + + atexit.register(proc.kill) + + self.log.info("[DMN] TNC started", path="binary") + except FileNotFoundError as err1: + self.log.info("[DMN] worker: ", e=err1) + command = [] + + if sys.platform in ["linux", "darwin"]: + command.append("python3") + elif sys.platform in ["win32", "win64"]: + command.append("python") + + command.append("main.py") + command += options + print(command) + proc = subprocess.Popen(command) + atexit.register(proc.kill) + + self.log.info("[DMN] TNC started", path="source") + + static.TNCPROCESS = proc + static.TNCSTARTED = True if __name__ == "__main__": mainlog = structlog.get_logger(__file__) # we need to run this on Windows for multiprocessing support From 54f2fe6a92ef39db0d34acce85f27204cf3a661a Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:05:41 +0100 Subject: [PATCH 12/23] attempt fixing ctest with socket dummy --- test/util_datac0.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/util_datac0.py b/test/util_datac0.py index 4bb5f71e..d54084e6 100644 --- a/test/util_datac0.py +++ b/test/util_datac0.py @@ -76,6 +76,9 @@ def t_setup( modem.RF.transmit = t_transmit t_modem.log = structlog.get_logger(f"station{station}_RF") + # Create socket + sock.ThreadedTCPServer(('localhost', 3000), sock.ThreadedTCPRequestHandler) + return tnc, orig_rx_func, orig_tx_func From a10f79411015a8eab06c33c5552860bf79758b7a Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:15:49 +0100 Subject: [PATCH 13/23] attempt fixing ctest with socket dummy --- test/util_datac0.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/util_datac0.py b/test/util_datac0.py index d54084e6..63e2aa5a 100644 --- a/test/util_datac0.py +++ b/test/util_datac0.py @@ -76,9 +76,6 @@ def t_setup( modem.RF.transmit = t_transmit t_modem.log = structlog.get_logger(f"station{station}_RF") - # Create socket - sock.ThreadedTCPServer(('localhost', 3000), sock.ThreadedTCPRequestHandler) - return tnc, orig_rx_func, orig_tx_func @@ -150,9 +147,9 @@ def t_datac0_1( log.debug("t_datac0_1: STOP test, setting TNC state") static.TNC_STATE = "BUSY" static.ARQ_STATE = True - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) time.sleep(0.5) - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration @@ -170,7 +167,7 @@ def t_datac0_1( # override ARQ SESSION STATE for allowing disconnect command static.ARQ_SESSION_STATE = "connected" data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall} - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) time.sleep(0.5) # Allow enough time for this side to process the disconnect frame. @@ -263,8 +260,8 @@ def t_datac0_2( if "cq" in data: t_data = {"type": "arq", "command": "stop_transmission"} - sock.process_tnc_commands(json.dumps(t_data, indent=None)) - sock.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration From 47a20a2727266ad781779b840d402b824380c430 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:34:43 +0100 Subject: [PATCH 14/23] attempt fixing ctest with socket dummy --- test/util_datac0_negative.py | 10 +++++----- test/util_tnc_ISS.py | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/util_datac0_negative.py b/test/util_datac0_negative.py index d5aaf845..18a47aa4 100644 --- a/test/util_datac0_negative.py +++ b/test/util_datac0_negative.py @@ -148,8 +148,8 @@ def t_datac0_1( static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) static.TNC_STATE = "BUSY" static.ARQ_STATE = True - sock.process_tnc_commands(json.dumps(data, indent=None)) - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration @@ -173,7 +173,7 @@ def t_datac0_1( # override ARQ SESSION STATE for allowing disconnect command static.ARQ_SESSION_STATE = "connected" data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall} - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) time.sleep(0.5) # Allow enough time for this side to process the disconnect frame. @@ -266,8 +266,8 @@ def t_datac0_2( if "cq" in data: t_data = {"type": "arq", "command": "stop_transmission"} - sock.process_tnc_commands(json.dumps(t_data, indent=None)) - sock.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration diff --git a/test/util_tnc_ISS.py b/test/util_tnc_ISS.py index f3d20a35..4bb741b0 100644 --- a/test/util_tnc_ISS.py +++ b/test/util_tnc_ISS.py @@ -124,17 +124,17 @@ def t_arq_iss(*args): time.sleep(0.5) - sock.process_tnc_commands(json.dumps(data, indent=None)) - sock.process_tnc_commands(json.dumps(data, indent=None)) - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) time.sleep(1.5) data = {"type": "arq", "command": "stop_transmission"} - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) time.sleep(0.5) - sock.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) # Set timeout timeout = time.time() + 15 From f6a272c839ccf7a70b32e69c90dce2919d46c99d Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:49:00 +0100 Subject: [PATCH 15/23] attempt fixing ctest with socket dummy --- test/util_datac0.py | 10 +++++----- test/util_datac0_negative.py | 10 +++++----- test/util_tnc_ISS.py | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/util_datac0.py b/test/util_datac0.py index 63e2aa5a..515a4bb3 100644 --- a/test/util_datac0.py +++ b/test/util_datac0.py @@ -147,9 +147,9 @@ def t_datac0_1( log.debug("t_datac0_1: STOP test, setting TNC state") static.TNC_STATE = "BUSY" static.ARQ_STATE = True - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) time.sleep(0.5) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration @@ -167,7 +167,7 @@ def t_datac0_1( # override ARQ SESSION STATE for allowing disconnect command static.ARQ_SESSION_STATE = "connected" data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall} - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) time.sleep(0.5) # Allow enough time for this side to process the disconnect frame. @@ -260,8 +260,8 @@ def t_datac0_2( if "cq" in data: t_data = {"type": "arq", "command": "stop_transmission"} - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(t_data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration diff --git a/test/util_datac0_negative.py b/test/util_datac0_negative.py index 18a47aa4..6ab019e0 100644 --- a/test/util_datac0_negative.py +++ b/test/util_datac0_negative.py @@ -148,8 +148,8 @@ def t_datac0_1( static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) static.TNC_STATE = "BUSY" static.ARQ_STATE = True - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration @@ -173,7 +173,7 @@ def t_datac0_1( # override ARQ SESSION STATE for allowing disconnect command static.ARQ_SESSION_STATE = "connected" data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall} - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) time.sleep(0.5) # Allow enough time for this side to process the disconnect frame. @@ -266,8 +266,8 @@ def t_datac0_2( if "cq" in data: t_data = {"type": "arq", "command": "stop_transmission"} - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(t_data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(t_data, indent=None)) # Assure the test completes. timeout = time.time() + timeout_duration diff --git a/test/util_tnc_ISS.py b/test/util_tnc_ISS.py index 4bb741b0..4c9172d1 100644 --- a/test/util_tnc_ISS.py +++ b/test/util_tnc_ISS.py @@ -124,17 +124,17 @@ def t_arq_iss(*args): time.sleep(0.5) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) time.sleep(1.5) data = {"type": "arq", "command": "stop_transmission"} - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) time.sleep(0.5) - sock.ThreadedTCPRequestHandler.process_tnc_commands(json.dumps(data, indent=None)) + sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None)) # Set timeout timeout = time.time() + 15 From 9111b6e595bf2c3fd57fd4478bb61493a6b686e6 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:14:58 +0100 Subject: [PATCH 16/23] and another attempt fixing ctests --- tnc/test2.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tnc/test2.py b/tnc/test2.py index e69de29b..29754791 100644 --- a/tnc/test2.py +++ b/tnc/test2.py @@ -0,0 +1,24 @@ +import sock +import threading +import ujson as json + + +received_json =b'{"type": "command", "command": "start_beacon", "parameter": "5"}' + +sock.TESTMODE = True +#sock.ThreadedTCPRequestHandler.process_tnc_commands(None, received_json) + +#testserver = sock.ThreadedTCPServer(('127.0.0.1', 3000), sock.ThreadedTCPRequestHandler).serve_forever +#server_thread = threading.Thread(target=testserver.serve_forever) +#server_thread.daemon = True +#server_thread.start() + + +#test = sock.ThreadedTCPRequestHandler(request=sock.ThreadedTCPServer, client_address='127.0.0.1', server=None) + +#sock.process_tnc_commands(received_json) +sock.ThreadedTCPRequestHandler.process_tnc_commands(None, received_json) + + + +print("done") \ No newline at end of file From c2ba13e539ceec7f64644db0731674f268d0847e Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:15:10 +0100 Subject: [PATCH 17/23] and another attempt fixing ctests --- tnc/sock.py | 94 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/tnc/sock.py b/tnc/sock.py index 34f6752c..76cc5e99 100644 --- a/tnc/sock.py +++ b/tnc/sock.py @@ -39,6 +39,8 @@ DAEMON_QUEUE = queue.Queue() CONNECTED_CLIENTS = set() CLOSE_SIGNAL = False +TESTMODE = False + log = structlog.get_logger("sock") @@ -211,69 +213,127 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): # ENABLE TNC LISTENING STATE if received_json["type"] == "set" and received_json["command"] == "listen": - self.tnc_set_listen(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_listen(None, received_json) + else: + self.tnc_set_listen(received_json) # START STOP AUDIO RECORDING if received_json["type"] == "set" and received_json["command"] == "record_audio": - self.tnc_set_record_audio(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_record_audio(None, received_json) + else: + self.tnc_set_record_audio(received_json) # SET ENABLE/DISABLE RESPOND TO CALL if received_json["type"] == "set" and received_json["command"] == "respond_to_call": - self.tnc_set_respond_to_call(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_respond_to_call(None, received_json) + else: + self.tnc_set_respond_to_call(received_json) # SET ENABLE RESPOND TO CQ if received_json["type"] == "set" and received_json["command"] == "respond_to_cq": - self.tnc_set_record_audio(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_record_audio(None, received_json) + else: + self.tnc_set_record_audio(received_json) # SET TX AUDIO LEVEL if received_json["type"] == "set" and received_json["command"] == "tx_audio_level": - self.tnc_set_tx_audio_level(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_tx_audio_level(None, received_json) + else: + self.tnc_set_tx_audio_level(received_json) # TRANSMIT TEST FRAME if received_json["type"] == "set" and received_json["command"] == "send_test_frame": - self.tnc_set_send_test_frame(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_send_test_frame(None, received_json) + else: + self.tnc_set_send_test_frame(received_json) # CQ CQ CQ if received_json["command"] == "cqcqcq": self.tnc_cqcqcq(received_json) # START_BEACON if received_json["command"] == "start_beacon": - self.tnc_start_beacon(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_start_beacon(None, received_json) + else: + self.tnc_start_beacon(received_json) # STOP_BEACON if received_json["command"] == "stop_beacon": - self.tnc_stop_beacon(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_stop_beacon(None, received_json) + else: + self.tnc_stop_beacon(received_json) # PING if received_json["type"] == "ping" and received_json["command"] == "ping": - self.tnc_ping_ping(received_json) + + if TESTMODE: + ThreadedTCPRequestHandler.tnc_ping_ping(None, received_json) + else: + self.tnc_ping_ping(received_json) + # CONNECT if received_json["type"] == "arq" and received_json["command"] == "connect": - self.tnc_arq_connect(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_arq_connect(None, received_json) + else: + self.tnc_arq_connect(received_json) + # DISCONNECT if received_json["type"] == "arq" and received_json["command"] == "disconnect": - self.tnc_arq_disconnect(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_arq_disconnect(None, received_json) + else: + self.tnc_arq_disconnect(received_json) + # TRANSMIT RAW DATA if received_json["type"] == "arq" and received_json["command"] == "send_raw": - self.tnc_arq_send_raw(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_arq_send_raw(None, received_json) + else: + self.tnc_arq_send_raw(received_json) + # STOP TRANSMISSION if received_json["type"] == "arq" and received_json["command"] == "stop_transmission": - self.tnc_arq_stop_transmission(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_arq_stop_transmission(None, received_json) + else: + self.tnc_arq_stop_transmission(None, received_json) + # GET RX BUFFER if received_json["type"] == "get" and received_json["command"] == "rx_buffer": - self.tnc_get_rx_buffer(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_get_rx_buffer(None, received_json) + else: + self.tnc_get_rx_buffer(received_json) # DELETE RX BUFFER if received_json["type"] == "set" and received_json["command"] == "del_rx_buffer": - self.tnc_set_del_rx_buffer(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_del_rx_buffer(None, received_json) + else: + self.tnc_set_del_rx_buffer(received_json) # SET FREQUENCY if received_json["type"] == "set" and received_json["command"] == "frequency": - self.tnc_set_frequency(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_frequency(None, received_json) + else: + self.tnc_set_frequency(received_json) # SET MODE if received_json["type"] == "set" and received_json["command"] == "mode": - self.tnc_set_mode(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_set_mode(None, received_json) + else: + self.tnc_set_mode(received_json) except Exception as err: log.error("[SCK] JSON decoding error", e=err) + def tnc_set_listen(self, received_json): try: static.LISTEN = received_json["state"] in ['true', 'True', True, "ON", "on"] From d1f42084f4f771d8f4919d18d581054173152a3a Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:15:49 +0100 Subject: [PATCH 18/23] deleted test file --- tnc/test2.py | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 tnc/test2.py diff --git a/tnc/test2.py b/tnc/test2.py deleted file mode 100644 index 29754791..00000000 --- a/tnc/test2.py +++ /dev/null @@ -1,24 +0,0 @@ -import sock -import threading -import ujson as json - - -received_json =b'{"type": "command", "command": "start_beacon", "parameter": "5"}' - -sock.TESTMODE = True -#sock.ThreadedTCPRequestHandler.process_tnc_commands(None, received_json) - -#testserver = sock.ThreadedTCPServer(('127.0.0.1', 3000), sock.ThreadedTCPRequestHandler).serve_forever -#server_thread = threading.Thread(target=testserver.serve_forever) -#server_thread.daemon = True -#server_thread.start() - - -#test = sock.ThreadedTCPRequestHandler(request=sock.ThreadedTCPServer, client_address='127.0.0.1', server=None) - -#sock.process_tnc_commands(received_json) -sock.ThreadedTCPRequestHandler.process_tnc_commands(None, received_json) - - - -print("done") \ No newline at end of file From 14269a718ba6caab812fa13f92ff2d4163942d16 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:17:08 +0100 Subject: [PATCH 19/23] set sock testmode in ctests --- test/util_datac0.py | 4 ++++ test/util_datac0_negative.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/util_datac0.py b/test/util_datac0.py index 515a4bb3..13bd7b1b 100644 --- a/test/util_datac0.py +++ b/test/util_datac0.py @@ -39,6 +39,10 @@ def t_setup( ): # Disable data_handler testmode - This is required to test a conversation. data_handler.TESTMODE = False + + # Enable socket testmode for overriding socket class + sock.TESTMODE = True + modem.RXCHANNEL = tmp_path / rx_channel modem.TESTMODE = True modem.TXCHANNEL = tmp_path / tx_channel diff --git a/test/util_datac0_negative.py b/test/util_datac0_negative.py index 6ab019e0..08c881e0 100644 --- a/test/util_datac0_negative.py +++ b/test/util_datac0_negative.py @@ -33,6 +33,10 @@ def t_setup( ): # Disable data_handler testmode - This is required to test a conversation. data_handler.TESTMODE = False + + # Enable socket testmode for overriding socket class + sock.TESTMODE = True + modem.RXCHANNEL = tmp_path / rx_channel modem.TESTMODE = True modem.TXCHANNEL = tmp_path / tx_channel From 0c5d755e1a27ac232e0c14fe003df4903c26e01b Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:31:33 +0100 Subject: [PATCH 20/23] forgot to adjust cq function --- tnc/sock.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tnc/sock.py b/tnc/sock.py index 76cc5e99..6904ee4e 100644 --- a/tnc/sock.py +++ b/tnc/sock.py @@ -253,7 +253,11 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): # CQ CQ CQ if received_json["command"] == "cqcqcq": - self.tnc_cqcqcq(received_json) + if TESTMODE: + ThreadedTCPRequestHandler.tnc_cqcqcq(None, received_json) + else: + self.tnc_cqcqcq(received_json) + # START_BEACON if received_json["command"] == "start_beacon": if TESTMODE: From 8c2ea112037556bef010f86e741215eeffd7c340 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:41:26 +0100 Subject: [PATCH 21/23] attempt with NACK NaN SNR value --- tnc/data_handler.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index d266f81f..088982c3 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -928,8 +928,6 @@ class DATA: # Update modes we are listening to self.set_listening_modes(False, True, self.mode_list[self.speed_level]) - - def arq_process_received_data_frame(self, data_frame, snr): """ @@ -1369,6 +1367,8 @@ class DATA: self.burst_nack_counter = 0 # Reset n retries per burst counter self.n_retries_per_burst = 0 + + self.burst_ack_snr = helpers.snr_from_bytes(data_in[2:3]) else: # Decrease speed level if we received a burst nack # self.speed_level = max(self.speed_level - 1, 0) @@ -1376,7 +1376,7 @@ class DATA: self.burst_nack = True # Increment burst nack counter self.burst_nack_counter += 1 - desc = "nack" + self.burst_ack_snr = 'NaN' # Update data_channel timestamp self.data_channel_last_received = int(time.time()) @@ -1387,12 +1387,6 @@ class DATA: self.speed_level = int.from_bytes(bytes(data_in[3:4]), "big") static.ARQ_SPEED_LEVEL = self.speed_level - #self.log.debug( - # f"[TNC] burst_{desc}_received:", - # speed_level=self.speed_level, - # c2_mode=FREEDV_MODE(self.mode_list[self.speed_level]).name, - #) - def frame_ack_received( self, data_in: bytes # pylint: disable=unused-argument ) -> None: From 0cfecd819067dc6104766b39e419f2dfceb25c8c Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:45:10 +0100 Subject: [PATCH 22/23] reduced fsk logging --- tnc/data_handler.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 088982c3..ccbfed85 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -2372,8 +2372,8 @@ class DATA: ping_frame[4:7] = helpers.get_crc_24(mycallsign) ping_frame[7:13] = helpers.callsign_to_bytes(mycallsign) - self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) if static.ENABLE_FSK: + self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.datac0.value) @@ -2589,9 +2589,9 @@ class DATA: beacon_frame[:1] = bytes([FR_TYPE.BEACON.value]) beacon_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign) beacon_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) - self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) if static.ENABLE_FSK: + self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) self.enqueue_frame_for_tx( [beacon_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value, @@ -2669,10 +2669,10 @@ class DATA: cq_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign) cq_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) - self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) self.log.debug("[TNC] CQ Frame:", data=[cq_frame]) if static.ENABLE_FSK: + self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) @@ -2744,7 +2744,6 @@ class DATA: qrv_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) qrv_frame[11:12] = helpers.snr_to_bytes(static.SNR) - if static.ENABLE_FSK: self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) self.enqueue_frame_for_tx([qrv_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) From 64e3d2abc0190f0388dedae54919371d39ae5191 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 10 Feb 2023 12:12:18 +0100 Subject: [PATCH 23/23] smaller pep8 improvements --- tnc/sock.py | 92 ++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/tnc/sock.py b/tnc/sock.py index 6904ee4e..17a287f7 100644 --- a/tnc/sock.py +++ b/tnc/sock.py @@ -52,11 +52,9 @@ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass +# noinspection PyTypeChecker class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): """ """ - - connection_alive = False - connection_alive = False log = structlog.get_logger("ThreadedTCPRequestHandler") @@ -93,7 +91,8 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): client.send(sock_data) except Exception as err: self.log.info("[SCK] Connection lost", e=err) - # TODO: Check if we really should set connection alive to false. This might disconnect all other clients as well... + # TODO: Check if we really should set connection alive to false. + # This might disconnect all other clients as well... self.connection_alive = False except Exception as err: self.log.debug("[SCK] catch harmless RuntimeError: Set changed size during iteration", e=err) @@ -136,7 +135,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): # wait some time between processing multiple commands # this is only a first test to avoid doubled transmission # we might improve this by only processing one command or - # doing some kind of selection to determin which commands need to be dropped + # doing some kind of selection to determine which commands need to be dropped # and which one can be processed during a running transmission threading.Event().wait(0.5) @@ -186,10 +185,11 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): ) try: CONNECTED_CLIENTS.remove(self.request) - except Exception: + except Exception as e: self.log.warning( "[SCK] client connection already removed from client list", client=self.request, + e=e, ) # ------------------------ TNC COMMANDS @@ -306,7 +306,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): if TESTMODE: ThreadedTCPRequestHandler.tnc_arq_stop_transmission(None, received_json) else: - self.tnc_arq_stop_transmission(None, received_json) + self.tnc_arq_stop_transmission(received_json) # GET RX BUFFER if received_json["type"] == "get" and received_json["command"] == "rx_buffer": @@ -355,6 +355,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): log.warning( "[SCK] CQ command execution error", e=err, command=received_json ) + def tnc_set_record_audio(self, received_json): try: if not static.AUDIO_RECORD: @@ -421,6 +422,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): e=err, command=received_json, ) + def tnc_cqcqcq(self, received_json): try: DATA_QUEUE_TRANSMIT.put(["CQ"]) @@ -445,6 +447,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): e=err, command=received_json, ) + def tnc_stop_beacon(self, received_json): try: log.warning("[SCK] Stopping beacon!") @@ -458,6 +461,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): e=err, command=received_json, ) + def tnc_ping_ping(self, received_json): # send ping frame and wait for ACK try: @@ -661,36 +665,36 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): ) def tnc_get_rx_buffer(self, received_json): - try: - if not RX_BUFFER.empty(): - output = { - "command": "rx_buffer", - "data-array": [], - } + try: + if not RX_BUFFER.empty(): + output = { + "command": "rx_buffer", + "data-array": [], + } - for _buffer_length in range(RX_BUFFER.qsize()): - base64_data = RX_BUFFER.queue[_buffer_length][4] - output["data-array"].append( - { - "uuid": RX_BUFFER.queue[_buffer_length][0], - "timestamp": RX_BUFFER.queue[_buffer_length][1], - "dxcallsign": str(RX_BUFFER.queue[_buffer_length][2], "utf-8"), - "dxgrid": str(RX_BUFFER.queue[_buffer_length][3], "utf-8"), - "data": base64_data, - } - ) - jsondata = json.dumps(output) - # self.request.sendall(bytes(jsondata, encoding)) - SOCKET_QUEUE.put(jsondata) - command_response("rx_buffer", True) + for _buffer_length in range(RX_BUFFER.qsize()): + base64_data = RX_BUFFER.queue[_buffer_length][4] + output["data-array"].append( + { + "uuid": RX_BUFFER.queue[_buffer_length][0], + "timestamp": RX_BUFFER.queue[_buffer_length][1], + "dxcallsign": str(RX_BUFFER.queue[_buffer_length][2], "utf-8"), + "dxgrid": str(RX_BUFFER.queue[_buffer_length][3], "utf-8"), + "data": base64_data, + } + ) + jsondata = json.dumps(output) + # self.request.sendall(bytes(jsondata, encoding)) + SOCKET_QUEUE.put(jsondata) + command_response("rx_buffer", True) - except Exception as err: - command_response("rx_buffer", False) - log.warning( - "[SCK] Send RX buffer command execution error", - e=err, - command=received_json, - ) + except Exception as err: + command_response("rx_buffer", False) + log.warning( + "[SCK] Send RX buffer command execution error", + e=err, + command=received_json, + ) def tnc_set_del_rx_buffer(self, received_json): try: @@ -728,11 +732,6 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): command=received_json, ) - - - - - # ------------------------ DAEMON COMMANDS def process_daemon_commands(self, data): """ @@ -757,9 +756,9 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): self.daemon_set_mygrid(received_json) if ( - received_json["type"] == "set" - and received_json["command"] == "start_tnc" - and not static.TNCSTARTED + received_json["type"] == "set" + and received_json["command"] == "start_tnc" + and not static.TNCSTARTED ): self.daemon_start_tnc(received_json) @@ -929,8 +928,8 @@ def send_daemon_state(): "input_devices": static.AUDIO_INPUT_DEVICES, "output_devices": static.AUDIO_OUTPUT_DEVICES, "serial_devices": static.SERIAL_DEVICES, - #'cpu': str(psutil.cpu_percent()), - #'ram': str(psutil.virtual_memory().percent), + # 'cpu': str(psutil.cpu_percent()), + # 'ram': str(psutil.virtual_memory().percent), "version": "0.1", } @@ -944,6 +943,7 @@ def send_daemon_state(): log.warning("[SCK] error", e=err) return None + def send_tnc_state(): """ send the tnc state to network @@ -1018,4 +1018,4 @@ def try_except(string): try: return string except Exception: - return False \ No newline at end of file + return False