From b2b53386d3a56a02f8bbdbf407cf027217e22452 Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 12 Mar 2021 16:18:41 +0100 Subject: [PATCH] first try with data channel timeout and keep alive --- data_handler.py | 29 +++++++++++++++----- helpers.py | 72 +++++++++++++++++++++++++++++++++++++++++++------ static.py | 2 ++ 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/data_handler.py b/data_handler.py index 8e7b78ec..6dd892cf 100644 --- a/data_handler.py +++ b/data_handler.py @@ -28,7 +28,8 @@ modem = modem.RF() def arq_data_received(data_in): static.TNC_STATE = 'BUSY' - + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) + static.ARQ_N_FRAME = int.from_bytes(bytes(data_in[:1]), "big") - 10 # get number of burst frame static.ARQ_N_RX_FRAMES_PER_BURSTS = int.from_bytes(bytes(data_in[1:2]), "big") # get number of bursts from received frame static.ARQ_RX_N_CURRENT_ARQ_FRAME = int.from_bytes(bytes(data_in[2:4]), "big") # get current number of total frames @@ -520,7 +521,8 @@ async def arq_connect(): def arq_received_connect(data_in): static.ARQ_STATE = 'CONNECTING' - + static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = int(time.time()) + static.DXCALLSIGN = bytes(data_in[3:9]).rstrip(b'\x00') static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN) # static.FREEDV_DATA_MODE = int.from_bytes(bytes(data_in[12:13]), "big") @@ -541,6 +543,8 @@ def arq_received_connect(data_in): def arq_transmit_keep_alive(): + static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = int(time.time()) # we need to reset the counter at this point + frame_type = bytes([221]) connection_frame = bytearray(14) connection_frame[:1] = frame_type @@ -555,8 +559,10 @@ def arq_transmit_keep_alive(): def arq_received_connect_keep_alive(data_in): if static.ARQ_SEND_KEEP_ALIVE == True and (static.ARQ_STATE == 'CONNECTING' or static.ARQ_STATE == 'CONNECTED'): logging.info("CONN [" + str(static.MYCALLSIGN, 'utf-8') + "] >|< [" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]") + static.ARQ_STATE = 'CONNECTED' - + static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = int(time.time()) + frame_type = bytes([221]) connection_frame = bytearray(14) connection_frame[:1] = frame_type @@ -584,7 +590,8 @@ async def arq_open_data_channel(): logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]") static.ARQ_SEND_KEEP_ALIVE = False static.ARQ_DATA_CHANNEL_MODE = 12 - + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) + while static.CHANNEL_STATE == 'SENDING_SIGNALLING': time.sleep(0.01) # print("wir warten 2 sekunden...") @@ -604,8 +611,12 @@ async def arq_open_data_channel(): def arq_received_data_channel_opener(data_in): logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]") + + static.ARQ_STATE = 'CONNECTED' + static.TNC_STATE = 'BUSY' static.ARQ_SEND_KEEP_ALIVE = False static.ARQ_DATA_CHANNEL_MODE = int.from_bytes(bytes(data_in[12:13]), "big") + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # static.ARQ_READY_FOR_DATA = int.from_bytes(bytes(data_in[13:14]), "big") connection_frame = bytearray(14) @@ -619,19 +630,23 @@ def arq_received_data_channel_opener(data_in): while static.CHANNEL_STATE == 'SENDING_SIGNALLING': time.sleep(0.01) - # print("waiting for data....") + print("waiting for data....") static.CHANNEL_STATE = 'RECEIVING_DATA' - # einen timeout benötigen wir auch noch.... + + + # und ab hier geht es dann in den "RECEIVING_DATA" mode.... def arq_received_channel_is_open(data_in): - static.ARQ_SEND_KEEP_ALIVE == False + static.ARQ_SEND_KEEP_ALIVE = False + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) if static.ARQ_DATA_CHANNEL_MODE == int.from_bytes(bytes(data_in[12:13]), "big"): logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]") time.sleep(1) static.ARQ_READY_FOR_DATA = True + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # ############################################################################################################ diff --git a/helpers.py b/helpers.py index 4286c05f..4d7d155d 100644 --- a/helpers.py +++ b/helpers.py @@ -13,14 +13,15 @@ import crcengine import static +import data_handler def get_crc_8(data): """ Author: DJ2LS - + Get the CRC8 of a byte string - + param: data = bytes() """ crc_algorithm = crcengine.new('crc8-ccitt') # load crc8 library @@ -32,9 +33,9 @@ def get_crc_8(data): def get_crc_16(data): """ Author: DJ2LS - + Get the CRC16 of a byte string - + param: data = bytes() """ crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library @@ -42,7 +43,61 @@ def get_crc_16(data): crc_data = crc_data.to_bytes(2, byteorder='big') return crc_data +def watchdog(): + """ + Author: DJ2LS + + watchdog master function. Frome here we call the watchdogs + """ + while True: + time.sleep(0.01) + connection_keep_alive_watchdog() + data_channel_keep_alive_watchdog() + +def connection_keep_alive_watchdog(): + """ + Author: DJ2LS + + Function to trigger a DISCONNECT, if timeout for receiving a keep alive frame is reached + + """ + if static.ARQ_STATE == 'CONNECTED' and not static.ARQ_READY_FOR_DATA and static.TNC_STATE == 'IDLE' and static.ARQ_SEND_KEEP_ALIVE: + time.sleep(0.01) + if static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED + 20 > time.time(): + static.ARQ_SEND_KEEP_ALIVE = True + else: + # TODO: show time out message + static.ARQ_SEND_KEEP_ALIVE = False + static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = 0 + static.ARQ_STATE = 'IDLE' + print("keep alive timeout") + asyncio.run(data_handler.arq_disconnect()) + +def data_channel_keep_alive_watchdog(): + """ + Author: DJ2LS + + + """ + + if static.ARQ_STATE == 'CONNECTED' and static.TNC_STATE == 'BUSY' and not static.ARQ_SEND_KEEP_ALIVE: + time.sleep(0.01) + if static.ARQ_DATA_CHANNEL_LAST_RECEIVED + 20 > time.time(): + static.ARQ_SEND_KEEP_ALIVE = False + #print("alles okay mit den daten....") + else: + # TODO: show time out message + # static.ARQ_SEND_KEEP_ALIVE = True + static.ARQ_DATA_CHANNEL_LAST_RECEIVED = 0 + print("data keep alive timeout") + arq_reset_frame_machine() + data_handler.arq_transmit_keep_alive() + + + + + async def set_after_timeout(): """ Author: DJ2LS @@ -111,10 +166,10 @@ def arq_reset_ack(state): def arq_reset_frame_machine(): """ Author: DJ2LS - + Reset the frame machine parameters to default, so we need to call just a function - + """ arq_reset_timeout(False) arq_reset_ack(False) @@ -135,12 +190,13 @@ def arq_reset_frame_machine(): static.CHANNEL_STATE = 'RECEIVING_SIGNALLING' static.ARQ_READY_FOR_DATA = False + def setup_logging(): """ Author: DJ2LS - + Set the custom logging format so we can use colors - + """ logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%H:%M:%S', level=logging.INFO) diff --git a/static.py b/static.py index 7356ce47..9f9ede2f 100644 --- a/static.py +++ b/static.py @@ -154,9 +154,11 @@ TNC_STATE = 'IDLE' # MODE FOR SENDING AN RECEIVING DATA DURING ARQ SESSION ARQ_READY_FOR_DATA = False ARQ_DATA_CHANNEL_MODE = 12 +ARQ_DATA_CHANNEL_LAST_RECEIVED = 0 # SEND KEEP ALIVE ONLY IF WE WANT ARQ_SEND_KEEP_ALIVE = True +ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = 0 #ARQ_WAIT_FOR_DISCONNECT = False # ------- TX BUFFER