diff --git a/arq.py b/arq.py index 3e820c19..c99963d6 100644 --- a/arq.py +++ b/arq.py @@ -16,6 +16,7 @@ import modem import helpers import main + modem = modem.RF() static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_DATA_PAYLOAD_PER_FRAME - 3 #6?! @@ -26,8 +27,6 @@ def arq_ack_timeout(): def data_received(data_in): - - # arqframe = frame_type + \ # 1 [:1] # frame type and current number of arq frame of (current) burst # bytes([static.ARQ_TX_N_FRAMES_PER_BURST]) + \ # 1 [1:2] # total number of arq frames per (current) burst # static.ARQ_N_CURRENT_ARQ_FRAME + \ # 2 [2:4] # current arq frame number @@ -35,8 +34,7 @@ def data_received(data_in): # static.ARQ_BURST_PAYLOAD_CRC + \ # 2 [6:8] # arq crc # payload_data # N [8:N] # payload data - - + 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 @@ -58,7 +56,7 @@ def data_received(data_in): logging.info("ARQ | RX | ARQ FRAME [" + str(static.ARQ_N_FRAME) + "/" + str(static.ARQ_N_RX_FRAMES_PER_BURSTS) + "] [" + str(arq_percent_burst).zfill(3) + "%] --- TOTAL [" + str(static.ARQ_RX_N_CURRENT_ARQ_FRAME) + "/" + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) + "] [" + str(arq_percent_frame).zfill(3) + "%]" ) - + #allocate ARQ_RX_FRAME_BUFFER as a list with "None" if not already done. This should be done only once per burst! # here we will save the N frame of a data frame to N list position so we can explicit search for it @@ -66,16 +64,13 @@ def data_received(data_in): for i in range(0,static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME+1): static.ARQ_RX_FRAME_BUFFER.insert(i,None) - #allocate ARQ_RX_BURST_BUFFER as a list with "None" if not already done. This should be done only once per burst! # here we will save the N frame of a burst to N list position so we can explicit search for it if static.ARQ_N_RX_FRAMES_PER_BURSTS != len(static.ARQ_RX_BURST_BUFFER) and static.ARQ_N_FRAME == 1: for i in range(0,static.ARQ_N_RX_FRAMES_PER_BURSTS+1): static.ARQ_RX_BURST_BUFFER.insert(i,None) - - - + # now we add the incoming data to the specified position in our lists static.ARQ_RX_BURST_BUFFER[static.ARQ_N_FRAME] = bytes(data_in) static.ARQ_RX_FRAME_BUFFER[static.ARQ_RX_N_CURRENT_ARQ_FRAME] = bytes(data_in) @@ -85,41 +80,54 @@ def data_received(data_in): # run only if we recieved all ARQ FRAMES per ARQ BURST burst_total_payload = bytearray() - if static.ARQ_N_FRAME == static.ARQ_N_RX_FRAMES_PER_BURSTS: #if received bursts are equal to burst number in frame + if static.ARQ_N_FRAME == static.ARQ_N_RX_FRAMES_PER_BURSTS and static.ARQ_RX_BURST_BUFFER.count(None) == 1: #if received bursts are equal to burst number in frame - #here we get the total payload for the frame to calculate the crc - for n_raw_frame in range(1,len(static.ARQ_RX_BURST_BUFFER)): - # we need to check if we have a None or received data in list - if static.ARQ_RX_BURST_BUFFER[n_raw_frame] != None: - burst_frame = static.ARQ_RX_BURST_BUFFER[n_raw_frame] #get burst frame - burst_payload = burst_frame[8:] #remove frame type and burst CRC #4 - burst_total_payload = burst_total_payload + burst_payload #stick bursts together +# #here we get the total payload for the frame to calculate the crc +# for n_raw_frame in range(1,len(static.ARQ_RX_BURST_BUFFER)): +# # we need to check if we have a None or received data in list +# if static.ARQ_RX_BURST_BUFFER[n_raw_frame] != None: +# burst_frame = static.ARQ_RX_BURST_BUFFER[n_raw_frame] #get burst frame +# burst_payload = burst_frame[8:] #remove frame type and burst CRC #4 +# burst_total_payload = burst_total_payload + burst_payload #stick bursts together # ------------------ calculate CRC of BURST - burst_payload_crc = helpers.get_crc_16(burst_total_payload) +# burst_payload_crc = helpers.get_crc_16(burst_total_payload) # IF BURST CRC IS CORRECT, APPEND BURST TO BUFFER AND SEND ACK FRAME - if burst_payload_crc == data_in[6:8]: +# if burst_payload_crc == data_in[6:8]: #BUILDING ACK FRAME FOR BURST ----------------------------------------------- - #ack_payload = bytes(burst_payload_crc) - ack_frame = b'<'+ bytes(burst_payload_crc) # < = 60 - ack_buffer = bytearray(static.ARQ_ACK_PAYLOAD_PER_FRAME) - ack_buffer[:len(ack_frame)] = ack_frame # set buffersize to length of data which will be send +# #ack_payload = bytes(burst_payload_crc) +# ack_frame = b'<'+ bytes(burst_payload_crc) # < = 60 +# ack_buffer = bytearray(static.ARQ_ACK_PAYLOAD_PER_FRAME) +# ack_buffer[:len(ack_frame)] = ack_frame # set buffersize to length of data which will be send #TRANSMIT ACK FRAME FOR BURST----------------------------------------------- - logging.info("ARQ | TX | ARQ BURST ACK [" + str(data_in[6:8].hex()) +"]") - modem.transmit_arq_ack(ack_buffer) +# logging.info("ARQ | TX | ARQ BURST ACK [" + str(data_in[6:8].hex()) +"]") +# modem.transmit_arq_ack(ack_buffer) # ---------------------------------------------------------------- - static.ARQ_RX_BURST_BUFFER = [] # CLEAR RX BURST BUFFER AFTER SENDING DATA +# static.ARQ_RX_BURST_BUFFER = [] # CLEAR RX BURST BUFFER AFTER SENDING DATA - else: #IF burst payload crc and input crc are NOT equal - logging.info("ARQ BURST CRC NOT EQUAL! [" + str(data_in[6:8]) + "]") - static.ARQ_RX_BURST_BUFFER = [] #erase ARQ RX Burst buffer +# else: #IF burst payload crc and input crc are NOT equal +# logging.info("ARQ BURST CRC NOT EQUAL! [" + str(data_in[6:8]) + "]") +# static.ARQ_RX_BURST_BUFFER = [] #erase ARQ RX Burst buffer - #if nframes are unequal to expected frames per burst + + # --------------- CHECK IF WE ARE MISSING FRAMES ------------------------------------------- + for burst in range(1,len(static.ARQ_RX_BURST_BUFFER)): + if static.ARQ_RX_BURST_BUFFER[burst] == None: + print("Missing frames:" + str(burst)) + + + + + logging.info("ARQ | TX | ARQ BURST ACK") + ack_buffer = bytearray(static.ARQ_ACK_PAYLOAD_PER_FRAME) + modem.transmit_arq_ack(ack_buffer) + static.ARQ_RX_BURST_BUFFER = [] + + #if nframes are unequal to expected frames per burst #just a placeholder at this time else: - #just a placeholder at this time pass # ---------------------------- FRAME MACHINE @@ -153,8 +161,7 @@ def data_received(data_in): arq_frame_payload = arq_frame_payload[0] - # --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER - + # --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER complete_data_frame = complete_data_frame + arq_frame_payload @@ -166,10 +173,9 @@ def data_received(data_in): #IF THE FRAME PAYLOAD CRC IS EQUAL TO THE FRAME CRC WHICH IS KNOWN FROM THE HEADER --> SUCCESS if frame_payload_crc == static.FRAME_CRC: logging.info("ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED! - TIME TO PARTY") - + #append received frame to RX_BUFFER static.RX_BUFFER.append(complete_data_frame) - - + #BUILDING ACK FRAME FOR DATA FRAME ----------------------------------------------- ack_frame = b'='+ bytes(static.FRAME_CRC) # < = 61 @@ -208,31 +214,22 @@ def frame_ack_received(): static.ARQ_FRAME_ACK_RECEIVED = 1 #Force data loops of TNC to stop and continue with next frame - def transmit(data_out): static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_DATA_PAYLOAD_PER_FRAME - 8 #3 ohne ARQ_TX_N_FRAMES_PER_BURST frame_header_length = 4 - - n_arq_frames_per_data_frame = (len(data_out)+frame_header_length) // static.ARQ_PAYLOAD_PER_FRAME + ((len(data_out)+frame_header_length) % static.ARQ_PAYLOAD_PER_FRAME > 0) # aufrunden 3.2 = 4 - - #print(static.FREEDV_DATA_PAYLOAD_PER_FRAME) - #print(static.ARQ_PAYLOAD_PER_FRAME) - #print(n_bursts_prediction) - ####static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = n_arq_frames_per_data_frame.to_bytes(2, byteorder='big') #65535 + + n_arq_frames_per_data_frame = (len(data_out)+frame_header_length) // static.ARQ_PAYLOAD_PER_FRAME + ((len(data_out)+frame_header_length) % static.ARQ_PAYLOAD_PER_FRAME > 0) frame_payload_crc = helpers.get_crc_16(data_out) - #print(frame_payload_crc) - + # This is the total frame with frame header, which will be send data_out = frame_payload_crc + static.FRAME_BOF + data_out + static.FRAME_EOF # 2 2 N 2 - # --------------------------------------------- LETS CREATE A BUFFER BY SPLITTING THE FILES INTO PEACES static.TX_BUFFER = [data_out[i:i+static.ARQ_PAYLOAD_PER_FRAME] for i in range(0, len(data_out), static.ARQ_PAYLOAD_PER_FRAME)] static.TX_BUFFER_SIZE = len(static.TX_BUFFER) - #print(static.TX_BUFFER) logging.info("ARQ | TX | DATA FRAME --- BYTES: " + str(len(data_out)) + " ARQ FRAMES: " + str(static.TX_BUFFER_SIZE)) @@ -241,51 +238,46 @@ def transmit(data_out): static.ARQ_N_SENT_FRAMES = 0 # SET N SENT FRAMES TO 0 FOR A NEW SENDING CYCLE while static.ARQ_N_SENT_FRAMES <= static.TX_BUFFER_SIZE: - #print("static.ARQ_N_SENT_FRAMES: " + str(static.ARQ_N_SENT_FRAMES)) static.ARQ_TX_N_FRAMES_PER_BURST = get_n_frames_per_burst() # ----------- CREATE FRAME TOTAL PAYLOAD TO BE ABLE TO CREATE CRC FOR IT - burst_total_payload = bytearray() + try: # DETECT IF LAST BURST TO PREVENT INDEX ERROR OF BUFFER - for i in range(static.ARQ_TX_N_FRAMES_PER_BURST): # Loop through TX_BUFFER LIST - # make sure we have always a filled buffer with the length of payload per frame - burst_raw_payload = static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + i] - burst_payload = bytearray(static.ARQ_PAYLOAD_PER_FRAME) - burst_payload[:len(burst_raw_payload)] = burst_raw_payload # get frame from TX_BUFFER - burst_total_payload = burst_total_payload + burst_payload # append single frame to total payload buffer - + for i in range(static.ARQ_TX_N_FRAMES_PER_BURST): # Loop through TX_BUFFER LIST + len(static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + i]) #we calculate the length to trigger a list index error + except IndexError: # IF LAST BURST DETECTED BUILD CRC WITH LESS FRAMES AND SET static.ARQ_TX_N_FRAMES_PER_BURST TO VALUE OF REST! - burst_total_payload = bytearray() # reset burst_total_payload because of possible input remaining of detecting loop one step above if static.ARQ_N_SENT_FRAMES == 0 and (static.ARQ_TX_N_FRAMES_PER_BURST > static.TX_BUFFER_SIZE): #WE CANT DO MODULO 0 --> CHECK IF FIRST FRAME == LAST FRAME static.ARQ_TX_N_FRAMES_PER_BURST = static.TX_BUFFER_SIZE + elif static.ARQ_N_SENT_FRAMES == 1 and (static.ARQ_TX_N_FRAMES_PER_BURST > static.TX_BUFFER_SIZE): # MODULO 1 WILL ALWAYS BE 0 --> THIS FIXES IT static.ARQ_TX_N_FRAMES_PER_BURST = static.TX_BUFFER_SIZE - static.ARQ_N_SENT_FRAMES + else: static.ARQ_TX_N_FRAMES_PER_BURST = (static.TX_BUFFER_SIZE % static.ARQ_N_SENT_FRAMES) - - #print("ARQ_TX_N_FRAMES_PER_BURST OF LAST BURST: " + str(static.ARQ_TX_N_FRAMES_PER_BURST)) - - for i in range(static.ARQ_TX_N_FRAMES_PER_BURST): #bytearray(b'111111111111111111111111222222222222222222222222') - - # make sure we have always a filled buffer with the length of payload per frame - burst_raw_payload = static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + i] - burst_payload = bytearray(static.ARQ_PAYLOAD_PER_FRAME) - burst_payload[:len(burst_raw_payload)] = burst_raw_payload # get frame from TX_BUFFER - burst_total_payload = burst_total_payload + burst_payload # append single frame to total payload buffer - - # ----------- GENERATE PAYLOAD CRC FOR ARQ_TX_N_FRAMES_PER_BURST - static.ARQ_BURST_PAYLOAD_CRC = helpers.get_crc_16(burst_total_payload) + + +# burst_total_payload = bytearray() # reset burst_total_payload because of possible input remaining of detecting loop one step above +# for i in range(static.ARQ_TX_N_FRAMES_PER_BURST): #bytearray(b'111111111111111111111111222222222222222222222222') +# +# # make sure we have always a filled buffer with the length of payload per frame +# burst_raw_payload = static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + i] +# burst_payload = bytearray(static.ARQ_PAYLOAD_PER_FRAME) +# burst_payload[:len(burst_raw_payload)] = burst_raw_payload # get frame from TX_BUFFER +# burst_total_payload = burst_total_payload + burst_payload # append single frame to total payload buffer +# +# # ----------- GENERATE PAYLOAD CRC FOR ARQ_TX_N_FRAMES_PER_BURST +# static.ARQ_BURST_PAYLOAD_CRC = helpers.get_crc_16(burst_total_payload) #--------------------------------------------- N ATTEMPTS TO SEND BURSTS IF ACK RECEPTION FAILS for static.TX_N_RETRIES in range(static.TX_N_MAX_RETRIES): if static.ARQ_N_SENT_FRAMES+1 <= static.TX_BUFFER_SIZE: - logging.info("ARQ | TX | B:[" + str(static.ARQ_BURST_PAYLOAD_CRC.hex()) + "] F:[" + str(static.ARQ_N_SENT_FRAMES+1) + "-" + str(static.ARQ_N_SENT_FRAMES + static.ARQ_TX_N_FRAMES_PER_BURST) + "] | T:[" + str(static.ARQ_N_SENT_FRAMES) + "/" + str(static.TX_BUFFER_SIZE) + "] [" + str(int(static.ARQ_N_SENT_FRAMES/(static.TX_BUFFER_SIZE)*100)).zfill(3) + "%] | A:[" + str(static.TX_N_RETRIES+1) + "/" + str(static.TX_N_MAX_RETRIES) + "]") - - + logging.info("ARQ | TX | F:[" + str(static.ARQ_N_SENT_FRAMES+1) + "-" + str(static.ARQ_N_SENT_FRAMES + static.ARQ_TX_N_FRAMES_PER_BURST) + "] | T:[" + str(static.ARQ_N_SENT_FRAMES) + "/" + str(static.TX_BUFFER_SIZE) + "] [" + str(int(static.ARQ_N_SENT_FRAMES/(static.TX_BUFFER_SIZE)*100)).zfill(3) + "%] | A:[" + str(static.TX_N_RETRIES+1) + "/" + str(static.TX_N_MAX_RETRIES) + "]") + # lets start a thread to transmit nonblocking TRANSMIT_ARQ_BURST_THREAD = threading.Thread(target=modem.transmit_arq_burst, name="TRANSMIT_ARQ_BURST") TRANSMIT_ARQ_BURST_THREAD.start() @@ -334,7 +326,7 @@ def transmit(data_out): # ----------- if no ACK received and out of retries.....stop frame sending if static.ARQ_ACK_RECEIVED == 0 and static.ARQ_FRAME_ACK_RECEIVED == 0 and static.ARQ_ACK_TIMEOUT == 1: logging.info("ARQ | TX | NO BURST OR FRAME ACK RECEIVED | DATA SHOULD BE RESEND!") - print(bytes(static.TX_BUFFER[static.ARQ_N_SENT_FRAMES])) + break #-------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT AND WE GOT A FRAME ACK diff --git a/modem.py b/modem.py index 5b55fdfa..6355ea27 100644 --- a/modem.py +++ b/modem.py @@ -19,6 +19,11 @@ import helpers import static import arq + + + + + class RF(): def __init__(self): @@ -179,11 +184,13 @@ class RF(): # 2 # arq crc # N # payload data + arqframe = frame_type + \ bytes([static.ARQ_TX_N_FRAMES_PER_BURST]) + \ static.ARQ_TX_N_CURRENT_ARQ_FRAME + \ static.ARQ_TX_N_TOTAL_ARQ_FRAMES + \ - static.ARQ_BURST_PAYLOAD_CRC + \ + static.MYCALLSIGN_CRC8 + \ + static.DXCALLSIGN_CRC8 + \ payload_data #print(arqframe) @@ -292,8 +299,9 @@ class RF(): frametype = int.from_bytes(bytes(data_bytes_out[:1]), "big") frame = frametype - 10 n_frames_per_burst = int.from_bytes(bytes(data_bytes_out[1:2]), "big") - if 50 >= frametype >= 10 and len(data_bytes_out) > 30: # --> The length check filters out random strings without CRC + if 50 >= frametype >= 10 and len(data_bytes_out) > 30: # --> The length check filters out random strings without CRC arq.data_received(bytes(data_bytes_out[:-2])) #send payload data to arq checker without CRC16 + else: print("MODE: " + str(data_mode) + " DATA: " + str(bytes(data_bytes_out))) diff --git a/static.py b/static.py index 90555be3..176c01e7 100644 --- a/static.py +++ b/static.py @@ -12,10 +12,21 @@ Created on Wed Dec 23 11:13:57 2020 #MODULATION TIME: 0.004580974578857422 #12 # 2 FRAME + PREAMBLE #AUDIO TIME: 14.750595331192017 #12 # 2 FRAME + PREAMBLE + +MYCALLSIGN = b'' +MYCALLSIGN_CRC8 = b'' + +DXCALLSIGN = b'' +DXCALLSIGN_CRC8 = b'' + + + + + # FreeDV Defaults FREEDV_RECEIVE = True -FREEDV_DATA_MODE = 12 +FREEDV_DATA_MODE = 10 FREEDV_SIGNALLING_MODE = 14 FREEDV_DATA_BYTES_PER_FRAME = 0