mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
better pep8 conformity
This commit is contained in:
parent
21eb8fa12b
commit
5c7e05ef70
128
tnc/daemon.py
128
tnc/daemon.py
|
@ -7,37 +7,38 @@ Created on Tue Dec 22 16:58:45 2020
|
|||
|
||||
"""
|
||||
|
||||
|
||||
import argparse
|
||||
import threading
|
||||
import socketserver
|
||||
import pyaudio
|
||||
import time
|
||||
import ujson as json
|
||||
import subprocess
|
||||
import os
|
||||
import static
|
||||
import psutil
|
||||
import sys
|
||||
import subprocess
|
||||
import ujson as json
|
||||
import psutil
|
||||
import serial.tools.list_ports
|
||||
import pyaudio
|
||||
import static
|
||||
|
||||
def start_daemon():
|
||||
|
||||
try:
|
||||
print("SRV | STARTING TCP/IP SOCKET FOR CMD ON PORT: " + str(PORT))
|
||||
socketserver.TCPServer.allow_reuse_address = True # https://stackoverflow.com/a/16641793
|
||||
daemon = socketserver.TCPServer(('0.0.0.0', PORT), CMDTCPRequestHandler)
|
||||
# https://stackoverflow.com/a/16641793
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
daemon = socketserver.TCPServer(
|
||||
('0.0.0.0', PORT), CMDTCPRequestHandler)
|
||||
daemon.serve_forever()
|
||||
|
||||
finally:
|
||||
daemon.server_close()
|
||||
|
||||
|
||||
|
||||
|
||||
class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
print("Client connected...")
|
||||
|
||||
print("Client connected...")
|
||||
|
||||
# loop through socket buffer until timeout is reached. then close buffer
|
||||
socketTimeout = time.time() + 3
|
||||
while socketTimeout > time.time():
|
||||
|
@ -47,23 +48,23 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
#data = str(self.request.recv(1024), 'utf-8')
|
||||
|
||||
data = bytes()
|
||||
|
||||
|
||||
# we need to loop through buffer until end of chunk is reached or timeout occured
|
||||
while True and socketTimeout > time.time():
|
||||
chunk = self.request.recv(45)
|
||||
data += chunk
|
||||
if chunk.endswith(b'}\n') or chunk.endswith(b'}'): # or chunk.endswith(b'\n'):
|
||||
# or chunk.endswith(b'\n'):
|
||||
if chunk.endswith(b'}\n') or chunk.endswith(b'}'):
|
||||
break
|
||||
data = data[:-1] # remove b'\n'
|
||||
data = str(data, 'utf-8')
|
||||
|
||||
|
||||
|
||||
if len(data) > 0:
|
||||
socketTimeout = time.time() + 3
|
||||
|
||||
|
||||
# convert data to json object
|
||||
# we need to do some error handling in case of socket timeout
|
||||
|
||||
|
||||
try:
|
||||
# only read first line of string. multiple lines will cause an json error
|
||||
# this occurs possibly, if we are getting data too fast
|
||||
|
@ -72,41 +73,44 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
|
||||
# GET COMMANDS
|
||||
# "command" : "..."
|
||||
|
||||
|
||||
# SET COMMANDS
|
||||
# "command" : "..."
|
||||
# "parameter" : " ..."
|
||||
|
||||
|
||||
# DATA COMMANDS
|
||||
# "command" : "..."
|
||||
# "type" : "..."
|
||||
# "dxcallsign" : "..."
|
||||
# "data" : "..."
|
||||
|
||||
|
||||
# print(received_json)
|
||||
#print(received_json["type"])
|
||||
#print(received_json["command"])
|
||||
#try:
|
||||
# print(received_json["type"])
|
||||
# print(received_json["command"])
|
||||
# try:
|
||||
|
||||
if received_json["type"] == 'SET' and received_json["command"] == 'STARTTNC' and not static.TNCSTARTED:
|
||||
rx_audio = str(received_json["parameter"][0]["rx_audio"])
|
||||
tx_audio = str(received_json["parameter"][0]["tx_audio"])
|
||||
deviceid = str(received_json["parameter"][0]["deviceid"])
|
||||
deviceport = str(received_json["parameter"][0]["deviceport"])
|
||||
serialspeed = str(received_json["parameter"][0]["serialspeed"])
|
||||
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
|
||||
deviceport = str(
|
||||
received_json["parameter"][0]["deviceport"])
|
||||
serialspeed = str(
|
||||
received_json["parameter"][0]["serialspeed"])
|
||||
pttprotocol = str(
|
||||
received_json["parameter"][0]["pttprotocol"])
|
||||
pttport = str(received_json["parameter"][0]["pttport"])
|
||||
print("---- STARTING TNC !")
|
||||
print(received_json["parameter"][0])
|
||||
|
||||
#command = "--rx "+ rx_audio +" \
|
||||
# command = "--rx "+ rx_audio +" \
|
||||
# --tx "+ tx_audio +" \
|
||||
# --deviceport "+ deviceport +" \
|
||||
# --deviceid "+ deviceid + " \
|
||||
# --serialspeed "+ serialspeed + " \
|
||||
# --pttprotocol "+ pttprotocol + " \
|
||||
# --pttport "+ pttport
|
||||
|
||||
|
||||
# list of parameters, necessary for running subprocess command as a list
|
||||
options = []
|
||||
options.append('--rx')
|
||||
|
@ -123,7 +127,7 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
options.append(pttprotocol)
|
||||
options.append('--pttport')
|
||||
options.append(pttport)
|
||||
|
||||
|
||||
# try running tnc from binary, else run from source
|
||||
# this helps running the tnc in a developer environment
|
||||
try:
|
||||
|
@ -141,20 +145,20 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
command += options
|
||||
p = subprocess.Popen(command)
|
||||
print("running TNC from source...")
|
||||
|
||||
static.TNCPROCESS = p#.pid
|
||||
|
||||
static.TNCPROCESS = p # .pid
|
||||
static.TNCSTARTED = True
|
||||
|
||||
if received_json["type"] == 'SET' and received_json["command"] == 'STOPTNC':
|
||||
parameter = received_json["parameter"]
|
||||
static.TNCPROCESS.kill()
|
||||
print("KILLING PROCESS ------------")
|
||||
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
||||
static.TNCSTARTED = False
|
||||
|
||||
|
||||
if received_json["type"] == 'GET' and received_json["command"] == 'DAEMON_STATE':
|
||||
|
||||
data = {'COMMAND' : 'DAEMON_STATE', 'DAEMON_STATE' : [], 'INPUT_DEVICES': [], 'OUTPUT_DEVICES': [], 'SERIAL_DEVICES': [], "CPU": str(psutil.cpu_percent()),"RAM": str(psutil.virtual_memory().percent), "VERSION": "0.1-prototype"}
|
||||
data = {'COMMAND': 'DAEMON_STATE', 'DAEMON_STATE': [], 'INPUT_DEVICES': [], 'OUTPUT_DEVICES': [], 'SERIAL_DEVICES': [
|
||||
], "CPU": str(psutil.cpu_percent()), "RAM": str(psutil.virtual_memory().percent), "VERSION": "0.1-prototype"}
|
||||
|
||||
if static.TNCSTARTED:
|
||||
data["DAEMON_STATE"].append({"STATUS": "running"})
|
||||
|
@ -164,36 +168,40 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
# UPDATE LIST OF AUDIO DEVICES
|
||||
p = pyaudio.PyAudio()
|
||||
for i in range(0, p.get_device_count()):
|
||||
|
||||
maxInputChannels = p.get_device_info_by_host_api_device_index(0,i).get('maxInputChannels')
|
||||
maxOutputChannels = p.get_device_info_by_host_api_device_index(0,i).get('maxOutputChannels')
|
||||
name = p.get_device_info_by_host_api_device_index(0,i).get('name')
|
||||
|
||||
if maxInputChannels > 0:
|
||||
data["INPUT_DEVICES"].append({"ID": i, "NAME" : str(name)})
|
||||
if maxOutputChannels > 0:
|
||||
data["OUTPUT_DEVICES"].append({"ID": i, "NAME" : str(name)})
|
||||
|
||||
|
||||
maxInputChannels = p.get_device_info_by_host_api_device_index(
|
||||
0, i).get('maxInputChannels')
|
||||
maxOutputChannels = p.get_device_info_by_host_api_device_index(
|
||||
0, i).get('maxOutputChannels')
|
||||
name = p.get_device_info_by_host_api_device_index(
|
||||
0, i).get('name')
|
||||
|
||||
if maxInputChannels > 0:
|
||||
data["INPUT_DEVICES"].append(
|
||||
{"ID": i, "NAME": str(name)})
|
||||
if maxOutputChannels > 0:
|
||||
data["OUTPUT_DEVICES"].append(
|
||||
{"ID": i, "NAME": str(name)})
|
||||
|
||||
# UPDATE LIST OF SERIAL DEVICES
|
||||
ports = serial.tools.list_ports.comports()
|
||||
for port, desc, hwid in ports:
|
||||
data["SERIAL_DEVICES"].append({"PORT": str(port), "DESCRIPTION" : str(desc)})
|
||||
data["SERIAL_DEVICES"].append(
|
||||
{"PORT": str(port), "DESCRIPTION": str(desc)})
|
||||
|
||||
#print(data)
|
||||
# print(data)
|
||||
jsondata = json.dumps(data)
|
||||
self.request.sendall(bytes(jsondata, encoding))
|
||||
|
||||
|
||||
|
||||
#exception, if JSON cant be decoded
|
||||
#except Exception as e:
|
||||
|
||||
# exception, if JSON cant be decoded
|
||||
# except Exception as e:
|
||||
except ValueError as e:
|
||||
print("############ START OF ERROR #####################")
|
||||
print('DAEMON PROGRAM ERROR: %s' %str(e))
|
||||
print('DAEMON PROGRAM ERROR: %s' % str(e))
|
||||
print("Wrong command")
|
||||
print(data)
|
||||
print(e)
|
||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||
exc_type, exc_tb = sys.exc_info()
|
||||
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||
print(exc_type, fname, exc_tb.tb_lineno)
|
||||
print("############ END OF ERROR #######################")
|
||||
|
@ -203,13 +211,11 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description='Simons TEST TNC')
|
||||
PARSER.add_argument('--port', dest="socket_port", default=3001, help="Socket port", type=int)
|
||||
PARSER.add_argument('--port', dest="socket_port",
|
||||
default=3001, help="Socket port", type=int)
|
||||
|
||||
|
||||
|
||||
ARGS = PARSER.parse_args()
|
||||
PORT = ARGS.socket_port
|
||||
|
||||
|
@ -217,9 +223,3 @@ if __name__ == '__main__':
|
|||
|
||||
DAEMON_THREAD = threading.Thread(target=start_daemon, name="daemon")
|
||||
DAEMON_THREAD.start()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
133
tnc/helpers.py
133
tnc/helpers.py
|
@ -15,13 +15,13 @@ import crcengine
|
|||
import static
|
||||
import data_handler
|
||||
|
||||
|
||||
def wait(seconds):
|
||||
timeout = time.time() + seconds
|
||||
|
||||
|
||||
while time.time() < timeout:
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
|
||||
|
||||
def get_crc_8(data):
|
||||
"""
|
||||
|
@ -50,30 +50,34 @@ 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)
|
||||
data_channel_keep_alive_watchdog()
|
||||
|
||||
|
||||
def data_channel_keep_alive_watchdog():
|
||||
"""
|
||||
Author: DJ2LS
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY': # and not static.ARQ_SEND_KEEP_ALIVE:
|
||||
# and not static.ARQ_SEND_KEEP_ALIVE:
|
||||
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY':
|
||||
time.sleep(0.01)
|
||||
if static.ARQ_DATA_CHANNEL_LAST_RECEIVED + 30 > time.time():
|
||||
pass
|
||||
else:
|
||||
static.ARQ_DATA_CHANNEL_LAST_RECEIVED = 0
|
||||
logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<<T>>[" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]")
|
||||
logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<<T>>[" + str(
|
||||
static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]")
|
||||
arq_reset_frame_machine()
|
||||
|
||||
|
||||
|
@ -116,128 +120,141 @@ def arq_reset_frame_machine():
|
|||
static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = 0
|
||||
static.ARQ_FRAME_BOF_RECEIVED = False
|
||||
static.ARQ_FRAME_EOF_RECEIVED = False
|
||||
|
||||
|
||||
static.ARQ_RX_BURST_BUFFER = []
|
||||
static.ARQ_RX_FRAME_BUFFER = []
|
||||
|
||||
|
||||
static.TNC_STATE = 'IDLE'
|
||||
static.ARQ_STATE = 'IDLE'
|
||||
###static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = int(time.time()) # we need to reset the counter at this point
|
||||
# static.ARQ_CONNECTION_KEEP_ALIVE_RECEIVED = int(time.time()) # we need to reset the counter at this point
|
||||
###static.ARQ_SEND_KEEP_ALIVE = True
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.ARQ_READY_FOR_DATA = False
|
||||
|
||||
static.ARQ_START_OF_TRANSMISSION = 0
|
||||
|
||||
|
||||
def calculate_transfer_rate():
|
||||
if static.ARQ_START_OF_TRANSMISSION > 0:
|
||||
static.TOTAL_TRANSMISSION_TIME = time.time() - static.ARQ_START_OF_TRANSMISSION
|
||||
|
||||
|
||||
print("ARQ_N_ARQ_FRAMES_PER_DATA_FRAME " + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME))
|
||||
print("ARQ_RX_N_CURRENT_ARQ_FRAME " + str(static.ARQ_RX_N_CURRENT_ARQ_FRAME))
|
||||
|
||||
|
||||
print("ARQ_N_ARQ_FRAMES_PER_DATA_FRAME " +
|
||||
str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME))
|
||||
print("ARQ_RX_N_CURRENT_ARQ_FRAME " +
|
||||
str(static.ARQ_RX_N_CURRENT_ARQ_FRAME))
|
||||
|
||||
arq_n_arq_frames_per_data_frame = static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME
|
||||
arq_rx_n_current_arq_frame = static.ARQ_RX_N_CURRENT_ARQ_FRAME
|
||||
|
||||
|
||||
if static.TX_BUFFER_SIZE == 0:
|
||||
total_n_frames = arq_n_arq_frames_per_data_frame
|
||||
elif arq_n_arq_frames_per_data_frame == 0:
|
||||
total_n_frames = static.TX_BUFFER_SIZE
|
||||
else:
|
||||
total_n_frames = 0
|
||||
|
||||
|
||||
if static.TOTAL_TRANSMISSION_TIME > 0:
|
||||
#total_transmission_time = time.time() - static.ARQ_START_OF_TRANSMISSION
|
||||
total_transmission_time = static.TOTAL_TRANSMISSION_TIME
|
||||
print("total_transmission_time: " + str(total_transmission_time))
|
||||
total_transmission_time = static.TOTAL_TRANSMISSION_TIME
|
||||
print("total_transmission_time: " + str(total_transmission_time))
|
||||
print("static.TOTAL_BYTES: " + str(static.TOTAL_BYTES))
|
||||
|
||||
|
||||
static.ARQ_BITS_PER_SECOND = int(
|
||||
(static.TOTAL_BYTES * 8) / total_transmission_time)
|
||||
static.ARQ_BYTES_PER_MINUTE = int(
|
||||
((static.TOTAL_BYTES) / total_transmission_time) * 60)
|
||||
|
||||
static.ARQ_BITS_PER_SECOND = int((static.TOTAL_BYTES * 8) / total_transmission_time)
|
||||
static.ARQ_BYTES_PER_MINUTE = int(((static.TOTAL_BYTES) / total_transmission_time) * 60)
|
||||
|
||||
burst_bytes = static.ARQ_PAYLOAD_PER_FRAME * static.ARQ_N_RX_FRAMES_PER_BURSTS
|
||||
burst_transmission_time = time.time() - static.ARQ_START_OF_BURST
|
||||
print("BURST TRANSMISSION TIME: " + str(burst_transmission_time))
|
||||
static.ARQ_BITS_PER_SECOND_BURST = int((burst_bytes * 8) / burst_transmission_time)
|
||||
static.ARQ_BYTES_PER_MINUTE_BURST = int(((burst_bytes) / burst_transmission_time) * 60)
|
||||
print("static.ARQ_BITS_PER_SECOND_BURST: " + str(static.ARQ_BITS_PER_SECOND_BURST))
|
||||
print("static.ARQ_BYTES_PER_MINUTE_BURST: " + str(static.ARQ_BYTES_PER_MINUTE_BURST))
|
||||
|
||||
static.ARQ_BITS_PER_SECOND_BURST = int(
|
||||
(burst_bytes * 8) / burst_transmission_time)
|
||||
static.ARQ_BYTES_PER_MINUTE_BURST = int(
|
||||
((burst_bytes) / burst_transmission_time) * 60)
|
||||
print("static.ARQ_BITS_PER_SECOND_BURST: " +
|
||||
str(static.ARQ_BITS_PER_SECOND_BURST))
|
||||
print("static.ARQ_BYTES_PER_MINUTE_BURST: " +
|
||||
str(static.ARQ_BYTES_PER_MINUTE_BURST))
|
||||
|
||||
# PERCENTAGE FOR TRANSMITTING
|
||||
if static.TX_BUFFER_SIZE > 0:
|
||||
print("static.ARQ_N_SENT_FRAMES: " + str(static.ARQ_N_SENT_FRAMES))
|
||||
static.ARQ_TRANSMISSION_PERCENT = int((static.ARQ_N_SENT_FRAMES / static.TX_BUFFER_SIZE) * 100)
|
||||
static.ARQ_TRANSMISSION_PERCENT = int(
|
||||
(static.ARQ_N_SENT_FRAMES / static.TX_BUFFER_SIZE) * 100)
|
||||
|
||||
# PERCENTAGE FOR RECEIVING
|
||||
elif arq_n_arq_frames_per_data_frame > 0:
|
||||
static.ARQ_TRANSMISSION_PERCENT = int((static.ARQ_RX_N_CURRENT_ARQ_FRAME / static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) * 100)
|
||||
|
||||
static.ARQ_TRANSMISSION_PERCENT = int(
|
||||
(static.ARQ_RX_N_CURRENT_ARQ_FRAME / static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) * 100)
|
||||
|
||||
else:
|
||||
static.ARQ_TRANSMISSION_PERCENT = 0.0
|
||||
|
||||
print("static.ARQ_TRANSMISSION_PERCENT: " + str(static.ARQ_TRANSMISSION_PERCENT))
|
||||
static.ARQ_TRANSMISSION_PERCENT = 0.0
|
||||
|
||||
print("static.ARQ_TRANSMISSION_PERCENT: " +
|
||||
str(static.ARQ_TRANSMISSION_PERCENT))
|
||||
print("static.ARQ_BYTES_PER_MINUTE: " + str(static.ARQ_BYTES_PER_MINUTE))
|
||||
print("static.ARQ_BITS_PER_SECOND: " + str(static.ARQ_BITS_PER_SECOND))
|
||||
return [static.ARQ_BITS_PER_SECOND, static.ARQ_BYTES_PER_MINUTE, static.ARQ_BITS_PER_SECOND_BURST, static.ARQ_BYTES_PER_MINUTE_BURST]
|
||||
|
||||
|
||||
def add_to_heard_stations(dxcallsign,dxgrid, datatype, snr):
|
||||
|
||||
def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr):
|
||||
# check if buffer empty
|
||||
if len(static.HEARD_STATIONS) == 0:
|
||||
static.HEARD_STATIONS.append([dxcallsign,dxgrid, int(time.time()), datatype, snr])
|
||||
static.HEARD_STATIONS.append(
|
||||
[dxcallsign, dxgrid, int(time.time()), datatype, snr])
|
||||
# if not, we search and update
|
||||
else:
|
||||
for i in range(0, len(static.HEARD_STATIONS)):
|
||||
# update callsign with new timestamp
|
||||
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
||||
static.HEARD_STATIONS[i] = [dxcallsign,dxgrid, int(time.time()), datatype, snr]
|
||||
static.HEARD_STATIONS[i] = [dxcallsign,
|
||||
dxgrid, int(time.time()), datatype, snr]
|
||||
break
|
||||
# insert if nothing found
|
||||
if i == len(static.HEARD_STATIONS) - 1:
|
||||
static.HEARD_STATIONS.append([dxcallsign,dxgrid, int(time.time()), datatype, snr])
|
||||
static.HEARD_STATIONS.append(
|
||||
[dxcallsign, dxgrid, int(time.time()), datatype, snr])
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
# for idx, item in enumerate(static.HEARD_STATIONS):
|
||||
# if dxcallsign in item:
|
||||
# item = [dxcallsign, int(time.time())]
|
||||
# static.HEARD_STATIONS[idx] = item
|
||||
|
||||
# static.HEARD_STATIONS[idx] = item
|
||||
|
||||
def setup_logging():
|
||||
"""
|
||||
Author: DJ2LS
|
||||
|
||||
Set the custom logging format so we can use colors
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
"""
|
||||
|
||||
logging.basicConfig(level=logging.INFO, \
|
||||
encoding='utf-8', \
|
||||
format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', \
|
||||
datefmt='%H:%M:%S', \
|
||||
handlers=[logging.FileHandler("codec2-FreeDATA-TNC.log"),logging.StreamHandler()]
|
||||
)
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
encoding='utf-8',
|
||||
format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s',
|
||||
datefmt='%H:%M:%S',
|
||||
handlers=[logging.FileHandler(
|
||||
"codec2-FreeDATA-TNC.log"), logging.StreamHandler()]
|
||||
)
|
||||
|
||||
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.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(
|
||||
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")
|
||||
|
||||
|
||||
|
|
602
tnc/modem.py
602
tnc/modem.py
|
@ -5,25 +5,24 @@ Created on Wed Dec 23 07:04:24 2020
|
|||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
import sys
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import pathlib
|
||||
import pyaudio
|
||||
import audioop
|
||||
import asyncio
|
||||
#import sys
|
||||
#import asyncio
|
||||
import logging
|
||||
import time
|
||||
import threading
|
||||
import atexit
|
||||
|
||||
import numpy as np
|
||||
import pyaudio
|
||||
import helpers
|
||||
import static
|
||||
import data_handler
|
||||
|
||||
import sys
|
||||
#sys.path.append("hamlib/linux")
|
||||
|
||||
# sys.path.append("hamlib/linux")
|
||||
try:
|
||||
import Hamlib
|
||||
print("running Hamlib from Sys Path")
|
||||
|
@ -34,7 +33,7 @@ else:
|
|||
# place for rigctld
|
||||
pass
|
||||
|
||||
import numpy as np
|
||||
|
||||
#import rigctld
|
||||
#rigctld = rigctld.Rigctld()
|
||||
|
||||
|
@ -42,27 +41,28 @@ import numpy as np
|
|||
MODEM_STATS_NR_MAX = 320
|
||||
MODEM_STATS_NC_MAX = 51
|
||||
|
||||
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Nc", ctypes.c_int),
|
||||
("snr_est", ctypes.c_float),
|
||||
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX),
|
||||
("nr", ctypes.c_int),
|
||||
("sync", ctypes.c_int),
|
||||
("foff", ctypes.c_float),
|
||||
("rx_timing", ctypes.c_float),
|
||||
("clock_offset", ctypes.c_float),
|
||||
("sync_metric", ctypes.c_float),
|
||||
("pre", ctypes.c_int),
|
||||
("post", ctypes.c_int),
|
||||
("uw_fails", ctypes.c_int),
|
||||
]
|
||||
_fields_ = [
|
||||
("Nc", ctypes.c_int),
|
||||
("snr_est", ctypes.c_float),
|
||||
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX),
|
||||
("nr", ctypes.c_int),
|
||||
("sync", ctypes.c_int),
|
||||
("foff", ctypes.c_float),
|
||||
("rx_timing", ctypes.c_float),
|
||||
("clock_offset", ctypes.c_float),
|
||||
("sync_metric", ctypes.c_float),
|
||||
("pre", ctypes.c_int),
|
||||
("post", ctypes.c_int),
|
||||
("uw_fails", ctypes.c_int),
|
||||
]
|
||||
|
||||
|
||||
class RF():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# -------------------------------------------- LOAD FREEDV
|
||||
try:
|
||||
# we check at first for libcodec2 in root - necessary if we want to run it inside a pyinstaller binary
|
||||
|
@ -99,20 +99,23 @@ class RF():
|
|||
self.audio_writing_to_stream = False
|
||||
# --------------------------------------------START DECODER THREAD
|
||||
|
||||
DECODER_THREAD = threading.Thread(target=self.receive, name="DECODER_THREAD")
|
||||
DECODER_THREAD = threading.Thread(
|
||||
target=self.receive, name="DECODER_THREAD")
|
||||
DECODER_THREAD.start()
|
||||
|
||||
PLAYBACK_THREAD = threading.Thread(target=self.play_audio, name="PLAYBACK_THREAD")
|
||||
PLAYBACK_THREAD = threading.Thread(
|
||||
target=self.play_audio, name="PLAYBACK_THREAD")
|
||||
PLAYBACK_THREAD.start()
|
||||
|
||||
self.fft_data = bytes()
|
||||
FFT_THREAD = threading.Thread(target=self.calculate_fft, name="FFT_THREAD")
|
||||
FFT_THREAD = threading.Thread(
|
||||
target=self.calculate_fft, name="FFT_THREAD")
|
||||
FFT_THREAD.start()
|
||||
|
||||
# --------------------------------------------CONFIGURE HAMLIB
|
||||
#my_rig.set_ptt(Hamlib.RIG_PTT_RIG,0)
|
||||
#my_rig.set_ptt(Hamlib.RIG_PTT_SERIAL_DTR,0)
|
||||
#my_rig.set_ptt(Hamlib.RIG_PTT_SERIAL_RTS,1)
|
||||
# my_rig.set_ptt(Hamlib.RIG_PTT_RIG,0)
|
||||
# my_rig.set_ptt(Hamlib.RIG_PTT_SERIAL_DTR,0)
|
||||
# my_rig.set_ptt(Hamlib.RIG_PTT_SERIAL_RTS,1)
|
||||
#self.my_rig.set_conf("dtr_state", "OFF")
|
||||
#my_rig.set_conf("rts_state", "OFF")
|
||||
#self.my_rig.set_conf("ptt_type", "RTS")
|
||||
|
@ -128,221 +131,241 @@ class RF():
|
|||
self.my_rig.set_conf("serial_handshake", "None")
|
||||
self.my_rig.set_conf("stop_bits", "1")
|
||||
self.my_rig.set_conf("data_bits", "8")
|
||||
|
||||
|
||||
if static.HAMLIB_PTT_TYPE == 'RIG':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
||||
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'DTR-H':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "HIGH")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'DTR-L':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "LOW")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'RTS':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
||||
self.my_rig.set_conf("dtr_state", "OFF")
|
||||
self.my_rig.set_conf("ptt_type", "RTS")
|
||||
|
||||
self.my_rig.set_conf("ptt_type", "RTS")
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'PARALLEL':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
||||
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'MICDATA':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
||||
|
||||
|
||||
elif static.HAMLIB_PTT_TYPE == 'CM108':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
||||
|
||||
|
||||
else: # static.HAMLIB_PTT_TYPE == 'RIG_PTT_NONE':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||
|
||||
|
||||
self.my_rig.open()
|
||||
atexit.register(self.my_rig.close)
|
||||
|
||||
|
||||
# set rig mode to USB
|
||||
self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
||||
|
||||
|
||||
# start thread for getting hamlib data
|
||||
HAMLIB_THREAD = threading.Thread(target=self.get_radio_stats, name="HAMLIB_THREAD")
|
||||
HAMLIB_THREAD = threading.Thread(
|
||||
target=self.get_radio_stats, name="HAMLIB_THREAD")
|
||||
HAMLIB_THREAD.start()
|
||||
|
||||
|
||||
except:
|
||||
print("Unexpected error:", sys.exc_info()[0])
|
||||
print("can't open rig")
|
||||
sys.exit("hamlib error")
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
|
||||
def ptt_and_wait(self, state):
|
||||
static.PTT_STATE = state
|
||||
|
||||
|
||||
if state:
|
||||
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type, 1)
|
||||
#rigctld.ptt_enable()
|
||||
# rigctld.ptt_enable()
|
||||
ptt_toggle_timeout = time.time() + 0.5
|
||||
while time.time() < ptt_toggle_timeout:
|
||||
pass
|
||||
|
||||
|
||||
else:
|
||||
|
||||
|
||||
ptt_toggle_timeout = time.time() + 0.5
|
||||
while time.time() < ptt_toggle_timeout:
|
||||
pass
|
||||
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type, 0)
|
||||
#rigctld.ptt_disable()
|
||||
|
||||
return False
|
||||
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type, 0)
|
||||
# rigctld.ptt_disable()
|
||||
|
||||
return False
|
||||
|
||||
def play_audio(self):
|
||||
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
|
||||
#while len(self.streambuffer) > 0:
|
||||
# while len(self.streambuffer) > 0:
|
||||
# time.sleep(0.01)
|
||||
if len(self.streambuffer) > 0 and self.audio_writing_to_stream:
|
||||
self.streambuffer = bytes(self.streambuffer)
|
||||
|
||||
|
||||
# we need t wait a little bit until the buffer is filled. If we are not waiting, we are sending empty data
|
||||
time.sleep(0.1)
|
||||
self.stream_tx.write(self.streambuffer)
|
||||
# clear stream buffer after sending
|
||||
self.streambuffer = bytes()
|
||||
|
||||
|
||||
self.audio_writing_to_stream = False
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
|
||||
def transmit_signalling(self, data_out, count):
|
||||
state_before_transmit = static.CHANNEL_STATE
|
||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
||||
#print(static.CHANNEL_STATE)
|
||||
|
||||
# print(static.CHANNEL_STATE)
|
||||
|
||||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
freedv = self.c_lib.freedv_open(static.FREEDV_SIGNALLING_MODE)
|
||||
bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
bytes_per_frame = int(
|
||||
self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
payload_per_frame = bytes_per_frame - 2
|
||||
n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(freedv)
|
||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv) # get n_tx_modem_samples which defines the size of the modulation object
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(freedv)
|
||||
|
||||
# get n_tx_modem_samples which defines the size of the modulation object
|
||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv)
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(
|
||||
freedv)
|
||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(
|
||||
freedv)
|
||||
|
||||
mod_out = ctypes.c_short * n_tx_modem_samples
|
||||
mod_out = mod_out()
|
||||
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples # *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
|
||||
# *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples
|
||||
mod_out_preamble = mod_out_preamble()
|
||||
|
||||
mod_out_postamble = ctypes.c_short * n_tx_postamble_modem_samples # *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
# *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_postamble = ctypes.c_short * n_tx_postamble_modem_samples
|
||||
mod_out_postamble = mod_out_postamble()
|
||||
|
||||
buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
|
||||
buffer[:len(data_out)] = data_out # set buffersize to length of data which will be send
|
||||
# use this if CRC16 checksum is required ( DATA1-3)
|
||||
buffer = bytearray(payload_per_frame)
|
||||
# set buffersize to length of data which will be send
|
||||
buffer[:len(data_out)] = data_out
|
||||
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16
|
||||
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(
|
||||
bytes(buffer), payload_per_frame)) # generate CRC16
|
||||
# convert crc to 2 byte hex string
|
||||
crc = crc.value.to_bytes(2, byteorder='big')
|
||||
buffer += crc # append crc16 to buffer
|
||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||
|
||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data) # modulate DATA and safe it into mod_out pointer
|
||||
# modulate DATA and safe it into mod_out pointer
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data)
|
||||
self.c_lib.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
|
||||
self.streambuffer = bytearray()
|
||||
self.streambuffer += bytes(mod_out_preamble)
|
||||
self.streambuffer += bytes(mod_out)
|
||||
self.streambuffer += bytes(mod_out_postamble)
|
||||
|
||||
converted_audio = audioop.ratecv(self.streambuffer,2,1,static.MODEM_SAMPLE_RATE, static.AUDIO_SAMPLE_RATE_TX, None)
|
||||
|
||||
converted_audio = audioop.ratecv(
|
||||
self.streambuffer, 2, 1, static.MODEM_SAMPLE_RATE, static.AUDIO_SAMPLE_RATE_TX, None)
|
||||
self.streambuffer = bytes(converted_audio[0])
|
||||
# append frame again with as much as in count defined
|
||||
for i in range(1, count):
|
||||
self.streambuffer += bytes(converted_audio[0])
|
||||
#print(len(self.streambuffer))
|
||||
# print(len(self.streambuffer))
|
||||
#self.streambuffer += bytes(converted_audio[0])
|
||||
#print(len(self.streambuffer))
|
||||
|
||||
# print(len(self.streambuffer))
|
||||
|
||||
# -------------- transmit audio
|
||||
#logging.debug("SENDING SIGNALLING FRAME " + str(data_out))
|
||||
|
||||
##state_before_transmit = static.CHANNEL_STATE
|
||||
##static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
||||
|
||||
|
||||
while self.ptt_and_wait(True):
|
||||
pass
|
||||
self.audio_writing_to_stream = True
|
||||
|
||||
|
||||
# wait until audio has been processed
|
||||
while self.audio_writing_to_stream:
|
||||
time.sleep(0.01)
|
||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
||||
|
||||
self.ptt_and_wait(False)
|
||||
## we have a problem with the receiving state
|
||||
self.ptt_and_wait(False)
|
||||
# we have a problem with the receiving state
|
||||
##static.CHANNEL_STATE = state_before_transmit
|
||||
if state_before_transmit != 'RECEIVING_DATA':
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
else:
|
||||
static.CHANNEL_STATE = state_before_transmit
|
||||
|
||||
|
||||
self.c_lib.freedv_close(freedv)
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
# GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT
|
||||
|
||||
def transmit_arq_burst(self):
|
||||
|
||||
|
||||
# we could place this timing part inside the modem...
|
||||
# lets see if this is a good idea..
|
||||
static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # we need to update our timeout timestamp
|
||||
static.ARQ_START_OF_BURST = int(time.time()) # we need to update our timeout timestamp
|
||||
|
||||
# we need to update our timeout timestamp
|
||||
static.ARQ_DATA_CHANNEL_LAST_RECEIVED = int(time.time())
|
||||
# we need to update our timeout timestamp
|
||||
static.ARQ_START_OF_BURST = int(time.time())
|
||||
|
||||
state_before_transmit = static.CHANNEL_STATE
|
||||
static.CHANNEL_STATE = 'SENDING_DATA'
|
||||
|
||||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
freedv = self.c_lib.freedv_open(static.ARQ_DATA_CHANNEL_MODE)
|
||||
|
||||
static.FREEDV_DATA_BYTES_PER_FRAME = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
static.FREEDV_DATA_BYTES_PER_FRAME = int(
|
||||
self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
static.FREEDV_DATA_PAYLOAD_PER_FRAME = static.FREEDV_DATA_BYTES_PER_FRAME - 2
|
||||
|
||||
n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(freedv)
|
||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv) # *2 #get n_tx_modem_samples which defines the size of the modulation object
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(freedv)
|
||||
|
||||
# *2 #get n_tx_modem_samples which defines the size of the modulation object
|
||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv)
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(
|
||||
freedv)
|
||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(
|
||||
freedv)
|
||||
|
||||
mod_out = ctypes.c_short * n_tx_modem_samples
|
||||
mod_out = mod_out()
|
||||
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples # *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
|
||||
# *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples
|
||||
mod_out_preamble = mod_out_preamble()
|
||||
|
||||
mod_out_postamble = ctypes.c_short * n_tx_postamble_modem_samples # *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
# *2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_postamble = ctypes.c_short * n_tx_postamble_modem_samples
|
||||
mod_out_postamble = mod_out_postamble()
|
||||
|
||||
|
||||
self.streambuffer = bytearray()
|
||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
self.streambuffer += bytes(mod_out_preamble)
|
||||
|
||||
|
||||
if not static.ARQ_RPT_RECEIVED:
|
||||
|
||||
|
||||
for n in range(0, static.ARQ_TX_N_FRAMES_PER_BURST):
|
||||
# ---------------------------BUILD ARQ BURST ---------------------------------------------------------------------
|
||||
frame_type = 10 + n + 1 # static.ARQ_TX_N_FRAMES_PER_BURST
|
||||
frame_type = bytes([frame_type])
|
||||
|
||||
payload_data = bytes(static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + n])
|
||||
payload_data = bytes(
|
||||
static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + n])
|
||||
|
||||
n_current_arq_frame = static.ARQ_N_SENT_FRAMES + n + 1
|
||||
static.ARQ_TX_N_CURRENT_ARQ_FRAME = n_current_arq_frame.to_bytes(2, byteorder='big')
|
||||
static.ARQ_TX_N_CURRENT_ARQ_FRAME = n_current_arq_frame.to_bytes(
|
||||
2, byteorder='big')
|
||||
|
||||
n_total_arq_frame = len(static.TX_BUFFER)
|
||||
#static.ARQ_TX_N_TOTAL_ARQ_FRAMES = n_total_arq_frame
|
||||
|
@ -355,18 +378,23 @@ class RF():
|
|||
static.MYCALLSIGN_CRC8 + \
|
||||
payload_data
|
||||
|
||||
buffer = bytearray(static.FREEDV_DATA_PAYLOAD_PER_FRAME) # create TX buffer
|
||||
buffer[:len(arqframe)] = arqframe # set buffersize to length of data which will be send
|
||||
# create TX buffer
|
||||
buffer = bytearray(static.FREEDV_DATA_PAYLOAD_PER_FRAME)
|
||||
# set buffersize to length of data which will be send
|
||||
buffer[:len(arqframe)] = arqframe
|
||||
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), static.FREEDV_DATA_PAYLOAD_PER_FRAME)) # generate CRC16
|
||||
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(
|
||||
bytes(buffer), static.FREEDV_DATA_PAYLOAD_PER_FRAME)) # generate CRC16
|
||||
# convert crc to 2 byte hex string
|
||||
crc = crc.value.to_bytes(2, byteorder='big')
|
||||
buffer += crc # append crc16 to buffer
|
||||
|
||||
data = (ctypes.c_ubyte * static.FREEDV_DATA_BYTES_PER_FRAME).from_buffer_copy(buffer)
|
||||
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data) # modulate DATA and safe it into mod_out pointer
|
||||
data = (
|
||||
ctypes.c_ubyte * static.FREEDV_DATA_BYTES_PER_FRAME).from_buffer_copy(buffer)
|
||||
|
||||
# modulate DATA and safe it into mod_out pointer
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data)
|
||||
self.streambuffer += bytes(mod_out)
|
||||
|
||||
|
||||
elif static.ARQ_RPT_RECEIVED:
|
||||
|
||||
|
@ -378,12 +406,14 @@ class RF():
|
|||
frame_type = bytes([frame_type])
|
||||
|
||||
try:
|
||||
payload_data = bytes(static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + missing_frame - 1])
|
||||
payload_data = bytes(
|
||||
static.TX_BUFFER[static.ARQ_N_SENT_FRAMES + missing_frame - 1])
|
||||
except:
|
||||
print("modem buffer selection problem with ARQ RPT frames")
|
||||
|
||||
|
||||
n_current_arq_frame = static.ARQ_N_SENT_FRAMES + missing_frame
|
||||
static.ARQ_TX_N_CURRENT_ARQ_FRAME = n_current_arq_frame.to_bytes(2, byteorder='big')
|
||||
static.ARQ_TX_N_CURRENT_ARQ_FRAME = n_current_arq_frame.to_bytes(
|
||||
2, byteorder='big')
|
||||
|
||||
n_total_arq_frame = len(static.TX_BUFFER)
|
||||
#static.ARQ_TX_N_TOTAL_ARQ_FRAMES = n_total_arq_frame
|
||||
|
@ -396,28 +426,33 @@ class RF():
|
|||
static.MYCALLSIGN_CRC8 + \
|
||||
payload_data
|
||||
|
||||
buffer = bytearray(static.FREEDV_DATA_PAYLOAD_PER_FRAME) # create TX buffer
|
||||
buffer[:len(arqframe)] = arqframe # set buffersize to length of data which will be send
|
||||
# create TX buffer
|
||||
buffer = bytearray(static.FREEDV_DATA_PAYLOAD_PER_FRAME)
|
||||
# set buffersize to length of data which will be send
|
||||
buffer[:len(arqframe)] = arqframe
|
||||
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), static.FREEDV_DATA_PAYLOAD_PER_FRAME)) # generate CRC16
|
||||
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
|
||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(
|
||||
bytes(buffer), static.FREEDV_DATA_PAYLOAD_PER_FRAME)) # generate CRC16
|
||||
# convert crc to 2 byte hex string
|
||||
crc = crc.value.to_bytes(2, byteorder='big')
|
||||
buffer += crc # append crc16 to buffer
|
||||
|
||||
data = (ctypes.c_ubyte * static.FREEDV_DATA_BYTES_PER_FRAME).from_buffer_copy(buffer)
|
||||
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data) # modulate DATA and safe it into mod_out pointer
|
||||
data = (
|
||||
ctypes.c_ubyte * static.FREEDV_DATA_BYTES_PER_FRAME).from_buffer_copy(buffer)
|
||||
|
||||
# modulate DATA and safe it into mod_out pointer
|
||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data)
|
||||
self.streambuffer += bytes(mod_out)
|
||||
|
||||
|
||||
self.c_lib.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
self.streambuffer += bytes(mod_out_postamble)
|
||||
|
||||
converted_audio = audioop.ratecv(self.streambuffer,2,1,static.MODEM_SAMPLE_RATE, static.AUDIO_SAMPLE_RATE_TX, None)
|
||||
|
||||
converted_audio = audioop.ratecv(
|
||||
self.streambuffer, 2, 1, static.MODEM_SAMPLE_RATE, static.AUDIO_SAMPLE_RATE_TX, None)
|
||||
self.streambuffer = bytes(converted_audio[0])
|
||||
|
||||
|
||||
# -------------- transmit audio
|
||||
|
||||
|
||||
while self.ptt_and_wait(True):
|
||||
pass
|
||||
# this triggers writing buffer to audio stream
|
||||
|
@ -439,22 +474,23 @@ class RF():
|
|||
# --------------------------------------------------------------------------------------------------------
|
||||
|
||||
def receive(self):
|
||||
|
||||
|
||||
# DATAC0
|
||||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
datac0_freedv = self.c_lib.freedv_open(14)
|
||||
self.c_lib.freedv_get_bits_per_modem_frame(datac0_freedv)
|
||||
datac0_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac0_freedv)/8)
|
||||
datac0_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac0_freedv)
|
||||
|
||||
datac0_bytes_out = (ctypes.c_ubyte * datac0_bytes_per_frame) #bytes_per_frame
|
||||
datac0_bytes_out = datac0_bytes_out() #get pointer from bytes_out
|
||||
|
||||
self.c_lib.freedv_set_frames_per_burst(datac0_freedv,1)
|
||||
datac0_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac0_freedv)
|
||||
|
||||
# bytes_per_frame
|
||||
datac0_bytes_out = (ctypes.c_ubyte * datac0_bytes_per_frame)
|
||||
datac0_bytes_out = datac0_bytes_out() # get pointer from bytes_out
|
||||
|
||||
self.c_lib.freedv_set_frames_per_burst(datac0_freedv, 1)
|
||||
datac0_modem_stats_snr = c_float()
|
||||
datac0_modem_stats_sync = c_int()
|
||||
datac0_buffer = bytes()
|
||||
|
||||
|
||||
static.FREEDV_SIGNALLING_BYTES_PER_FRAME = datac0_bytes_per_frame
|
||||
static.FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = datac0_bytes_per_frame - 2
|
||||
|
||||
|
@ -462,10 +498,11 @@ class RF():
|
|||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
datac1_freedv = self.c_lib.freedv_open(10)
|
||||
datac1_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac1_freedv)/8)
|
||||
datac1_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac1_freedv)
|
||||
datac1_bytes_out = (ctypes.c_ubyte * datac1_bytes_per_frame) #bytes_per_frame
|
||||
datac1_bytes_out = datac1_bytes_out() #get pointer from bytes_out
|
||||
self.c_lib.freedv_set_frames_per_burst(datac1_freedv,1)
|
||||
datac1_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac1_freedv)
|
||||
# bytes_per_frame
|
||||
datac1_bytes_out = (ctypes.c_ubyte * datac1_bytes_per_frame)
|
||||
datac1_bytes_out = datac1_bytes_out() # get pointer from bytes_out
|
||||
self.c_lib.freedv_set_frames_per_burst(datac1_freedv, 1)
|
||||
datac1_modem_stats_snr = c_float()
|
||||
datac1_modem_stats_sync = c_int()
|
||||
datac1_buffer = bytes()
|
||||
|
@ -474,10 +511,11 @@ class RF():
|
|||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
datac3_freedv = self.c_lib.freedv_open(12)
|
||||
datac3_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac3_freedv)/8)
|
||||
datac3_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac3_freedv)
|
||||
datac3_bytes_out = (ctypes.c_ubyte * datac3_bytes_per_frame) #bytes_per_frame
|
||||
datac3_bytes_out = datac3_bytes_out() #get pointer from bytes_out
|
||||
self.c_lib.freedv_set_frames_per_burst(datac3_freedv,1)
|
||||
datac3_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac3_freedv)
|
||||
# bytes_per_frame
|
||||
datac3_bytes_out = (ctypes.c_ubyte * datac3_bytes_per_frame)
|
||||
datac3_bytes_out = datac3_bytes_out() # get pointer from bytes_out
|
||||
self.c_lib.freedv_set_frames_per_burst(datac3_freedv, 1)
|
||||
datac3_modem_stats_snr = c_float()
|
||||
datac3_modem_stats_sync = c_int()
|
||||
datac3_buffer = bytes()
|
||||
|
@ -503,242 +541,240 @@ class RF():
|
|||
'''
|
||||
|
||||
data_in = bytes()
|
||||
data_in = self.stream_rx.read(1024, exception_on_overflow = False)
|
||||
data_in = self.stream_rx.read(1024, exception_on_overflow=False)
|
||||
#self.fft_data = data_in
|
||||
data_in = audioop.ratecv(data_in,2,1,static.AUDIO_SAMPLE_RATE_RX, static.MODEM_SAMPLE_RATE, None)
|
||||
data_in = data_in[0]#.rstrip(b'\x00')
|
||||
data_in = audioop.ratecv(data_in, 2, 1, static.AUDIO_SAMPLE_RATE_RX, static.MODEM_SAMPLE_RATE, None)
|
||||
data_in = data_in[0] # .rstrip(b'\x00')
|
||||
self.fft_data = data_in
|
||||
|
||||
|
||||
# we need to set nin * 2 beause of byte size in array handling
|
||||
datac0_nin = self.c_lib.freedv_nin(datac0_freedv) * 2
|
||||
datac1_nin = self.c_lib.freedv_nin(datac1_freedv) * 2
|
||||
datac3_nin = self.c_lib.freedv_nin(datac3_freedv) * 2
|
||||
|
||||
|
||||
# refill buffer only if every mode has worked with its data
|
||||
if (len(datac0_buffer) < (datac0_nin*2)) and (len(datac1_buffer) < (datac1_nin*2)) and (len(datac3_buffer) < (datac3_nin*2)):
|
||||
datac0_buffer += data_in
|
||||
datac1_buffer += data_in
|
||||
datac3_buffer += data_in
|
||||
|
||||
|
||||
|
||||
# DECODING DATAC0
|
||||
|
||||
# DECODING DATAC0
|
||||
if len(datac0_buffer) >= (datac0_nin):
|
||||
|
||||
|
||||
datac0_audio = datac0_buffer[:datac0_nin]
|
||||
datac0_buffer = datac0_buffer[datac0_nin:]
|
||||
#print(len(datac0_audio))
|
||||
datac0_buffer = datac0_buffer[datac0_nin:]
|
||||
# print(len(datac0_audio))
|
||||
self.c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), datac0_bytes_out, datac0_audio]
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_audio) # demodulate audio
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_audio) # demodulate audio
|
||||
sync = self.c_lib.freedv_get_rx_status(datac0_freedv)
|
||||
if sync != 0 and nbytes != 0:
|
||||
|
||||
#calculate snr and scatter
|
||||
if sync != 0 and nbytes != 0:
|
||||
|
||||
# calculate snr and scatter
|
||||
self.get_scatter(datac0_freedv)
|
||||
self.calculate_snr(datac0_freedv)
|
||||
|
||||
datac0_task = threading.Thread(target=self.process_data, args=[datac0_bytes_out, datac0_freedv])
|
||||
datac0_task.start()
|
||||
|
||||
|
||||
|
||||
# DECODING DATAC1
|
||||
# DECODING DATAC1
|
||||
if len(datac1_buffer) >= (datac1_nin):
|
||||
datac1_audio = datac1_buffer[:datac1_nin]
|
||||
datac1_buffer = datac1_buffer[datac1_nin:]
|
||||
#print(len(datac1_audio))
|
||||
datac1_buffer = datac1_buffer[datac1_nin:]
|
||||
# print(len(datac1_audio))
|
||||
self.c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), datac1_bytes_out, datac1_audio]
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_audio) # demodulate audio
|
||||
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_audio) # demodulate audio
|
||||
|
||||
sync = self.c_lib.freedv_get_rx_status(datac1_freedv)
|
||||
if sync != 0 and nbytes != 0:
|
||||
|
||||
#calculate snr and scatter
|
||||
|
||||
# calculate snr and scatter
|
||||
self.get_scatter(datac1_freedv)
|
||||
self.calculate_snr(datac1_freedv)
|
||||
|
||||
datac1_task = threading.Thread(target=self.process_data, args=[datac1_bytes_out, datac1_freedv])
|
||||
datac1_task.start()
|
||||
|
||||
# DECODING DATAC3
|
||||
datac1_task.start()
|
||||
|
||||
# DECODING DATAC3
|
||||
if len(datac3_buffer) >= (datac3_nin):
|
||||
datac3_audio = datac3_buffer[:datac3_nin]
|
||||
datac3_buffer = datac3_buffer[datac3_nin:]
|
||||
datac3_buffer = datac3_buffer[datac3_nin:]
|
||||
self.c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), datac3_bytes_out, datac3_audio]
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_audio) # demodulate audio
|
||||
|
||||
nbytes = self.c_lib.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_audio) # demodulate audio
|
||||
|
||||
sync = self.c_lib.freedv_get_rx_status(datac3_freedv)
|
||||
if sync != 0 and nbytes != 0:
|
||||
|
||||
#calculate snr and scatter
|
||||
|
||||
# calculate snr and scatter
|
||||
self.get_scatter(datac3_freedv)
|
||||
self.calculate_snr(datac3_freedv)
|
||||
|
||||
datac3_task = threading.Thread(target=self.process_data, args=[datac3_bytes_out, datac3_freedv])
|
||||
datac3_task.start()
|
||||
|
||||
|
||||
|
||||
# forward data only if broadcast or we are the receiver
|
||||
# bytes_out[1:2] == callsign check for signalling frames, bytes_out[6:7] == callsign check for data frames, bytes_out[1:2] == b'\x01' --> broadcasts like CQ
|
||||
# we could also create an own function, which returns True. In this case we could add callsign blacklists and so on
|
||||
|
||||
|
||||
def process_data(self, bytes_out, freedv):
|
||||
force = True
|
||||
print(bytes(bytes_out))
|
||||
if bytes(bytes_out[1:2]) == static.MYCALLSIGN_CRC8 or bytes(bytes_out[6:7]) == static.MYCALLSIGN_CRC8 or bytes(bytes_out[1:2]) == b'\x01':
|
||||
|
||||
helpers.calculate_transfer_rate()
|
||||
# CHECK IF FRAMETYPE IS BETWEEN 10 and 50 ------------------------
|
||||
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
||||
frame = frametype - 10
|
||||
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
||||
|
||||
#self.c_lib.freedv_set_frames_per_burst(freedv_data, n_frames_per_burst);
|
||||
helpers.calculate_transfer_rate()
|
||||
# CHECK IF FRAMETYPE IS BETWEEN 10 and 50 ------------------------
|
||||
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
||||
frame = frametype - 10
|
||||
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
||||
|
||||
if 50 >= frametype >= 10:
|
||||
if frame != 3 or force == True:
|
||||
#self.c_lib.freedv_set_frames_per_burst(freedv_data, n_frames_per_burst);
|
||||
|
||||
data_handler.arq_data_received(bytes(bytes_out[:-2])) # send payload data to arq checker without CRC16
|
||||
if 50 >= frametype >= 10:
|
||||
if frame != 3 or force == True:
|
||||
|
||||
#print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None)))
|
||||
if static.ARQ_RX_BURST_BUFFER.count(None) <= 1:
|
||||
logging.debug("FULL BURST BUFFER ---> UNSYNC")
|
||||
self.c_lib.freedv_set_sync(freedv, 0)
|
||||
# send payload data to arq checker without CRC16
|
||||
data_handler.arq_data_received(bytes(bytes_out[:-2]))
|
||||
|
||||
else:
|
||||
logging.critical("---------------------------SIMULATED MISSING FRAME")
|
||||
force = True
|
||||
#print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None)))
|
||||
if static.ARQ_RX_BURST_BUFFER.count(None) <= 1:
|
||||
logging.debug("FULL BURST BUFFER ---> UNSYNC")
|
||||
self.c_lib.freedv_set_sync(freedv, 0)
|
||||
|
||||
# BURST ACK
|
||||
elif frametype == 60:
|
||||
logging.debug("ACK RECEIVED....")
|
||||
data_handler.burst_ack_received()
|
||||
else:
|
||||
logging.critical(
|
||||
"---------------------------SIMULATED MISSING FRAME")
|
||||
force = True
|
||||
|
||||
# FRAME ACK
|
||||
elif frametype == 61:
|
||||
logging.debug("FRAME ACK RECEIVED....")
|
||||
data_handler.frame_ack_received()
|
||||
# BURST ACK
|
||||
elif frametype == 60:
|
||||
logging.debug("ACK RECEIVED....")
|
||||
data_handler.burst_ack_received()
|
||||
|
||||
# FRAME RPT
|
||||
elif frametype == 62:
|
||||
logging.debug("REPEAT REQUEST RECEIVED....")
|
||||
data_handler.burst_rpt_received(bytes_out[:-2])
|
||||
# FRAME ACK
|
||||
elif frametype == 61:
|
||||
logging.debug("FRAME ACK RECEIVED....")
|
||||
data_handler.frame_ack_received()
|
||||
|
||||
# FRAME NAK
|
||||
elif frametype == 63:
|
||||
logging.debug("FRAME NAK RECEIVED....")
|
||||
data_handler.frame_nack_received(bytes_out[:-2])
|
||||
|
||||
# CQ FRAME
|
||||
elif frametype == 200:
|
||||
logging.debug("CQ RECEIVED....")
|
||||
data_handler.received_cq(bytes_out[:-2])
|
||||
# FRAME RPT
|
||||
elif frametype == 62:
|
||||
logging.debug("REPEAT REQUEST RECEIVED....")
|
||||
data_handler.burst_rpt_received(bytes_out[:-2])
|
||||
|
||||
# PING FRAME
|
||||
elif frametype == 210:
|
||||
logging.debug("PING RECEIVED....")
|
||||
data_handler.received_ping(bytes_out[:-2])
|
||||
# FRAME NAK
|
||||
elif frametype == 63:
|
||||
logging.debug("FRAME NAK RECEIVED....")
|
||||
data_handler.frame_nack_received(bytes_out[:-2])
|
||||
|
||||
# PING ACK
|
||||
elif frametype == 211:
|
||||
logging.debug("PING ACK RECEIVED....")
|
||||
data_handler.received_ping_ack(bytes_out[:-2])
|
||||
# CQ FRAME
|
||||
elif frametype == 200:
|
||||
logging.debug("CQ RECEIVED....")
|
||||
data_handler.received_cq(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT
|
||||
elif frametype == 220:
|
||||
logging.info("ARQ CONNECT RECEIVED....")
|
||||
data_handler.arq_received_connect(bytes_out[:-2])
|
||||
# PING FRAME
|
||||
elif frametype == 210:
|
||||
logging.debug("PING RECEIVED....")
|
||||
data_handler.received_ping(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 221:
|
||||
logging.info("ARQ CONNECT ACK RECEIVED / KEEP ALIVE....")
|
||||
data_handler.arq_received_connect_keep_alive(bytes_out[:-2])
|
||||
# PING ACK
|
||||
elif frametype == 211:
|
||||
logging.debug("PING ACK RECEIVED....")
|
||||
data_handler.received_ping_ack(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 222:
|
||||
logging.debug("ARQ DISCONNECT RECEIVED")
|
||||
data_handler.arq_disconnect_received(bytes_out[:-2])
|
||||
# ARQ CONNECT
|
||||
# elif frametype == 220:
|
||||
# logging.info("ARQ CONNECT RECEIVED....")
|
||||
# data_handler.arq_received_connect(bytes_out[:-2])
|
||||
|
||||
# ARQ FILE TRANSFER RECEIVED!
|
||||
elif frametype == 225:
|
||||
logging.debug("ARQ arq_received_data_channel_opener RECEIVED")
|
||||
data_handler.arq_received_data_channel_opener(bytes_out[:-2])
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
# elif frametype == 221:
|
||||
# logging.info("ARQ CONNECT ACK RECEIVED / KEEP ALIVE....")
|
||||
# data_handler.arq_received_connect_keep_alive(bytes_out[:-2])
|
||||
|
||||
# ARQ CHANNEL IS OPENED
|
||||
elif frametype == 226:
|
||||
logging.debug("ARQ arq_received_channel_is_open RECEIVED")
|
||||
data_handler.arq_received_channel_is_open(bytes_out[:-2])
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
# elif frametype == 222:
|
||||
# logging.debug("ARQ DISCONNECT RECEIVED")
|
||||
# data_handler.arq_disconnect_received(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 230:
|
||||
logging.debug("BEACON RECEIVED")
|
||||
data_handler.received_beacon(bytes_out[:-2])
|
||||
# ARQ FILE TRANSFER RECEIVED!
|
||||
elif frametype == 225:
|
||||
logging.debug("ARQ arq_received_data_channel_opener RECEIVED")
|
||||
data_handler.arq_received_data_channel_opener(bytes_out[:-2])
|
||||
|
||||
else:
|
||||
logging.info("OTHER FRAME: " + str(bytes_out[:-2]))
|
||||
print(frametype)
|
||||
# ARQ CHANNEL IS OPENED
|
||||
elif frametype == 226:
|
||||
logging.debug("ARQ arq_received_channel_is_open RECEIVED")
|
||||
data_handler.arq_received_channel_is_open(bytes_out[:-2])
|
||||
|
||||
# DO UNSYNC AFTER LAST BURST by checking the frame nums against the total frames per burst
|
||||
if frame == n_frames_per_burst:
|
||||
|
||||
logging.debug("LAST FRAME ---> UNSYNC")
|
||||
|
||||
self.c_lib.freedv_set_sync(freedv, 0) # FORCE UNSYNC
|
||||
|
||||
# clear bytes_out buffer to be ready for next frames after successfull decoding
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 230:
|
||||
logging.debug("BEACON RECEIVED")
|
||||
data_handler.received_beacon(bytes_out[:-2])
|
||||
|
||||
#bytes_out = (ctypes.c_ubyte * bytes_per_frame)
|
||||
#bytes_out = bytes_out() # get pointer to bytes_out
|
||||
else:
|
||||
logging.info("OTHER FRAME: " + str(bytes_out[:-2]))
|
||||
print(frametype)
|
||||
|
||||
# DO UNSYNC AFTER LAST BURST by checking the frame nums against the total frames per burst
|
||||
if frame == n_frames_per_burst:
|
||||
|
||||
logging.debug("LAST FRAME ---> UNSYNC")
|
||||
|
||||
self.c_lib.freedv_set_sync(freedv, 0) # FORCE UNSYNC
|
||||
|
||||
# clear bytes_out buffer to be ready for next frames after successfull decoding
|
||||
|
||||
#bytes_out = (ctypes.c_ubyte * bytes_per_frame)
|
||||
# bytes_out = bytes_out() # get pointer to bytes_out
|
||||
|
||||
else:
|
||||
# for debugging purposes to receive all data
|
||||
# for debugging purposes to receive all data
|
||||
pass
|
||||
# print(bytes_out[:-2])
|
||||
|
||||
|
||||
# print(bytes_out[:-2])
|
||||
|
||||
def get_scatter(self, freedv):
|
||||
modemStats = MODEMSTATS()
|
||||
self.c_lib.freedv_get_modem_extended_stats.restype = None
|
||||
self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats))
|
||||
|
||||
self.c_lib.freedv_get_modem_extended_stats(
|
||||
freedv, ctypes.byref(modemStats))
|
||||
|
||||
scatterdata = []
|
||||
for i in range(MODEM_STATS_NC_MAX):
|
||||
for j in range(MODEM_STATS_NR_MAX):
|
||||
#check if odd or not to get every 2nd item for x
|
||||
if (j % 2) == 0:
|
||||
for j in range(MODEM_STATS_NR_MAX):
|
||||
# check if odd or not to get every 2nd item for x
|
||||
if (j % 2) == 0:
|
||||
xsymbols = modemStats.rx_symbols[i][j]
|
||||
ysymbols = modemStats.rx_symbols[i][j+1]
|
||||
ysymbols = modemStats.rx_symbols[i][j+1]
|
||||
# check if value 0.0 or has real data
|
||||
if xsymbols != 0.0 and ysymbols != 0.0:
|
||||
scatterdata.append({"x" : xsymbols, "y" : ysymbols })
|
||||
|
||||
scatterdata.append({"x": xsymbols, "y": ysymbols})
|
||||
|
||||
# only append scatter data if new data arrived
|
||||
if len(scatterdata) > 0:
|
||||
static.SCATTER = scatterdata
|
||||
|
||||
static.SCATTER = scatterdata
|
||||
|
||||
def calculate_ber(self, freedv):
|
||||
Tbits = self.c_lib.freedv_get_total_bits(freedv)
|
||||
Terrs = self.c_lib.freedv_get_total_bit_errors(freedv)
|
||||
|
||||
|
||||
if Tbits != 0:
|
||||
ber = (Terrs / Tbits) * 100
|
||||
static.BER = int(ber)
|
||||
|
||||
self.c_lib.freedv_set_total_bit_errors(freedv, 0)
|
||||
self.c_lib.freedv_set_total_bits(freedv, 0)
|
||||
|
||||
|
||||
def calculate_snr(self, freedv):
|
||||
|
||||
|
||||
modem_stats_snr = c_float()
|
||||
modem_stats_sync = c_int()
|
||||
|
||||
self.c_lib.freedv_get_modem_stats(freedv,byref(modem_stats_sync), byref(modem_stats_snr))
|
||||
|
||||
self.c_lib.freedv_get_modem_stats(freedv, byref(
|
||||
modem_stats_sync), byref(modem_stats_snr))
|
||||
modem_stats_snr = modem_stats_snr.value
|
||||
try:
|
||||
static.SNR = round(modem_stats_snr,1)
|
||||
static.SNR = round(modem_stats_snr, 1)
|
||||
except:
|
||||
static.SNR = 0
|
||||
|
||||
|
||||
def get_radio_stats(self):
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
|
@ -748,14 +784,13 @@ class RF():
|
|||
#static.HAMLIB_FREQUENCY = rigctld.get_frequency()
|
||||
#static.HAMLIB_MODE = rigctld.get_mode()[0]
|
||||
#static.HAMLIB_BANDWITH = rigctld.get_mode()[1]
|
||||
|
||||
|
||||
|
||||
def calculate_fft(self):
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
# WE NEED TO OPTIMIZE THIS!
|
||||
data_in = self.fft_data
|
||||
|
||||
|
||||
# https://gist.github.com/ZWMiller/53232427efc5088007cab6feee7c6e4c
|
||||
audio_data = np.fromstring(data_in, np.int16)
|
||||
# Fast Fourier Transform, 10*log10(abs) is to scale it to dB
|
||||
|
@ -763,11 +798,11 @@ class RF():
|
|||
|
||||
try:
|
||||
fftarray = np.fft.rfft(audio_data)
|
||||
# set value 0 to 1 to avoid division by zero
|
||||
# set value 0 to 1 to avoid division by zero
|
||||
fftarray[fftarray == 0] = 1
|
||||
dfft = 10.*np.log10(abs(fftarray))
|
||||
dfftlist = dfft.tolist()
|
||||
|
||||
|
||||
# send fft only if receiving
|
||||
if static.CHANNEL_STATE == 'RECEIVING_SIGNALLING' or static.CHANNEL_STATE == 'RECEIVING_DATA':
|
||||
#static.FFT = dfftlist[20:100]
|
||||
|
@ -776,4 +811,3 @@ class RF():
|
|||
print("setting fft = 0")
|
||||
# else 0
|
||||
static.FFT = [0] * 400
|
||||
|
||||
|
|
140
tnc/sock.py
140
tnc/sock.py
|
@ -33,17 +33,19 @@ import static
|
|||
import data_handler
|
||||
import helpers
|
||||
|
||||
import sys, os
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
print("Client connected...")
|
||||
|
||||
print("Client connected...")
|
||||
|
||||
# loop through socket buffer until timeout is reached. then close buffer
|
||||
socketTimeout = time.time() + 3
|
||||
while socketTimeout > time.time():
|
||||
|
@ -53,21 +55,21 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
#data = str(self.request.recv(1024), 'utf-8')
|
||||
|
||||
data = bytes()
|
||||
|
||||
|
||||
# we need to loop through buffer until end of chunk is reached or timeout occured
|
||||
while True and socketTimeout > time.time():
|
||||
|
||||
chunk = self.request.recv(71) # we keep amount of bytes short
|
||||
data += chunk
|
||||
if chunk.endswith(b'}\n') or chunk.endswith(b'}'): # or chunk.endswith(b'\n'):
|
||||
# or chunk.endswith(b'\n'):
|
||||
if chunk.endswith(b'}\n') or chunk.endswith(b'}'):
|
||||
break
|
||||
data = data[:-1] # remove b'\n'
|
||||
data = str(data, 'utf-8')
|
||||
|
||||
|
||||
if len(data) > 0:
|
||||
socketTimeout = time.time() + static.SOCKET_TIMEOUT
|
||||
|
||||
|
||||
# convert data to json object
|
||||
# we need to do some error handling in case of socket timeout or decoding issue
|
||||
try:
|
||||
|
@ -78,7 +80,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
data = data.splitlines()[0]
|
||||
received_json = json.loads(data)
|
||||
|
||||
#except ValueError as e:
|
||||
# except ValueError as e:
|
||||
# print("++++++++++++ START OF JSON ERROR +++++++++++++++++++++++")
|
||||
# print(e)
|
||||
# print("-----------------------------------")
|
||||
|
@ -86,29 +88,32 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
# print("++++++++++++ END OF JSON ERROR +++++++++++++++++++++++++")
|
||||
# received_json = {}
|
||||
# break
|
||||
#try:
|
||||
# try:
|
||||
|
||||
# CQ CQ CQ -----------------------------------------------------
|
||||
if received_json["command"] == "CQCQCQ":
|
||||
#socketTimeout = 0
|
||||
#asyncio.run(data_handler.transmit_cq())
|
||||
CQ_THREAD = threading.Thread(target=data_handler.transmit_cq, args=[], name="CQ")
|
||||
# asyncio.run(data_handler.transmit_cq())
|
||||
CQ_THREAD = threading.Thread(
|
||||
target=data_handler.transmit_cq, args=[], name="CQ")
|
||||
CQ_THREAD.start()
|
||||
|
||||
# PING ----------------------------------------------------------
|
||||
if received_json["type"] == 'PING' and received_json["command"] == "PING":
|
||||
# send ping frame and wait for ACK
|
||||
dxcallsign = received_json["dxcallsign"]
|
||||
#asyncio.run(data_handler.transmit_ping(dxcallsign))
|
||||
PING_THREAD = threading.Thread(target=data_handler.transmit_ping, args=[dxcallsign], name="CQ")
|
||||
# asyncio.run(data_handler.transmit_ping(dxcallsign))
|
||||
PING_THREAD = threading.Thread(
|
||||
target=data_handler.transmit_ping, args=[dxcallsign], name="CQ")
|
||||
PING_THREAD.start()
|
||||
|
||||
if received_json["type"] == 'ARQ' and received_json["command"] == "sendFile":# and static.ARQ_READY_FOR_DATA == True: # and static.ARQ_STATE == 'CONNECTED' :
|
||||
# and static.ARQ_READY_FOR_DATA == True: # and static.ARQ_STATE == 'CONNECTED' :
|
||||
if received_json["type"] == 'ARQ' and received_json["command"] == "sendFile":
|
||||
static.TNC_STATE = 'BUSY'
|
||||
|
||||
#on a new transmission we reset the timer
|
||||
|
||||
# on a new transmission we reset the timer
|
||||
static.ARQ_START_OF_TRANSMISSION = int(time.time())
|
||||
|
||||
|
||||
dxcallsign = received_json["dxcallsign"]
|
||||
mode = int(received_json["mode"])
|
||||
n_frames = int(received_json["n_frames"])
|
||||
|
@ -116,12 +121,13 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
filetype = received_json["filetype"]
|
||||
data = received_json["data"]
|
||||
checksum = received_json["checksum"]
|
||||
|
||||
|
||||
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
|
||||
|
||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
|
||||
static.DXCALLSIGN)
|
||||
|
||||
#dataframe = '{"filename": "'+ filename + '", "filetype" : "' + filetype + '", "data" : "' + data + '", "checksum" : "' + checksum + '"}'
|
||||
rawdata = {"filename" : filename , "filetype" :filetype, "data" : data, "checksum" : checksum}
|
||||
rawdata = {"filename": filename, "filetype": filetype,"data": data, "checksum": checksum}
|
||||
#dataframe = {filename: filename}
|
||||
#data_out = bytes(received_json["data"], 'utf-8')
|
||||
dataframe = json.dumps(rawdata)
|
||||
|
@ -141,9 +147,11 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
self.request.sendall(b'INVALID CALLSIGN')
|
||||
else:
|
||||
static.MYCALLSIGN = bytes(callsign, encoding)
|
||||
static.MYCALLSIGN_CRC8 = helpers.get_crc_8(static.MYCALLSIGN)
|
||||
logging.info("CMD | MYCALLSIGN: " + str(static.MYCALLSIGN))
|
||||
|
||||
static.MYCALLSIGN_CRC8 = helpers.get_crc_8(
|
||||
static.MYCALLSIGN)
|
||||
logging.info("CMD | MYCALLSIGN: " +
|
||||
str(static.MYCALLSIGN))
|
||||
|
||||
if received_json["type"] == 'SET' and received_json["command"] == 'MYGRID':
|
||||
mygrid = received_json["parameter"]
|
||||
|
||||
|
@ -152,25 +160,24 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
else:
|
||||
static.MYGRID = bytes(mygrid, encoding)
|
||||
logging.info("CMD | MYGRID: " + str(static.MYGRID))
|
||||
|
||||
|
||||
|
||||
if received_json["type"] == 'GET' and received_json["command"] == 'STATION_INFO':
|
||||
output = {
|
||||
"COMMAND": "STATION_INFO",
|
||||
"TIMESTAMP" : received_json["timestamp"],
|
||||
"TIMESTAMP": received_json["timestamp"],
|
||||
"MY_CALLSIGN": str(static.MYCALLSIGN, encoding),
|
||||
"DX_CALLSIGN": str(static.DXCALLSIGN, encoding),
|
||||
"DX_GRID": str(static.DXGRID, encoding),
|
||||
"EOF" : "EOF",
|
||||
"EOF": "EOF",
|
||||
}
|
||||
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
self.request.sendall(bytes(jsondata, encoding))
|
||||
|
||||
if received_json["type"] == 'GET' and received_json["command"] == 'TNC_STATE':
|
||||
output = {
|
||||
"COMMAND": "TNC_STATE",
|
||||
"TIMESTAMP" : received_json["timestamp"],
|
||||
"TIMESTAMP": received_json["timestamp"],
|
||||
"PTT_STATE": str(static.PTT_STATE),
|
||||
"CHANNEL_STATE": str(static.CHANNEL_STATE),
|
||||
"TNC_STATE": str(static.TNC_STATE),
|
||||
|
@ -178,65 +185,63 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
"AUDIO_RMS": str(static.AUDIO_RMS),
|
||||
"BER": str(static.BER),
|
||||
"SNR": str(static.SNR),
|
||||
"FREQUENCY" : str(static.HAMLIB_FREQUENCY),
|
||||
"MODE" : str(static.HAMLIB_MODE),
|
||||
"BANDWITH" : str(static.HAMLIB_BANDWITH),
|
||||
"FFT" : str(static.FFT),
|
||||
"SCATTER" : static.SCATTER,
|
||||
"FREQUENCY": str(static.HAMLIB_FREQUENCY),
|
||||
"MODE": str(static.HAMLIB_MODE),
|
||||
"BANDWITH": str(static.HAMLIB_BANDWITH),
|
||||
"FFT": str(static.FFT),
|
||||
"SCATTER": static.SCATTER,
|
||||
"RX_BUFFER_LENGTH": str(len(static.RX_BUFFER)),
|
||||
"TX_N_MAX_RETRIES": str(static.TX_N_MAX_RETRIES),
|
||||
"ARQ_TX_N_FRAMES_PER_BURST": str(static.ARQ_TX_N_FRAMES_PER_BURST),
|
||||
"ARQ_TX_N_BURSTS": str(static.ARQ_TX_N_BURSTS),
|
||||
"ARQ_TX_N_CURRENT_ARQ_FRAME": str(int.from_bytes(bytes(static.ARQ_TX_N_CURRENT_ARQ_FRAME), "big")),
|
||||
"ARQ_TX_N_TOTAL_ARQ_FRAMES": str(int.from_bytes(bytes(static.TX_BUFFER_SIZE), "big")), # WE NEED TO CHANGE THE JSON TO TX_BUFFER_SIZE?!
|
||||
# WE NEED TO CHANGE THE JSON TO TX_BUFFER_SIZE?!
|
||||
"ARQ_TX_N_TOTAL_ARQ_FRAMES": str(int.from_bytes(bytes(static.TX_BUFFER_SIZE), "big")),
|
||||
"ARQ_RX_FRAME_N_BURSTS": str(static.ARQ_RX_FRAME_N_BURSTS),
|
||||
"ARQ_RX_N_CURRENT_ARQ_FRAME": str(static.ARQ_RX_N_CURRENT_ARQ_FRAME),
|
||||
"ARQ_N_ARQ_FRAMES_PER_DATA_FRAME": str(int.from_bytes(bytes(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME), "big")),
|
||||
"ARQ_BYTES_PER_MINUTE" : str(static.ARQ_BYTES_PER_MINUTE),
|
||||
"ARQ_BYTES_PER_MINUTE_BURST" : str(static.ARQ_BYTES_PER_MINUTE_BURST),
|
||||
"ARQ_TRANSMISSION_PERCENT" : str(static.ARQ_TRANSMISSION_PERCENT),
|
||||
"TOTAL_BYTES" : str(static.TOTAL_BYTES),
|
||||
|
||||
"STATIONS" : [],
|
||||
"EOF" : "EOF",
|
||||
"ARQ_BYTES_PER_MINUTE": str(static.ARQ_BYTES_PER_MINUTE),
|
||||
"ARQ_BYTES_PER_MINUTE_BURST": str(static.ARQ_BYTES_PER_MINUTE_BURST),
|
||||
"ARQ_TRANSMISSION_PERCENT": str(static.ARQ_TRANSMISSION_PERCENT),
|
||||
"TOTAL_BYTES": str(static.TOTAL_BYTES),
|
||||
|
||||
"STATIONS": [],
|
||||
"EOF": "EOF",
|
||||
}
|
||||
|
||||
|
||||
for i in range(0, len(static.HEARD_STATIONS)):
|
||||
output["STATIONS"].append({"DXCALLSIGN": str(static.HEARD_STATIONS[i][0], 'utf-8'),"DXGRID": str(static.HEARD_STATIONS[i][1], 'utf-8'), "TIMESTAMP": static.HEARD_STATIONS[i][2], "DATATYPE": static.HEARD_STATIONS[i][3], "SNR": static.HEARD_STATIONS[i][4]})
|
||||
|
||||
|
||||
try:
|
||||
output["STATIONS"].append({"DXCALLSIGN": str(static.HEARD_STATIONS[i][0], 'utf-8'), "DXGRID": str(static.HEARD_STATIONS[i][1], 'utf-8'),"TIMESTAMP": static.HEARD_STATIONS[i][2], "DATATYPE": static.HEARD_STATIONS[i][3], "SNR": static.HEARD_STATIONS[i][4]})
|
||||
|
||||
try:
|
||||
jsondata = json.dumps(output)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
|
||||
|
||||
try:
|
||||
self.request.sendall(bytes(jsondata, encoding))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
if received_json["type"] == 'GET' and received_json["command"] == 'RX_BUFFER':
|
||||
output = {
|
||||
"COMMAND": "RX_BUFFER",
|
||||
"DATA-ARRAY" : [],
|
||||
"EOF" : "EOF",
|
||||
"DATA-ARRAY": [],
|
||||
"EOF": "EOF",
|
||||
}
|
||||
for i in range(0, len(static.RX_BUFFER)):
|
||||
|
||||
|
||||
rawdata = json.loads(static.RX_BUFFER[i][3])
|
||||
|
||||
output["DATA-ARRAY"].append({"DXCALLSIGN": str(static.RX_BUFFER[i][0], 'utf-8'),"DXGRID": str(static.RX_BUFFER[i][1], 'utf-8'), "TIMESTAMP": static.RX_BUFFER[i][2], "RXDATA": [rawdata]})
|
||||
|
||||
|
||||
output["DATA-ARRAY"].append({"DXCALLSIGN": str(static.RX_BUFFER[i][0], 'utf-8'), "DXGRID": str(static.RX_BUFFER[i][1], 'utf-8'), "TIMESTAMP": static.RX_BUFFER[i][2], "RXDATA": [rawdata]})
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
self.request.sendall(bytes(jsondata, encoding))
|
||||
|
||||
if received_json["type"] == 'SET' and received_json["command"] == 'DEL_RX_BUFFER':
|
||||
static.RX_BUFFER = []
|
||||
|
||||
|
||||
#exception, if JSON cant be decoded
|
||||
#except Exception as e:
|
||||
# exception, if JSON cant be decoded
|
||||
# except Exception as e:
|
||||
except:
|
||||
print("############ START OF ERROR #####################")
|
||||
print("SOCKET COMMAND ERROR: " + data)
|
||||
|
@ -248,19 +253,22 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
print("############ END OF ERROR #######################")
|
||||
|
||||
print("reset of connection...")
|
||||
#socketTimeout = 0
|
||||
#socketTimeout = 0
|
||||
print("Client disconnected...")
|
||||
|
||||
|
||||
def start_cmd_socket():
|
||||
|
||||
try:
|
||||
logging.info("SRV | STARTING TCP/IP SOCKET FOR CMD ON PORT: " + str(static.PORT))
|
||||
socketserver.TCPServer.allow_reuse_address = True # https://stackoverflow.com/a/16641793
|
||||
cmdserver = ThreadedTCPServer((static.HOST, static.PORT), ThreadedTCPRequestHandler)
|
||||
logging.info(
|
||||
"SRV | STARTING TCP/IP SOCKET FOR CMD ON PORT: " + str(static.PORT))
|
||||
# https://stackoverflow.com/a/16641793
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
cmdserver = ThreadedTCPServer(
|
||||
(static.HOST, static.PORT), ThreadedTCPRequestHandler)
|
||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
server_thread.start()
|
||||
|
||||
except:
|
||||
print("Socket error...")
|
||||
|
|
Loading…
Reference in a new issue