diff --git a/arq.py b/arq.py index 4855155e..74bb96c8 100644 --- a/arq.py +++ b/arq.py @@ -13,36 +13,18 @@ from random import randrange import static import modem +modem = modem.RF() import helpers -#import tnc - - - - -modem = modem.RF() - -static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_DATA_PAYLOAD_PER_FRAME - 3 #6?! -static.ARQ_ACK_PAYLOAD_PER_FRAME = 14 - 2# 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 -# static.ARQ_N_TOTAL_ARQ_FRAMES + \ # 2 [4:6] # total number arq frames -# 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 static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = int.from_bytes(bytes(data_in[4:6]), "big") # get get total number of frames - static.ARQ_BURST_PAYLOAD_CRC = data_in[6:8] logging.debug("----------------------------------------------------------------") @@ -50,7 +32,6 @@ def data_received(data_in): logging.debug("ARQ_N_RX_FRAMES_PER_BURSTS: " + str(static.ARQ_N_RX_FRAMES_PER_BURSTS)) logging.debug("ARQ_RX_N_CURRENT_ARQ_FRAME: " + str(static.ARQ_RX_N_CURRENT_ARQ_FRAME)) logging.debug("ARQ_N_ARQ_FRAMES_PER_DATA_FRAME: " + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME)) - logging.debug("static.ARQ_BURST_PAYLOAD_CRC: " + str(static.ARQ_BURST_PAYLOAD_CRC)) logging.debug("----------------------------------------------------------------") @@ -63,7 +44,6 @@ def data_received(data_in): #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 - # delete frame buffer if first frame to make sure the buffer is cleared and no junks of a old frame is remaining if static.ARQ_RX_N_CURRENT_ARQ_FRAME == 1: static.ARQ_RX_FRAME_BUFFER = [] @@ -93,11 +73,8 @@ def data_received(data_in): static.ARQ_RX_BURST_BUFFER[static.ARQ_N_FRAME] = bytes(data_in) - #for i in range(len(static.ARQ_RX_BURST_BUFFER)): - # print(static.ARQ_RX_BURST_BUFFER[i]) - -# - ------------------------- ARQ BURST CHECKER - + +# - ------------------------- ARQ BURST CHECKER # run only if we recieved all ARQ FRAMES per ARQ BURST if static.ARQ_RX_BURST_BUFFER.count(None) == 1: #count nones logging.info("ARQ | TX | BURST ACK") @@ -116,7 +93,6 @@ def data_received(data_in): elif static.ARQ_N_FRAME == static.ARQ_N_RX_FRAMES_PER_BURSTS and static.ARQ_RX_BURST_BUFFER.count(None) != 1: # --------------- CHECK WHICH BURST FRAMES WE ARE MISSING ------------------------------------------- - missing_frames = b'' for burstnumber in range(1,len(static.ARQ_RX_BURST_BUFFER)): @@ -140,9 +116,7 @@ def data_received(data_in): modem.transmit_arq_ack(rpt_frame) - # ---------------------------- FRAME MACHINE - # --------------- IF LIST NOT CONTAINS "None" stick everything together complete_data_frame = bytearray() #print("static.ARQ_RX_FRAME_BUFFER.count(None)" + str(static.ARQ_RX_FRAME_BUFFER.count(None))) @@ -203,7 +177,6 @@ def data_received(data_in): #print("----------------------------------------------------------------") #print(static.RX_BUFFER[-1]) - #tnc.request.sendall(bytes(static.RX_BUFFER[-1])) #print("----------------------------------------------------------------") else: @@ -215,8 +188,8 @@ def data_received(data_in): 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 + static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_DATA_PAYLOAD_PER_FRAME - 8 + frame_header_length = 6 #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) @@ -367,8 +340,7 @@ def transmit(data_out): logging.debug("static.ARQ_N_SENT_FRAMES " + str(static.ARQ_N_SENT_FRAMES)) logging.debug("static.TX_BUFFER_SIZE " + str(static.TX_BUFFER_SIZE)) logging.debug("static.TX_N_RETRIES " + str(static.TX_N_RETRIES)) - logging.debug("static.TX_N_MAX_RETRIES " + str(static.TX_N_MAX_RETRIES)) - + logging.debug("static.TX_N_MAX_RETRIES " + str(static.TX_N_MAX_RETRIES)) logging.debug("static.ARQ_STATE " + str(static.ARQ_STATE)) logging.debug("static.ARQ_FRAME_ACK_RECEIVED " + str(static.ARQ_FRAME_ACK_RECEIVED)) logging.debug("static.ARQ_RX_FRAME_TIMEOUT " + str(static.ARQ_RX_FRAME_TIMEOUT)) @@ -419,12 +391,8 @@ def transmit(data_out): - - - # BURST MACHINE TO DEFINE N BURSTS PER FRAME ---> LATER WE CAN USE CHANNEL MESSUREMENT TO SET FRAMES PER BURST def get_n_frames_per_burst(): - #n_frames_per_burst = randrange(1,10) n_frames_per_burst = 2 return n_frames_per_burst @@ -432,19 +400,16 @@ def get_n_frames_per_burst(): def burst_ack_received(): - static.ARQ_ACK_RECEIVED = True #Force data loops of TNC to stop and continue with next frame def frame_ack_received(): - static.ARQ_FRAME_ACK_RECEIVED = True #Force data loops of TNC to stop and continue with next frame def burst_rpt_received(data_in): - static.ARQ_RPT_RECEIVED = True static.ARQ_RPT_FRAMES = [] diff --git a/helpers.py b/helpers.py index d821851a..54fae9e0 100644 --- a/helpers.py +++ b/helpers.py @@ -9,8 +9,8 @@ Created on Fri Dec 25 21:25:14 2020 import time import threading import logging -from colorlog import ColoredFormatter import crcengine +import pyaudio import static @@ -62,4 +62,36 @@ def arq_reset_frame_machine(): static.ARQ_N_SENT_FRAMES = 0 static.ARQ_TX_N_FRAMES_PER_BURST = 0 + +def setup_logging(): + + logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%H:%M:%S', level=logging.INFO) + logging.addLevelName( logging.DEBUG, "\033[1;36m%s\033[1;0m" % logging.getLevelName(logging.DEBUG)) + logging.addLevelName( logging.INFO, "\033[1;37m%s\033[1;0m" % logging.getLevelName(logging.INFO)) + logging.addLevelName( logging.WARNING, "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING)) + logging.addLevelName( logging.ERROR, "\033[1;31m%s\033[1;0m" % "FAILED") + #logging.addLevelName( logging.ERROR, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR)) + logging.addLevelName( logging.CRITICAL, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.CRITICAL)) + + logging.addLevelName( 25, "\033[1;32m%s\033[1;0m" % "SUCCESS") + logging.addLevelName( 24, "\033[1;34m%s\033[1;0m" % "DATA") + + + # https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output + #'DEBUG' : 37, # white + #'INFO' : 36, # cyan + #'WARNING' : 33, # yellow + #'ERROR' : 31, # red + #'CRITICAL': 41, # white on red bg + + + +def list_audio_devices(): + p = pyaudio.PyAudio() + devices = [] + for x in range(0, p.get_device_count()): + devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}") + + for line in devices: + print(line) diff --git a/main.py b/main.py index b2f1e49f..6361a702 100644 --- a/main.py +++ b/main.py @@ -11,24 +11,18 @@ import socketserver import argparse import logging import threading -import pyaudio -#import tnc import static import helpers - - - - def start_cmd_socket(): try: logging.info("SRV | STARTING TCP/IP CMD ON PORT: " + str(static.PORT)) socketserver.TCPServer.allow_reuse_address = True #https://stackoverflow.com/a/16641793 - cmdserver = socketserver.TCPServer((static.HOST, static.PORT), tnc.CMDTCPRequestHandler) + cmdserver = socketserver.TCPServer((static.HOST, static.PORT), sock.CMDTCPRequestHandler) cmdserver.serve_forever() finally: @@ -40,22 +34,19 @@ def start_data_socket(): try: logging.info("SRV | STARTING TCP/IP DATA ON PORT: " + str(static.PORT + 1)) socketserver.TCPServer.allow_reuse_address = True #https://stackoverflow.com/a/16641793 - dataserver = socketserver.TCPServer((static.HOST, static.PORT + 1), tnc.DATATCPRequestHandler) + dataserver = socketserver.TCPServer((static.HOST, static.PORT + 1), sock.DATATCPRequestHandler) dataserver.serve_forever() finally: - dataserver.server_close() + dataserver.server_close() + + + + -p = pyaudio.PyAudio() -devices = [] -for x in range(0, p.get_device_count()): - devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}") - -for line in devices: - print(line) @@ -63,6 +54,14 @@ for line in devices: if __name__ == '__main__': + # config logging + helpers.setup_logging() + + # list audio devices + helpers.list_audio_devices() + + + static.MYCALLSIGN = b'DJ2LS' static.MYCALLSIGN_CRC8 = helpers.get_crc_8(static.MYCALLSIGN) @@ -93,28 +92,9 @@ if __name__ == '__main__': static.AUDIO_OUTPUT_DEVICE = args.audio_output_device static.PORT = args.socket_port - import tnc # we need to wait until we got all parameters from argparse - - #-------------------------------------------- DEFINE LOGGING - logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%H:%M:%S', level=logging.INFO) - - logging.addLevelName( logging.DEBUG, "\033[1;36m%s\033[1;0m" % logging.getLevelName(logging.DEBUG)) - logging.addLevelName( logging.INFO, "\033[1;37m%s\033[1;0m" % logging.getLevelName(logging.INFO)) - logging.addLevelName( logging.WARNING, "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING)) - logging.addLevelName( logging.ERROR, "\033[1;31m%s\033[1;0m" % "FAILED") - #logging.addLevelName( logging.ERROR, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR)) - logging.addLevelName( logging.CRITICAL, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.CRITICAL)) - - logging.addLevelName( 25, "\033[1;32m%s\033[1;0m" % "SUCCESS") - logging.addLevelName( 24, "\033[1;34m%s\033[1;0m" % "DATA") + import sock # we need to wait until we got all parameters from argparse - # https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output - #'DEBUG' : 37, # white - #'INFO' : 36, # cyan - #'WARNING' : 33, # yellow - #'ERROR' : 31, # red - #'CRITICAL': 41, # white on red bg diff --git a/modem.py b/modem.py index 38ae7585..6579f012 100644 --- a/modem.py +++ b/modem.py @@ -10,7 +10,8 @@ import ctypes from ctypes import * import pathlib import pyaudio -import sys +import audioop +#import sys import logging import time import threading @@ -19,7 +20,7 @@ import helpers import static import arq -import audioop + diff --git a/sock.py b/sock.py new file mode 100644 index 00000000..f5eb3895 --- /dev/null +++ b/sock.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Dec 25 21:25:14 2020 + +@author: DJ2LS +""" + +import socketserver +import threading +import logging + + +import static +import arq + +class DATATCPRequestHandler(socketserver.BaseRequestHandler): + + def handle(self): + + self.data = bytes() + while True: + chunk = self.request.recv(8192)#.strip() + self.data += chunk + if chunk.endswith(b'\n'): + break + + + +class CMDTCPRequestHandler(socketserver.BaseRequestHandler): + + def handle(self): + + self.data = bytes() + while True: + chunk = self.request.recv(8192)#.strip() + self.data += chunk + if chunk.endswith(b'\n'): + break + + + + # self.request is the TCP socket connected to the client + #self.data = self.request.recv(1024).strip() +### self.data = self.request.recv(1000000).strip() + + # interrupt listening loop "while true" by setting MODEM_RECEIVE to False + #if len(self.data) > 0: + # static.MODEM_RECEIVE = False + + + ####print("{} wrote:".format(self.client_address[0])) + ####print(self.data) + + # just send back the same data, but upper-cased + #####self.request.sendall(self.data.upper()) + + #if self.data == b'TEST': + #logging.info("DER TEST KLAPPT! HIER KOMMT DER COMMAND PARSER HIN!") + if self.data.startswith(b'SHOWBUFFERSIZE'): + self.request.sendall(bytes(static.RX_BUFFER[-1])) + print(static.RX_BUFFER_SIZE) + +# BROADCAST PARSER ----------------------------------------------------------- + + if self.data.startswith(b'BC:'): + #import modem + #modem = modem.RF() + + data = self.data.split(b'BC:') + #modem.Transmit(data[1]) + + + +# SEND AN ARQ FRAME ----------------------------------------------------------- + + if self.data.startswith(b'ARQ:'): + + data = self.data.split(b'ARQ:') + data_out = data[1] + + TRANSMIT_ARQ = threading.Thread(target=arq.transmit, args=[data_out], name="TRANSMIT_ARQ") + TRANSMIT_ARQ.start() + diff --git a/static.py b/static.py index 4fa71047..f1613d74 100644 --- a/static.py +++ b/static.py @@ -5,23 +5,21 @@ Created on Wed Dec 23 11:13:57 2020 @author: DJ2LS """ -# ADDITION MESSUREMENT: -#AUDIO TIME: 7.451462268829346 #12 # 1 FRAME + PREAMBLE -#MODULATION TIME: 0.002051115036010742 #12 # 1 FRAME + PREAMBLE - -#MODULATION TIME: 0.004580974578857422 #12 # 2 FRAME + PREAMBLE -#AUDIO TIME: 14.750595331192017 #12 # 2 FRAME + PREAMBLE - +# Operator Defaults MYCALLSIGN = b'' MYCALLSIGN_CRC8 = b'' DXCALLSIGN = b'' DXCALLSIGN_CRC8 = b'' +MYGRID = b'' +#--------------------------------- - - +# Server Defaults +HOST = "localhost" +PORT = 3000 +#--------------------------------- # FreeDV Defaults FREEDV_RECEIVE = True @@ -33,13 +31,9 @@ FREEDV_DATA_BYTES_PER_FRAME = 0 FREEDV_DATA_PAYLOAD_PER_FRAME = 0 FREEDV_SIGNALLING_BYTES_PER_FRAME = 0 FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = 0 +#--------------------------------- -# Server Defaults -HOST = "localhost" -PORT = 3000 - - -#AUdio Defaults +#Audio Defaults AUDIO_INPUT_DEVICE = 1 AUDIO_OUTPUT_DEVICE = 1 #TX_SAMPLE_STATE = None @@ -50,20 +44,17 @@ AUDIO_OUTPUT_DEVICE = 1 MODEM_SAMPLE_RATE = 8000 #8000 AUDIO_FRAMES_PER_BUFFER = 2048 AUDIO_CHANNELS = 1 +#--------------------------------- - -#TNC DEFAULTS -# ARQ -TX_N_MAX_RETRIES = 3 +#ARQ DEFAULTS +TX_N_MAX_RETRIES = 10 TX_N_RETRIES = 0 - - ARQ_TX_N_FRAMES_PER_BURST = 0 ARQ_TX_N_BURSTS = 0 ARQ_PAYLOAD_PER_FRAME = 0 -ARQ_ACK_WAITING_FOR_ID = 0 + ARQ_RX_BURST_BUFFER = [] ARQ_RX_FRAME_BUFFER = [] ARQ_RX_FRAME_N_BURSTS = 0 @@ -79,22 +70,20 @@ ARQ_RX_N_CURRENT_ARQ_FRAME = 0 ## ARQ_N_RX_ARQ_FRAMES = 0 # total number of received frames - ARQ_N_RX_FRAMES_PER_BURSTS = 0 # NUMBER OF FRAMES WE ARE WAITING FOR --> GOT DATA FROM RECEIVED FRAME ARQ_ACK_PAYLOAD_PER_FRAME = 0 # PAYLOAD per ACK frame ARQ_ACK_RECEIVED = False # set to 1 if ACK received ARQ_RX_ACK_TIMEOUT = False # set to 1 if timeut reached -ARQ_RX_ACK_TIMEOUT_SECONDS = 5.0 #timeout for waiting for ACK frames - +ARQ_RX_ACK_TIMEOUT_SECONDS = 10.0 #timeout for waiting for ACK frames ARQ_FRAME_ACK_RECEIVED = False # set to 1 if FRAME ACK received ARQ_RX_FRAME_TIMEOUT = False -ARQ_RX_FRAME_TIMEOUT_SECONDS = 5.0 +ARQ_RX_FRAME_TIMEOUT_SECONDS = 10.0 ARQ_RX_RPT_TIMEOUT = False -ARQ_RX_RPT_TIMEOUT_SECONDS = 5.0 +ARQ_RX_RPT_TIMEOUT_SECONDS = 10.0 ARQ_RPT_RECEIVED = False #indicate if RPT frame has been received ARQ_RPT_FRAMES = [] #buffer for frames which are requested to repeat