diff --git a/arq.py b/arq.py new file mode 100644 index 00000000..8262e26c --- /dev/null +++ b/arq.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Sun Dec 27 20:43:40 2020 + +@author: DJ2LS +""" +# CRC aller payloads via XOR scrambeln und dann eine CRC8 mitsenden + + +import logging +import crcengine +import threading + +import static +import modem +import other + + + +modem = modem.RF() +crc_algorithm = crcengine.new('crc16-ccitt-false') #load crc16 library + +static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_PAYLOAD_PER_FRAME - 6 + +#class ARQ(): +# +# def receive(bytes_in): +# +# print("TEST") + + +def receive(data_in): + print(data_in[:1]) + + +def transmit(data_out): + + static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_PAYLOAD_PER_FRAME - 6 + + 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)] # split incomming bytes to size of 30bytes, create a list and loop through it + static.TX_BUFFER_SIZE = len(static.TX_BUFFER) + logging.info("TX | TOTAL PAYLOAD BYTES/FRAMES TO SEND: " + str(len(data_out)) + " / " + str(static.TX_BUFFER_SIZE)) + + for n_raw_frame in range(0, static.TX_BUFFER_SIZE, static.ARQ_TX_N_FRAMES): # LOOP THROUGH DATA LIST with steps = ARQ_TX_N_FRAMES + print("N_RAW_FRAME: " + str(n_raw_frame)) + + # ----------- GENERATE PAYLOAD CRC FOR ARQ_TX_N_FRAMES + burst_total_payload = bytearray() + + for i in range(static.ARQ_TX_N_FRAMES): #bytearray(b'111111111111111111111111222222222222222222222222') + burst_total_payload = burst_total_payload + static.TX_BUFFER[n_raw_frame + i] + + burst_payload_crc = crc_algorithm(burst_total_payload) + burst_payload_crc = burst_payload_crc.to_bytes(2, byteorder='big') #b'\xa7\xd6' + print(burst_payload_crc) + + #-------------------- BUILD ARQBURSTS + arqburst = [] + for i in range(static.ARQ_TX_N_FRAMES): + + #print(n_raw_frame) + #print(i) + #print(n_raw_frame + i) + #print(static.TX_BUFFER[n_raw_frame + i]) + + frame_type = 10 + static.ARQ_TX_N_FRAMES + frame_type = bytes([frame_type]) + + payload_data = bytes(static.TX_BUFFER[n_raw_frame + i]) + + arqframe = frame_type + burst_payload_crc + payload_data + + arqburst.append(arqframe) + + + #--------------------------------------------- N ATTEMPTS TO SEND BURSTS IF ACK FAILS + for static.TX_N_RETRIES in range(static.TX_N_MAX_RETRIES): + + static.ACK_RECEIVED = 0 + + # ----------------------- Loop through ARQ FRAMES BUFFER with N = Numbers of frames which will be send at once + for n in range(static.ARQ_TX_N_FRAMES): + logging.info("TX | SENDING BURST " + str(n+1) + " / " + str(static.ARQ_TX_N_FRAMES)) + modem.Transmit(arqburst[n]) + #modem.RF.Transmit(arqburst[n]) + print(arqburst[n]) + + # --------------------------- START TIMER ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1 + static.ACK_TIMEOUT = 0 + timer = threading.Timer(static.ACK_TIMEOUT_SECONDS * static.ARQ_TX_N_FRAMES, other.timeout) + timer.start() + + # --------------------------- WHILE TIMEOUT NOT REACHED AND NO ACK RECEIVED --> LISTEN + logging.info("TX | WAITING FOR ACK") + + while static.ACK_TIMEOUT == 0 and static.ACK_RECEIVED == 0: + static.MODEM_RECEIVE = True + else: + logging.info("TX | ACK TIMEOUT - SENDING AGAIN") + + #--------------- BREAK LOOP IF ACK HAS BEEN RECEIVED + if static.ACK_RECEIVED == 1: + #static.TX_N_RETRIES = 3 + break + + # ----------- if no ACK received and out of retries.....stop frame sending + if static.ACK_RECEIVED == 0: + logging.info("TX | NO ACK RECEIVED | FRAME NEEDS TO BE RESEND!") + break + + + #-------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT + if n_raw_frame == static.TX_BUFFER_SIZE: + break + + logging.info("TX | BUFFER EMPTY") \ No newline at end of file diff --git a/modem.py b/modem.py index 2ea0c5c7..e527316d 100644 --- a/modem.py +++ b/modem.py @@ -15,6 +15,9 @@ import sys import logging import static +import arq + +#arq = arq.ARQ() @@ -58,7 +61,8 @@ class RF(): self.n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(self.freedv) self.nin = self.c_lib.freedv_nin(self.freedv) - + static.FREEDV_BYTES_PER_FRAME = self.bytes_per_frame + static.FREEDV_PAYLOAD_PER_FRAME = self.payload_per_frame # MODULATION-OUT OBJECT @@ -75,9 +79,11 @@ class RF(): return (c_ubyte * self.bytes_per_frame) # GET DATA AND MODULATE IT + def Transmit(self,data_out): mod_out = self.ModulationOut()() # new modulation object and get pointer to it + data_list = [data_out[i:i+self.payload_per_frame] for i in range(0, len(data_out), self.payload_per_frame)] # split incomming bytes to size of 30bytes, create a list and loop through it data_list_length = len(data_list) @@ -96,7 +102,8 @@ class RF(): crc = c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), self.payload_per_frame)) # generate CRC16 crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string buffer += crc # append crc16 to buffer - + + data = self.FrameBytes().from_buffer_copy(buffer) #change data format from bytearray to ctypes.u_byte and copy from buffer to data self.c_lib.freedv_rawdatatx(self.freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer @@ -162,16 +169,21 @@ class RF(): print(bytes(bytes_out[:-2])) self.c_lib.freedv_set_sync(self.freedv, 0) - - #print(bytes(bytes_out)) + + + + # CHECK IF FRAMETYPE CONTAINS ACK------------------------ + frametype = int.from_bytes(bytes(bytes_out[:1]), "big") + if 20 >= frametype >= 10 : + arq.receive(bytes(bytes_out)) # CHECK IF FRAME CONTAINS ACK------------------------ - if bytes(bytes_out[:6]) == b'REQACK': + #if bytes(bytes_out[:6]) == b'REQACK': - logging.info("RX | ACK REQUESTED!") - time.sleep(5) - logging.info("TX | SENDING ACK FRAME") - self.Transmit(b'ACK') + #logging.info("RX | ACK REQUESTED!") + #time.sleep(5) + #logging.info("TX | SENDING ACK FRAME") + #self.Transmit(b'ACK') #---------------------------------------------------- # CHECK IF FRAME CONTAINS ACK------------------------ diff --git a/other.py b/other.py index 1a8e69ec..59fc98d7 100644 --- a/other.py +++ b/other.py @@ -8,13 +8,11 @@ Created on Fri Dec 25 21:25:14 2020 import time import threading +import logging import static def timeout(): - print("TIMEOUT REACHED!") - #static.ACK_TIMEOUT = seconds - #time.sleep(seconds) static.ACK_TIMEOUT = 1 \ No newline at end of file diff --git a/tnc.py b/tnc.py index b69cffde..8a70d9cd 100644 --- a/tnc.py +++ b/tnc.py @@ -5,16 +5,25 @@ import socketserver import threading import logging +import crcengine +import ctypes +from ctypes import * + + + + -import modem import static #from other import * import other +import arq -modem = modem.RF() +#arq = arq.ARQ() +crc_algorithm = crcengine.new('crc16-ccitt-false') #load crc16 library + class TCPRequestHandler(socketserver.BaseRequestHandler): @@ -41,69 +50,25 @@ class TCPRequestHandler(socketserver.BaseRequestHandler): # BROADCAST PARSER ----------------------------------------------------------- if self.data.startswith(b'BC:'): + #import modem + #modem = modem.RF() + static.MODEM_RECEIVE = True ####### FALSE.... - #print(static.MODEM_RECEIVE) data = self.data.split(b'BC:') - daten = modem.Transmit(data[1]) + #modem.Transmit(data[1]) static.MODEM_RECEIVE = True - #print(static.MODEM_RECEIVE) + - - -# ACKNOWLEDGE PARSER ----------------------------------------------------------- +# SEND AN ARQ FRAME ----------------------------------------------------------- if self.data.startswith(b'ACK:'): static.MODEM_RECEIVE = True ############## FALSE - #print(static.MODEM_RECEIVE) - + data = self.data.split(b'ACK:') data_out = data[1] - - - static.TX_BUFFER = [data_out[i:i+24] for i in range(0, len(data_out), 24)] # split incomming bytes to size of 30bytes, create a list and loop through it - static.TX_BUFFER_SIZE = len(static.TX_BUFFER) - logging.info("TX | TOTAL PAYLOAD BYTES/FRAMES TO SEND: " + str(len(data_out)) + " / " + str(static.TX_BUFFER_SIZE)) - for frame in range(static.TX_BUFFER_SIZE): # LOOP THROUGH DATA LIST - - #--------------------------------------------- BUILD DATA PACKET - ack = b'REQACK' - data_to_transmit = ack + static.TX_BUFFER[frame] - - logging.info("TX | SENDING FRAME " + str(frame+1) + " / " + str(static.TX_BUFFER_SIZE)) - #--------------------------------------------------------------- - - - #--------------------------------------------- ATTEMPTS TO SEND A MESSAGE IF ACK FAILS - for static.TX_N_RETRIES in range(static.TX_N_MAX_RETRIES): - # --------------------------- SEND FRAME - static.ACK_RECEIVED = 0 - daten = modem.Transmit(data_to_transmit) - - # --------------------------- START TIMER ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1 - static.ACK_TIMEOUT = 0 - timer = threading.Timer(static.ACK_TIMEOUT_SECONDS, other.timeout) - timer.start() - - # --------------------------- WHILE TIMEOUT NOT REACHED AND NO ACK RECEIVED --> LISTEN - logging.info("TX | WAITING FOR ACK") - - while static.ACK_TIMEOUT == 0 and static.ACK_RECEIVED == 0: - static.MODEM_RECEIVE = True - - #--------------- BREAK LOOP IF ACK HAS BEEN RECEIVED - if static.ACK_RECEIVED == 1: - static.TX_N_RETRIES = 3 - break - - - #-------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT - if frame == static.TX_BUFFER_SIZE: - break - - logging.info("TX | BUFFER EMPTY") - + arq.transmit(data_out) \ No newline at end of file