mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Incorporate some changes from pep8_improvements.
Simplify structlog calls. Other refactoring.
This commit is contained in:
parent
4c16efaf2c
commit
98c1030c24
40
tnc/audio.py
40
tnc/audio.py
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
@ -8,15 +7,16 @@ import sounddevice as sd
|
||||||
|
|
||||||
atexit.register(sd._terminate)
|
atexit.register(sd._terminate)
|
||||||
|
|
||||||
|
|
||||||
def get_audio_devices():
|
def get_audio_devices():
|
||||||
"""
|
"""
|
||||||
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
|
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
|
||||||
|
|
||||||
also uses a process data manager
|
also uses a process data manager
|
||||||
"""
|
"""
|
||||||
# we need to run this on windows for multiprocessing support
|
# we need to run this on Windows for multiprocessing support
|
||||||
# multiprocessing.freeze_support()
|
# multiprocessing.freeze_support()
|
||||||
#multiprocessing.get_context('spawn')
|
# multiprocessing.get_context("spawn")
|
||||||
|
|
||||||
# we need to reset and initialize sounddevice before running the multiprocessing part.
|
# we need to reset and initialize sounddevice before running the multiprocessing part.
|
||||||
# If we are not doing this at this early point, not all devices will be displayed
|
# If we are not doing this at this early point, not all devices will be displayed
|
||||||
|
@ -26,41 +26,43 @@ def get_audio_devices():
|
||||||
with multiprocessing.Manager() as manager:
|
with multiprocessing.Manager() as manager:
|
||||||
proxy_input_devices = manager.list()
|
proxy_input_devices = manager.list()
|
||||||
proxy_output_devices = manager.list()
|
proxy_output_devices = manager.list()
|
||||||
#print(multiprocessing.get_start_method())
|
# print(multiprocessing.get_start_method())
|
||||||
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
|
proc = multiprocessing.Process(
|
||||||
p.start()
|
target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)
|
||||||
p.join()
|
)
|
||||||
|
proc.start()
|
||||||
|
proc.join()
|
||||||
|
|
||||||
return list(proxy_input_devices), list(proxy_output_devices)
|
return list(proxy_input_devices), list(proxy_output_devices)
|
||||||
|
|
||||||
|
|
||||||
def fetch_audio_devices(input_devices, output_devices):
|
def fetch_audio_devices(input_devices, output_devices):
|
||||||
"""
|
"""
|
||||||
get audio devices from portaudio
|
get audio devices from portaudio
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_devices: proxy variable for input devices
|
input_devices: proxy variable for input devices
|
||||||
output_devices: proxy variable for outout devices
|
output_devices: proxy variable for output devices
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
devices = sd.query_devices(device=None, kind=None)
|
devices = sd.query_devices(device=None, kind=None)
|
||||||
for index, device in enumerate(devices):
|
for index, device in enumerate(devices):
|
||||||
#for i in range(0, p.get_device_count()):
|
# Use a try/except block beacuse Windows doesn't have an audio device range
|
||||||
# we need to do a try exception, beacuse for windows theres no audio device range
|
|
||||||
try:
|
try:
|
||||||
name = device["name"]
|
name = device["name"]
|
||||||
|
|
||||||
maxOutputChannels = device["max_output_channels"]
|
max_output_channels = device["max_output_channels"]
|
||||||
maxInputChannels = device["max_input_channels"]
|
max_input_channels = device["max_input_channels"]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
print(e)
|
print(err)
|
||||||
maxInputChannels = 0
|
max_input_channels = 0
|
||||||
maxOutputChannels = 0
|
max_output_channels = 0
|
||||||
name = ''
|
name = ""
|
||||||
|
|
||||||
if maxInputChannels > 0:
|
if max_input_channels > 0:
|
||||||
input_devices.append({"id": index, "name": name})
|
input_devices.append({"id": index, "name": name})
|
||||||
if maxOutputChannels > 0:
|
if max_output_channels > 0:
|
||||||
output_devices.append({"id": index, "name": name})
|
output_devices.append({"id": index, "name": name})
|
||||||
|
|
|
@ -16,6 +16,7 @@ from threading import Lock
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
log = structlog.get_logger(__file__)
|
||||||
|
|
||||||
# Enum for codec2 modes
|
# Enum for codec2 modes
|
||||||
class FREEDV_MODE(Enum):
|
class FREEDV_MODE(Enum):
|
||||||
|
@ -65,7 +66,7 @@ if hasattr(sys, "_MEIPASS"):
|
||||||
else:
|
else:
|
||||||
sys.path.append(os.path.abspath("."))
|
sys.path.append(os.path.abspath("."))
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
|
log.info("[C2 ] Searching for libcodec2...")
|
||||||
if sys.platform == "linux":
|
if sys.platform == "linux":
|
||||||
files = glob.glob(r"**/*libcodec2*", recursive=True)
|
files = glob.glob(r"**/*libcodec2*", recursive=True)
|
||||||
files.append("libcodec2.so")
|
files.append("libcodec2.so")
|
||||||
|
@ -80,16 +81,14 @@ api = None
|
||||||
for file in files:
|
for file in files:
|
||||||
try:
|
try:
|
||||||
api = ctypes.CDLL(file)
|
api = ctypes.CDLL(file)
|
||||||
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
|
log.info("[C2 ] Libcodec2 loaded", path=file)
|
||||||
break
|
break
|
||||||
except OSError as e:
|
except OSError as err:
|
||||||
structlog.get_logger("structlog").warning(
|
log.warning("[C2 ] Libcodec2 found but not loaded", path=file, e=err)
|
||||||
"[C2 ] Libcodec2 found but not loaded", path=file, e=e
|
|
||||||
)
|
|
||||||
|
|
||||||
# Quit module if codec2 cant be loaded
|
# Quit module if codec2 cant be loaded
|
||||||
if api is None or "api" not in locals():
|
if api is None or "api" not in locals():
|
||||||
structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded")
|
log.critical("[C2 ] Libcodec2 not loaded - Exiting")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ctypes function init
|
# ctypes function init
|
||||||
|
@ -271,7 +270,7 @@ api.rx_sync_flags_to_text = [ # type: ignore
|
||||||
# Audio buffer ---------------------------------------------------------
|
# Audio buffer ---------------------------------------------------------
|
||||||
class audio_buffer:
|
class audio_buffer:
|
||||||
"""
|
"""
|
||||||
Thread safe audio buffer, which fits to needs of codec2
|
Thread-safe audio buffer, which fits the needs of codec2
|
||||||
|
|
||||||
made by David Rowe, VK5DGR
|
made by David Rowe, VK5DGR
|
||||||
"""
|
"""
|
||||||
|
@ -279,9 +278,7 @@ class audio_buffer:
|
||||||
# A buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
# A buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
||||||
# self.nbuffer is the current number of samples in the buffer
|
# self.nbuffer is the current number of samples in the buffer
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
structlog.get_logger("structlog").debug(
|
log.debug("[C2 ] Creating audio buffer", size=size)
|
||||||
"[C2 ] Creating audio buffer", size=size
|
|
||||||
)
|
|
||||||
self.size = size
|
self.size = size
|
||||||
self.buffer = np.zeros(size, dtype=np.int16)
|
self.buffer = np.zeros(size, dtype=np.int16)
|
||||||
self.nbuffer = 0
|
self.nbuffer = 0
|
||||||
|
@ -343,7 +340,7 @@ class resampler:
|
||||||
MEM48 = api.FDMDV_OS_TAPS_48K
|
MEM48 = api.FDMDV_OS_TAPS_48K
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
structlog.get_logger("structlog").debug("[C2 ] Create 48<->8 kHz resampler")
|
log.debug("[C2 ] Create 48<->8 kHz resampler")
|
||||||
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
|
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
|
||||||
self.filter_mem48 = np.zeros(self.MEM48)
|
self.filter_mem48 = np.zeros(self.MEM48)
|
||||||
|
|
||||||
|
|
255
tnc/daemon.py
255
tnc/daemon.py
|
@ -15,8 +15,6 @@ import argparse
|
||||||
import atexit
|
import atexit
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import queue
|
|
||||||
import re
|
|
||||||
import signal
|
import signal
|
||||||
import socketserver
|
import socketserver
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -24,17 +22,14 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import crcengine
|
|
||||||
import psutil
|
|
||||||
import serial.tools.list_ports
|
|
||||||
import structlog
|
|
||||||
import ujson as json
|
|
||||||
|
|
||||||
import audio
|
import audio
|
||||||
import helpers
|
import crcengine
|
||||||
import log_handler
|
import log_handler
|
||||||
|
import serial.tools.list_ports
|
||||||
import sock
|
import sock
|
||||||
import static
|
import static
|
||||||
|
import structlog
|
||||||
|
import ujson as json
|
||||||
|
|
||||||
|
|
||||||
# signal handler for closing aplication
|
# signal handler for closing aplication
|
||||||
|
@ -47,26 +42,35 @@ def signal_handler(sig, frame):
|
||||||
|
|
||||||
Returns: system exit
|
Returns: system exit
|
||||||
"""
|
"""
|
||||||
print('Closing daemon...')
|
print("Closing daemon...")
|
||||||
sock.CLOSE_SIGNAL = True
|
sock.CLOSE_SIGNAL = True
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
class DAEMON():
|
|
||||||
|
class DAEMON:
|
||||||
"""
|
"""
|
||||||
Daemon class
|
Daemon class
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# load crc engine
|
# load crc engine
|
||||||
self.crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc8 library
|
self.crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library
|
||||||
|
|
||||||
self.daemon_queue = sock.DAEMON_QUEUE
|
self.daemon_queue = sock.DAEMON_QUEUE
|
||||||
update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True)
|
update_audio_devices = threading.Thread(
|
||||||
|
target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True
|
||||||
|
)
|
||||||
update_audio_devices.start()
|
update_audio_devices.start()
|
||||||
|
|
||||||
update_serial_devices = threading.Thread(target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True)
|
update_serial_devices = threading.Thread(
|
||||||
|
target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True
|
||||||
|
)
|
||||||
update_serial_devices.start()
|
update_serial_devices.start()
|
||||||
|
|
||||||
worker = threading.Thread(target=self.worker, name="WORKER", daemon=True)
|
worker = threading.Thread(target=self.worker, name="WORKER", daemon=True)
|
||||||
|
@ -79,9 +83,15 @@ class DAEMON():
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
try:
|
||||||
if not static.TNCSTARTED:
|
if not static.TNCSTARTED:
|
||||||
static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices()
|
(
|
||||||
except Exception as e:
|
static.AUDIO_INPUT_DEVICES,
|
||||||
structlog.get_logger("structlog").error("[DMN] update_audio_devices: Exception gathering audio devices:", e=e)
|
static.AUDIO_OUTPUT_DEVICES,
|
||||||
|
) = audio.get_audio_devices()
|
||||||
|
except Exception as err1:
|
||||||
|
self.log.error(
|
||||||
|
"[DMN] update_audio_devices: Exception gathering audio devices:",
|
||||||
|
e=err1,
|
||||||
|
)
|
||||||
# print(e)
|
# print(e)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
@ -91,21 +101,26 @@ class DAEMON():
|
||||||
"""
|
"""
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
try:
|
||||||
#print("update serial")
|
# print("update serial")
|
||||||
serial_devices = []
|
serial_devices = []
|
||||||
ports = serial.tools.list_ports.comports()
|
ports = serial.tools.list_ports.comports()
|
||||||
for port, desc, hwid in ports:
|
for port, desc, hwid in ports:
|
||||||
# calculate hex of hwid if we have unique names
|
# calculate hex of hwid if we have unique names
|
||||||
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8'))
|
crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
|
||||||
crc_hwid = crc_hwid.to_bytes(2, byteorder='big')
|
crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
|
||||||
crc_hwid = crc_hwid.hex()
|
crc_hwid = crc_hwid.hex()
|
||||||
description = f"{desc} [{crc_hwid}]"
|
description = f"{desc} [{crc_hwid}]"
|
||||||
serial_devices.append({"port": str(port), "description": str(description) })
|
serial_devices.append(
|
||||||
|
{"port": str(port), "description": str(description)}
|
||||||
|
)
|
||||||
|
|
||||||
static.SERIAL_DEVICES = serial_devices
|
static.SERIAL_DEVICES = serial_devices
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
except Exception as e:
|
except Exception as err1:
|
||||||
structlog.get_logger("structlog").error("[DMN] update_serial_devices: Exception gathering serial devices:", e=e)
|
self.log.error(
|
||||||
|
"[DMN] update_serial_devices: Exception gathering serial devices:",
|
||||||
|
e=err1,
|
||||||
|
)
|
||||||
# print(e)
|
# print(e)
|
||||||
|
|
||||||
def worker(self):
|
def worker(self):
|
||||||
|
@ -140,131 +155,131 @@ class DAEMON():
|
||||||
# data[22] tx-audio-level
|
# data[22] tx-audio-level
|
||||||
# data[23] respond_to_cq
|
# data[23] respond_to_cq
|
||||||
|
|
||||||
if data[0] == 'STARTTNC':
|
if data[0] == "STARTTNC":
|
||||||
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||||
|
|
||||||
# list of parameters, necessary for running subprocess command as a list
|
# list of parameters, necessary for running subprocess command as a list
|
||||||
options = []
|
options = []
|
||||||
|
|
||||||
options.append('--port')
|
options.append("--port")
|
||||||
options.append(str(static.DAEMONPORT - 1))
|
options.append(str(static.DAEMONPORT - 1))
|
||||||
|
|
||||||
options.append('--mycall')
|
options.append("--mycall")
|
||||||
options.append(data[1])
|
options.append(data[1])
|
||||||
|
|
||||||
options.append('--mygrid')
|
options.append("--mygrid")
|
||||||
options.append(data[2])
|
options.append(data[2])
|
||||||
|
|
||||||
options.append('--rx')
|
options.append("--rx")
|
||||||
options.append(data[3])
|
options.append(data[3])
|
||||||
|
|
||||||
options.append('--tx')
|
options.append("--tx")
|
||||||
options.append(data[4])
|
options.append(data[4])
|
||||||
|
|
||||||
# if radiocontrol != disabled
|
# if radiocontrol != disabled
|
||||||
# this should hopefully avoid a ton of problems if we are just running in
|
# this should hopefully avoid a ton of problems if we are just running in
|
||||||
# disabled mode
|
# disabled mode
|
||||||
|
|
||||||
if data[13] != 'disabled':
|
if data[13] != "disabled":
|
||||||
options.append('--devicename')
|
options.append("--devicename")
|
||||||
options.append(data[5])
|
options.append(data[5])
|
||||||
|
|
||||||
options.append('--deviceport')
|
options.append("--deviceport")
|
||||||
options.append(data[6])
|
options.append(data[6])
|
||||||
|
|
||||||
options.append('--serialspeed')
|
options.append("--serialspeed")
|
||||||
options.append(data[7])
|
options.append(data[7])
|
||||||
|
|
||||||
options.append('--pttprotocol')
|
options.append("--pttprotocol")
|
||||||
options.append(data[8])
|
options.append(data[8])
|
||||||
|
|
||||||
options.append('--pttport')
|
options.append("--pttport")
|
||||||
options.append(data[9])
|
options.append(data[9])
|
||||||
|
|
||||||
options.append('--data_bits')
|
options.append("--data_bits")
|
||||||
options.append(data[10])
|
options.append(data[10])
|
||||||
|
|
||||||
options.append('--stop_bits')
|
options.append("--stop_bits")
|
||||||
options.append(data[11])
|
options.append(data[11])
|
||||||
|
|
||||||
options.append('--handshake')
|
options.append("--handshake")
|
||||||
options.append(data[12])
|
options.append(data[12])
|
||||||
|
|
||||||
options.append('--radiocontrol')
|
options.append("--radiocontrol")
|
||||||
options.append(data[13])
|
options.append(data[13])
|
||||||
|
|
||||||
if data[13] == 'rigctld':
|
if data[13] == "rigctld":
|
||||||
options.append('--rigctld_ip')
|
options.append("--rigctld_ip")
|
||||||
options.append(data[14])
|
options.append(data[14])
|
||||||
|
|
||||||
options.append('--rigctld_port')
|
options.append("--rigctld_port")
|
||||||
options.append(data[15])
|
options.append(data[15])
|
||||||
|
|
||||||
if data[16] == 'True':
|
if data[16] == "True":
|
||||||
options.append('--scatter')
|
options.append("--scatter")
|
||||||
|
|
||||||
if data[17] == 'True':
|
if data[17] == "True":
|
||||||
options.append('--fft')
|
options.append("--fft")
|
||||||
|
|
||||||
if data[18] == 'True':
|
if data[18] == "True":
|
||||||
options.append('--500hz')
|
options.append("--500hz")
|
||||||
|
|
||||||
options.append('--tuning_range_fmin')
|
options.append("--tuning_range_fmin")
|
||||||
options.append(data[19])
|
options.append(data[19])
|
||||||
|
|
||||||
options.append('--tuning_range_fmax')
|
options.append("--tuning_range_fmax")
|
||||||
options.append(data[20])
|
options.append(data[20])
|
||||||
|
|
||||||
# overriding FSK mode
|
# overriding FSK mode
|
||||||
#if data[21] == 'True':
|
# if data[21] == "True":
|
||||||
# options.append('--fsk')
|
# options.append("--fsk")
|
||||||
|
|
||||||
options.append('--tx-audio-level')
|
options.append("--tx-audio-level")
|
||||||
options.append(data[22])
|
options.append(data[22])
|
||||||
|
|
||||||
if data[23] == 'True':
|
if data[23] == "True":
|
||||||
options.append('--qrv')
|
options.append("--qrv")
|
||||||
|
|
||||||
# Try running tnc from binary, else run from source
|
# Try running tnc from binary, else run from source
|
||||||
# This helps running the tnc in a developer environment
|
# This helps running the tnc in a developer environment
|
||||||
try:
|
try:
|
||||||
command = []
|
command = []
|
||||||
if sys.platform in ['linux', 'darwin']:
|
if sys.platform in ["linux", "darwin"]:
|
||||||
command.append('./freedata-tnc')
|
command.append("./freedata-tnc")
|
||||||
elif sys.platform in ['win32', 'win64']:
|
elif sys.platform in ["win32", "win64"]:
|
||||||
command.append('freedata-tnc.exe')
|
command.append("freedata-tnc.exe")
|
||||||
|
|
||||||
command += options
|
command += options
|
||||||
p = subprocess.Popen(command)
|
p = subprocess.Popen(command)
|
||||||
|
|
||||||
atexit.register(p.kill)
|
atexit.register(p.kill)
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary")
|
self.log.info("[DMN] TNC started", path="binary")
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as err1:
|
||||||
structlog.get_logger("structlog").error("[DMN] worker: Exception:", e=e)
|
self.log.info("[DMN] worker: ", e=err1)
|
||||||
command = []
|
command = []
|
||||||
if sys.platform in ['linux', 'darwin']:
|
if sys.platform in ["linux", "darwin"]:
|
||||||
command.append('python3')
|
command.append("python3")
|
||||||
elif sys.platform in ['win32', 'win64']:
|
elif sys.platform in ["win32", "win64"]:
|
||||||
command.append('python')
|
command.append("python")
|
||||||
|
|
||||||
command.append('main.py')
|
command.append("main.py")
|
||||||
command += options
|
command += options
|
||||||
p = subprocess.Popen(command)
|
p = subprocess.Popen(command)
|
||||||
atexit.register(p.kill)
|
atexit.register(p.kill)
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[DMN] TNC started", path="source")
|
self.log.info("[DMN] TNC started", path="source")
|
||||||
|
|
||||||
static.TNCPROCESS = p # .pid
|
static.TNCPROCESS = p # .pid
|
||||||
static.TNCSTARTED = True
|
static.TNCSTARTED = True
|
||||||
'''
|
"""
|
||||||
# WE HAVE THIS PART in SOCKET
|
# WE HAVE THIS PART in SOCKET
|
||||||
if data[0] == 'STOPTNC':
|
if data[0] == "STOPTNC":
|
||||||
static.TNCPROCESS.kill()
|
static.TNCPROCESS.kill()
|
||||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
self.log.warning("[DMN] Stopping TNC")
|
||||||
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
||||||
static.TNCSTARTED = False
|
static.TNCSTARTED = False
|
||||||
'''
|
"""
|
||||||
# data[1] devicename
|
# data[1] devicename
|
||||||
# data[2] deviceport
|
# data[2] deviceport
|
||||||
# data[3] serialspeed
|
# data[3] serialspeed
|
||||||
|
@ -276,7 +291,7 @@ class DAEMON():
|
||||||
# data[9] radiocontrol
|
# data[9] radiocontrol
|
||||||
# data[10] rigctld_ip
|
# data[10] rigctld_ip
|
||||||
# data[11] rigctld_port
|
# data[11] rigctld_port
|
||||||
if data[0] == 'TEST_HAMLIB':
|
if data[0] == "TEST_HAMLIB":
|
||||||
devicename = data[1]
|
devicename = data[1]
|
||||||
deviceport = data[2]
|
deviceport = data[2]
|
||||||
serialspeed = data[3]
|
serialspeed = data[3]
|
||||||
|
@ -290,19 +305,28 @@ class DAEMON():
|
||||||
rigctld_port = data[11]
|
rigctld_port = data[11]
|
||||||
|
|
||||||
# check how we want to control the radio
|
# check how we want to control the radio
|
||||||
if radiocontrol == 'direct':
|
if radiocontrol == "direct":
|
||||||
import rig
|
import rig
|
||||||
elif radiocontrol == 'rigctl':
|
elif radiocontrol == "rigctl":
|
||||||
import rigctl as rig
|
import rigctl as rig
|
||||||
elif radiocontrol == 'rigctld':
|
elif radiocontrol == "rigctld":
|
||||||
import rigctld as rig
|
import rigctld as rig
|
||||||
else:
|
else:
|
||||||
import rigdummy as rig
|
import rigdummy as rig
|
||||||
|
|
||||||
hamlib = rig.radio()
|
hamlib = rig.radio()
|
||||||
hamlib.open_rig(devicename=devicename, deviceport=deviceport, hamlib_ptt_type=pttprotocol,
|
hamlib.open_rig(
|
||||||
serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits,
|
devicename=devicename,
|
||||||
handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port)
|
deviceport=deviceport,
|
||||||
|
hamlib_ptt_type=pttprotocol,
|
||||||
|
serialspeed=serialspeed,
|
||||||
|
pttport=pttport,
|
||||||
|
data_bits=data_bits,
|
||||||
|
stop_bits=stop_bits,
|
||||||
|
handshake=handshake,
|
||||||
|
rigctld_ip=rigctld_ip,
|
||||||
|
rigctld_port=rigctld_port,
|
||||||
|
)
|
||||||
|
|
||||||
hamlib_version = rig.hamlib_version
|
hamlib_version = rig.hamlib_version
|
||||||
|
|
||||||
|
@ -310,14 +334,14 @@ class DAEMON():
|
||||||
pttstate = hamlib.get_ptt()
|
pttstate = hamlib.get_ptt()
|
||||||
|
|
||||||
if pttstate:
|
if pttstate:
|
||||||
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status='SUCCESS')
|
self.log.info("[DMN] Hamlib PTT", status="SUCCESS")
|
||||||
response = {'command': 'test_hamlib', 'result': 'SUCCESS'}
|
response = {"command": "test_hamlib", "result": "SUCCESS"}
|
||||||
elif not pttstate:
|
elif not pttstate:
|
||||||
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status='NO SUCCESS')
|
self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS")
|
||||||
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'}
|
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status='FAILED')
|
self.log.error("[DMN] Hamlib PTT", status="FAILED")
|
||||||
response = {'command': 'test_hamlib', 'result': 'FAILED'}
|
response = {"command": "test_hamlib", "result": "FAILED"}
|
||||||
|
|
||||||
hamlib.set_ptt(False)
|
hamlib.set_ptt(False)
|
||||||
hamlib.close_rig()
|
hamlib.close_rig()
|
||||||
|
@ -325,51 +349,74 @@ class DAEMON():
|
||||||
jsondata = json.dumps(response)
|
jsondata = json.dumps(response)
|
||||||
sock.SOCKET_QUEUE.put(jsondata)
|
sock.SOCKET_QUEUE.put(jsondata)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err1:
|
||||||
structlog.get_logger("structlog").error("[DMN] worker: Exception: ", e=e)
|
self.log.error("[DMN] worker: Exception: ", e=err1)
|
||||||
# print(e)
|
# print(e)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
mainlog = structlog.get_logger(__file__)
|
||||||
# we need to run this on windows for multiprocessing support
|
# we need to run this on windows for multiprocessing support
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support()
|
||||||
|
|
||||||
# --------------------------------------------GET PARAMETER INPUTS
|
# --------------------------------------------GET PARAMETER INPUTS
|
||||||
PARSER = argparse.ArgumentParser(description='FreeDATA Daemon')
|
PARSER = argparse.ArgumentParser(description="FreeDATA Daemon")
|
||||||
PARSER.add_argument('--port', dest="socket_port", default=3001, help="Socket port in the range of 1024-65536", type=int)
|
PARSER.add_argument(
|
||||||
|
"--port",
|
||||||
|
dest="socket_port",
|
||||||
|
default=3001,
|
||||||
|
help="Socket port in the range of 1024-65536",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
ARGS = PARSER.parse_args()
|
ARGS = PARSER.parse_args()
|
||||||
|
|
||||||
static.DAEMONPORT = ARGS.socket_port
|
static.DAEMONPORT = ARGS.socket_port
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.platform == 'linux':
|
if sys.platform == "linux":
|
||||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon'
|
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == "darwin":
|
||||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon'
|
logging_path = (
|
||||||
|
os.getenv("HOME")
|
||||||
|
+ "/Library/"
|
||||||
|
+ "Application Support/"
|
||||||
|
+ "FreeDATA/"
|
||||||
|
+ "daemon"
|
||||||
|
)
|
||||||
|
|
||||||
if sys.platform in ['win32', 'win64']:
|
if sys.platform in ["win32", "win64"]:
|
||||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon'
|
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
|
||||||
|
|
||||||
if not os.path.exists(logging_path):
|
if not os.path.exists(logging_path):
|
||||||
os.makedirs(logging_path)
|
os.makedirs(logging_path)
|
||||||
log_handler.setup_logging(logging_path)
|
log_handler.setup_logging(logging_path)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e)
|
mainlog.error("[DMN] logger init error", exception=err)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
structlog.get_logger("structlog").info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
|
mainlog.info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
|
||||||
# https://stackoverflow.com/a/16641793
|
# https://stackoverflow.com/a/16641793
|
||||||
socketserver.TCPServer.allow_reuse_address = True
|
socketserver.TCPServer.allow_reuse_address = True
|
||||||
cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler)
|
cmdserver = sock.ThreadedTCPServer(
|
||||||
|
(static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler
|
||||||
|
)
|
||||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||||
server_thread.daemon = True
|
server_thread.daemon = True
|
||||||
server_thread.start()
|
server_thread.start()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e)
|
mainlog.error(
|
||||||
|
"[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
daemon = DAEMON()
|
daemon = DAEMON()
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION)
|
mainlog.info(
|
||||||
|
"[DMN] Starting FreeDATA Daemon",
|
||||||
|
author="DJ2LS",
|
||||||
|
year="2022",
|
||||||
|
version=static.VERSION,
|
||||||
|
)
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
|
@ -81,7 +81,7 @@ class DATA:
|
||||||
self.data_channel_max_retries = 5
|
self.data_channel_max_retries = 5
|
||||||
self.datachannel_timeout = False
|
self.datachannel_timeout = False
|
||||||
|
|
||||||
# List of codec2 modes to use in 'low bandwidth' mode.
|
# List of codec2 modes to use in "low bandwidth" mode.
|
||||||
self.mode_list_low_bw = [
|
self.mode_list_low_bw = [
|
||||||
codec2.FREEDV_MODE.datac0.value,
|
codec2.FREEDV_MODE.datac0.value,
|
||||||
codec2.FREEDV_MODE.datac3.value,
|
codec2.FREEDV_MODE.datac3.value,
|
||||||
|
@ -89,7 +89,7 @@ class DATA:
|
||||||
# List for time to wait for corresponding mode in seconds
|
# List for time to wait for corresponding mode in seconds
|
||||||
self.time_list_low_bw = [3, 7]
|
self.time_list_low_bw = [3, 7]
|
||||||
|
|
||||||
# List of codec2 modes to use in 'high bandwidth' mode.
|
# List of codec2 modes to use in "high bandwidth" mode.
|
||||||
self.mode_list_high_bw = [
|
self.mode_list_high_bw = [
|
||||||
codec2.FREEDV_MODE.datac0.value,
|
codec2.FREEDV_MODE.datac0.value,
|
||||||
codec2.FREEDV_MODE.datac3.value,
|
codec2.FREEDV_MODE.datac3.value,
|
||||||
|
@ -101,13 +101,13 @@ class DATA:
|
||||||
# Mode list for selecting between low bandwidth ( 500Hz ) and modes with higher bandwidth
|
# Mode list for selecting between low bandwidth ( 500Hz ) and modes with higher bandwidth
|
||||||
# but ability to fall back to low bandwidth modes if needed.
|
# but ability to fall back to low bandwidth modes if needed.
|
||||||
if static.LOW_BANDWITH_MODE:
|
if static.LOW_BANDWITH_MODE:
|
||||||
# List of codec2 modes to use in 'low bandwidth' mode.
|
# List of codec2 modes to use in "low bandwidth" mode.
|
||||||
self.mode_list = self.mode_list_low_bw
|
self.mode_list = self.mode_list_low_bw
|
||||||
# list of times to wait for corresponding mode in seconds
|
# list of times to wait for corresponding mode in seconds
|
||||||
self.time_list = self.time_list_low_bw
|
self.time_list = self.time_list_low_bw
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# List of codec2 modes to use in 'high bandwidth' mode.
|
# List of codec2 modes to use in "high bandwidth" mode.
|
||||||
self.mode_list = self.mode_list_high_bw
|
self.mode_list = self.mode_list_high_bw
|
||||||
# list of times to wait for corresponding mode in seconds
|
# list of times to wait for corresponding mode in seconds
|
||||||
self.time_list = self.time_list_high_bw
|
self.time_list = self.time_list_high_bw
|
||||||
|
@ -968,7 +968,7 @@ class DATA:
|
||||||
break # break retry loop
|
break # break retry loop
|
||||||
|
|
||||||
# We need this part for leaving the repeat loop
|
# We need this part for leaving the repeat loop
|
||||||
# static.ARQ_STATE == 'DATA' --> when stopping transmission manually
|
# static.ARQ_STATE == "DATA" --> when stopping transmission manually
|
||||||
if not static.ARQ_STATE:
|
if not static.ARQ_STATE:
|
||||||
# print("not ready for data...leaving loop....")
|
# print("not ready for data...leaving loop....")
|
||||||
break
|
break
|
||||||
|
@ -1205,10 +1205,7 @@ class DATA:
|
||||||
# ############################################################################################################
|
# ############################################################################################################
|
||||||
def arq_session_handler(self) -> bool:
|
def arq_session_handler(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Create a session with `callsign` and wait until the session is open.
|
Create a session with `static.DXCALLSIGN` and wait until the session is open.
|
||||||
|
|
||||||
Args:
|
|
||||||
callsign:
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if the session was opened successfully
|
True if the session was opened successfully
|
||||||
|
@ -1233,7 +1230,7 @@ class DATA:
|
||||||
static.ARQ_SESSION_STATE = "connecting"
|
static.ARQ_SESSION_STATE = "connecting"
|
||||||
|
|
||||||
if static.ARQ_SESSION and static.ARQ_SESSION_STATE == "connected":
|
if static.ARQ_SESSION and static.ARQ_SESSION_STATE == "connected":
|
||||||
# static.ARQ_SESSION_STATE = 'connected'
|
# static.ARQ_SESSION_STATE = "connected"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
static.ARQ_SESSION_STATE = "failed"
|
static.ARQ_SESSION_STATE = "failed"
|
||||||
|
@ -1278,7 +1275,6 @@ class DATA:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
# Stop waiting if data channel is opened
|
# Stop waiting if data channel is opened
|
||||||
if static.ARQ_SESSION:
|
if static.ARQ_SESSION:
|
||||||
# eventuell einfach nur return true um die nächste break ebene zu vermeiden?
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Session connect timeout, send close_session frame to
|
# Session connect timeout, send close_session frame to
|
||||||
|
@ -1392,8 +1388,8 @@ class DATA:
|
||||||
def transmit_session_heartbeat(self) -> None:
|
def transmit_session_heartbeat(self) -> None:
|
||||||
"""Send ARQ sesion heartbeat while connected"""
|
"""Send ARQ sesion heartbeat while connected"""
|
||||||
# static.ARQ_SESSION = True
|
# static.ARQ_SESSION = True
|
||||||
# static.TNC_STATE = 'BUSY'
|
# static.TNC_STATE = "BUSY"
|
||||||
# static.ARQ_SESSION_STATE = 'connected'
|
# static.ARQ_SESSION_STATE = "connected"
|
||||||
|
|
||||||
connection_frame = bytearray(14)
|
connection_frame = bytearray(14)
|
||||||
connection_frame[:1] = bytes([222])
|
connection_frame[:1] = bytes([222])
|
||||||
|
@ -1933,9 +1929,7 @@ class DATA:
|
||||||
if static.ENABLE_FSK:
|
if static.ENABLE_FSK:
|
||||||
self.enqueue_frame_for_tx(
|
self.enqueue_frame_for_tx(
|
||||||
beacon_frame,
|
beacon_frame,
|
||||||
c2_mode=codec2.freedv_get_mode_value_by_name(
|
c2_mode=codec2.FREEDV_MODE.fsk_ldpc_0.value,
|
||||||
"FSK_LDPC_0"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.enqueue_frame_for_tx(beacon_frame)
|
self.enqueue_frame_for_tx(beacon_frame)
|
||||||
|
@ -2010,7 +2004,7 @@ class DATA:
|
||||||
|
|
||||||
if static.ENABLE_FSK:
|
if static.ENABLE_FSK:
|
||||||
self.enqueue_frame_for_tx(
|
self.enqueue_frame_for_tx(
|
||||||
cq_frame, c2_mode=codec2.freedv_get_mode_value_by_name("FSK_LDPC_0")
|
cq_frame, c2_mode=codec2.FREEDV_MODE.fsk_ldpc_0.value
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.enqueue_frame_for_tx(cq_frame)
|
self.enqueue_frame_for_tx(cq_frame)
|
||||||
|
@ -2074,7 +2068,7 @@ class DATA:
|
||||||
|
|
||||||
if static.ENABLE_FSK:
|
if static.ENABLE_FSK:
|
||||||
self.enqueue_frame_for_tx(
|
self.enqueue_frame_for_tx(
|
||||||
qrv_frame, c2_mode=codec2.freedv_get_mode_value_by_name("FSK_LDPC_0")
|
qrv_frame, c2_mode=codec2.FREEDV_MODE.fsk_ldpc_0.value
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.enqueue_frame_for_tx(qrv_frame)
|
self.enqueue_frame_for_tx(qrv_frame)
|
||||||
|
@ -2299,18 +2293,16 @@ class DATA:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# set modes we want to listen to
|
# set modes we want to listen to
|
||||||
mode_name = codec2.freedv_get_mode_name_by_value(mode)
|
if mode == codec2.FREEDV_MODE.datac1.value:
|
||||||
|
|
||||||
if mode_name == "datac1":
|
|
||||||
modem.RECEIVE_DATAC1 = True
|
modem.RECEIVE_DATAC1 = True
|
||||||
self.log.debug("[TNC] Changing listening data mode", mode="datac1")
|
self.log.debug("[TNC] Changing listening data mode", mode="datac1")
|
||||||
elif mode_name == "datac3":
|
elif mode == codec2.FREEDV_MODE.datac3.value:
|
||||||
modem.RECEIVE_DATAC3 = True
|
modem.RECEIVE_DATAC3 = True
|
||||||
self.log.debug("[TNC] Changing listening data mode", mode="datac3")
|
self.log.debug("[TNC] Changing listening data mode", mode="datac3")
|
||||||
elif mode_name == "fsk_ldpc_1":
|
elif mode == codec2.FREEDV_MODE.fsk_ldpc_1.value:
|
||||||
modem.RECEIVE_FSK_LDPC_1 = True
|
modem.RECEIVE_FSK_LDPC_1 = True
|
||||||
self.log.debug("[TNC] Changing listening data mode", mode="fsk_ldpc_1")
|
self.log.debug("[TNC] Changing listening data mode", mode="fsk_ldpc_1")
|
||||||
elif mode_name == "allmodes":
|
elif mode == codec2.FREEDV_MODE.allmodes.value:
|
||||||
modem.RECEIVE_DATAC1 = True
|
modem.RECEIVE_DATAC1 = True
|
||||||
modem.RECEIVE_DATAC3 = True
|
modem.RECEIVE_DATAC3 = True
|
||||||
modem.RECEIVE_FSK_LDPC_1 = True
|
modem.RECEIVE_FSK_LDPC_1 = True
|
||||||
|
|
248
tnc/helpers.py
248
tnc/helpers.py
|
@ -8,9 +8,10 @@ Created on Fri Dec 25 21:25:14 2020
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import crcengine
|
import crcengine
|
||||||
|
import static
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
import static
|
log = structlog.get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
def wait(seconds: float) -> bool:
|
def wait(seconds: float) -> bool:
|
||||||
|
@ -27,6 +28,7 @@ def wait(seconds: float) -> bool:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_crc_8(data) -> bytes:
|
def get_crc_8(data) -> bytes:
|
||||||
"""Author: DJ2LS
|
"""Author: DJ2LS
|
||||||
|
|
||||||
|
@ -40,11 +42,12 @@ def get_crc_8(data) -> bytes:
|
||||||
Returns:
|
Returns:
|
||||||
CRC-8 (CCITT) of the provided data as bytes
|
CRC-8 (CCITT) of the provided data as bytes
|
||||||
"""
|
"""
|
||||||
crc_algorithm = crcengine.new('crc8-ccitt') # load crc8 library
|
crc_algorithm = crcengine.new("crc8-ccitt") # load crc8 library
|
||||||
crc_data = crc_algorithm(data)
|
crc_data = crc_algorithm(data)
|
||||||
crc_data = crc_data.to_bytes(1, byteorder='big')
|
crc_data = crc_data.to_bytes(1, byteorder="big")
|
||||||
return crc_data
|
return crc_data
|
||||||
|
|
||||||
|
|
||||||
def get_crc_16(data) -> bytes:
|
def get_crc_16(data) -> bytes:
|
||||||
"""Author: DJ2LS
|
"""Author: DJ2LS
|
||||||
|
|
||||||
|
@ -58,11 +61,12 @@ def get_crc_16(data) -> bytes:
|
||||||
Returns:
|
Returns:
|
||||||
CRC-16 (CCITT) of the provided data as bytes
|
CRC-16 (CCITT) of the provided data as bytes
|
||||||
"""
|
"""
|
||||||
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library
|
crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
|
||||||
crc_data = crc_algorithm(data)
|
crc_data = crc_algorithm(data)
|
||||||
crc_data = crc_data.to_bytes(2, byteorder='big')
|
crc_data = crc_data.to_bytes(2, byteorder="big")
|
||||||
return crc_data
|
return crc_data
|
||||||
|
|
||||||
|
|
||||||
def get_crc_24(data) -> bytes:
|
def get_crc_24(data) -> bytes:
|
||||||
"""Author: DJ2LS
|
"""Author: DJ2LS
|
||||||
|
|
||||||
|
@ -77,13 +81,20 @@ def get_crc_24(data) -> bytes:
|
||||||
Returns:
|
Returns:
|
||||||
CRC-24 (OpenPGP) of the provided data as bytes
|
CRC-24 (OpenPGP) of the provided data as bytes
|
||||||
"""
|
"""
|
||||||
crc_algorithm = crcengine.create(0x864cfb, 24, 0xb704ce, ref_in=False,
|
crc_algorithm = crcengine.create(
|
||||||
ref_out=False, xor_out=0,
|
0x864CFB,
|
||||||
name='crc-24-openpgp')
|
24,
|
||||||
|
0xB704CE,
|
||||||
|
ref_in=False,
|
||||||
|
ref_out=False,
|
||||||
|
xor_out=0,
|
||||||
|
name="crc-24-openpgp",
|
||||||
|
)
|
||||||
crc_data = crc_algorithm(data)
|
crc_data = crc_algorithm(data)
|
||||||
crc_data = crc_data.to_bytes(3, byteorder='big')
|
crc_data = crc_data.to_bytes(3, byteorder="big")
|
||||||
return crc_data
|
return crc_data
|
||||||
|
|
||||||
|
|
||||||
def get_crc_32(data: bytes) -> bytes:
|
def get_crc_32(data: bytes) -> bytes:
|
||||||
"""Author: DJ2LS
|
"""Author: DJ2LS
|
||||||
|
|
||||||
|
@ -97,11 +108,12 @@ def get_crc_32(data: bytes) -> bytes:
|
||||||
Returns:
|
Returns:
|
||||||
CRC-32 of the provided data as bytes
|
CRC-32 of the provided data as bytes
|
||||||
"""
|
"""
|
||||||
crc_algorithm = crcengine.new('crc32') # load crc32 library
|
crc_algorithm = crcengine.new("crc32") # load crc32 library
|
||||||
crc_data = crc_algorithm(data)
|
crc_data = crc_algorithm(data)
|
||||||
crc_data = crc_data.to_bytes(4, byteorder='big')
|
crc_data = crc_data.to_bytes(4, byteorder="big")
|
||||||
return crc_data
|
return crc_data
|
||||||
|
|
||||||
|
|
||||||
def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -118,24 +130,46 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||||
"""
|
"""
|
||||||
# check if buffer empty
|
# check if buffer empty
|
||||||
if len(static.HEARD_STATIONS) == 0:
|
if len(static.HEARD_STATIONS) == 0:
|
||||||
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency])
|
static.HEARD_STATIONS.append(
|
||||||
|
[dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
|
||||||
|
)
|
||||||
# if not, we search and update
|
# if not, we search and update
|
||||||
else:
|
else:
|
||||||
for i in range(len(static.HEARD_STATIONS)):
|
for i in range(len(static.HEARD_STATIONS)):
|
||||||
# Update callsign with new timestamp
|
# Update callsign with new timestamp
|
||||||
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
||||||
static.HEARD_STATIONS[i] = [dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
|
static.HEARD_STATIONS[i] = [
|
||||||
|
dxcallsign,
|
||||||
|
dxgrid,
|
||||||
|
int(time.time()),
|
||||||
|
datatype,
|
||||||
|
snr,
|
||||||
|
offset,
|
||||||
|
frequency,
|
||||||
|
]
|
||||||
break
|
break
|
||||||
# Insert if nothing found
|
# Insert if nothing found
|
||||||
if i == len(static.HEARD_STATIONS) - 1:
|
if i == len(static.HEARD_STATIONS) - 1:
|
||||||
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency])
|
static.HEARD_STATIONS.append(
|
||||||
|
[
|
||||||
|
dxcallsign,
|
||||||
|
dxgrid,
|
||||||
|
int(time.time()),
|
||||||
|
datatype,
|
||||||
|
snr,
|
||||||
|
offset,
|
||||||
|
frequency,
|
||||||
|
]
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# for idx, item in enumerate(static.HEARD_STATIONS):
|
# for idx, item in enumerate(static.HEARD_STATIONS):
|
||||||
# if dxcallsign in item:
|
# if dxcallsign in item:
|
||||||
# item = [dxcallsign, int(time.time())]
|
# item = [dxcallsign, int(time.time())]
|
||||||
# static.HEARD_STATIONS[idx] = item
|
# static.HEARD_STATIONS[idx] = item
|
||||||
|
|
||||||
|
|
||||||
def callsign_to_bytes(callsign) -> bytes:
|
def callsign_to_bytes(callsign) -> bytes:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -146,48 +180,49 @@ def callsign_to_bytes(callsign) -> bytes:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# http://www.aprs.org/aprs11/SSIDs.txt
|
# http://www.aprs.org/aprs11/SSIDs.txt
|
||||||
#-0 Your primary station usually fixed and message capable
|
# -0 Your primary station usually fixed and message capable
|
||||||
#-1 generic additional station, digi, mobile, wx, etc
|
# -1 generic additional station, digi, mobile, wx, etc
|
||||||
#-2 generic additional station, digi, mobile, wx, etc
|
# -2 generic additional station, digi, mobile, wx, etc
|
||||||
#-3 generic additional station, digi, mobile, wx, etc
|
# -3 generic additional station, digi, mobile, wx, etc
|
||||||
#-4 generic additional station, digi, mobile, wx, etc
|
# -4 generic additional station, digi, mobile, wx, etc
|
||||||
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||||
#-6 Special activity, Satellite ops, camping or 6 meters, etc
|
# -6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||||
#-7 walkie talkies, HT's or other human portable
|
# -7 walkie talkies, HT's or other human portable
|
||||||
#-8 boats, sailboats, RV's or second main mobile
|
# -8 boats, sailboats, RV's or second main mobile
|
||||||
#-9 Primary Mobile (usually message capable)
|
# -9 Primary Mobile (usually message capable)
|
||||||
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||||
#-11 balloons, aircraft, spacecraft, etc
|
# -11 balloons, aircraft, spacecraft, etc
|
||||||
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||||
#-13 Weather stations
|
# -13 Weather stations
|
||||||
#-14 Truckers or generally full time drivers
|
# -14 Truckers or generally full time drivers
|
||||||
#-15 generic additional station, digi, mobile, wx, etc
|
# -15 generic additional station, digi, mobile, wx, etc
|
||||||
|
|
||||||
# Try converting to bytestring if possible type string
|
# Try converting to bytestring if possible type string
|
||||||
try:
|
try:
|
||||||
callsign = bytes(callsign, 'utf-8')
|
callsign = bytes(callsign, "utf-8")
|
||||||
except TypeError as e:
|
except TypeError as err:
|
||||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=e)
|
log.debug("[HLP] callsign_to_bytes: Error converting callsign to bytes:", e=err)
|
||||||
pass
|
|
||||||
|
|
||||||
# Need this step to reduce the needed payload by the callsign (stripping "-" out of the callsign)
|
# Need this step to reduce the needed payload by the callsign
|
||||||
callsign = callsign.split(b'-')
|
# (stripping "-" out of the callsign)
|
||||||
|
callsign = callsign.split(b"-")
|
||||||
ssid = 0
|
ssid = 0
|
||||||
try:
|
try:
|
||||||
ssid = int(callsign[1])
|
ssid = int(callsign[1])
|
||||||
except IndexError as e:
|
except IndexError as err:
|
||||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=e)
|
log.debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||||
|
|
||||||
#callsign = callsign[0]
|
# callsign = callsign[0]
|
||||||
#bytestring = bytearray(8)
|
# bytestring = bytearray(8)
|
||||||
#bytestring[:len(callsign)] = callsign
|
# bytestring[:len(callsign)] = callsign
|
||||||
#bytestring[7:8] = bytes([ssid])
|
# bytestring[7:8] = bytes([ssid])
|
||||||
|
|
||||||
# ---- callsign with encoding always 6 bytes long
|
# ---- callsign with encoding always 6 bytes long
|
||||||
callsign = callsign[0].decode("utf-8")
|
callsign = callsign[0].decode("utf-8")
|
||||||
ssid = bytes([ssid]).decode("utf-8")
|
ssid = bytes([ssid]).decode("utf-8")
|
||||||
return encode_call(callsign + ssid)
|
return encode_call(callsign + ssid)
|
||||||
#return bytes(bytestring)
|
# return bytes(bytestring)
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_callsign(bytestring: bytes) -> bytes:
|
def bytes_to_callsign(bytestring: bytes) -> bytes:
|
||||||
"""
|
"""
|
||||||
|
@ -200,25 +235,25 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
|
||||||
bytes
|
bytes
|
||||||
"""
|
"""
|
||||||
# http://www.aprs.org/aprs11/SSIDs.txt
|
# http://www.aprs.org/aprs11/SSIDs.txt
|
||||||
#-0 Your primary station usually fixed and message capable
|
# -0 Your primary station usually fixed and message capable
|
||||||
#-1 generic additional station, digi, mobile, wx, etc
|
# -1 generic additional station, digi, mobile, wx, etc
|
||||||
#-2 generic additional station, digi, mobile, wx, etc
|
# -2 generic additional station, digi, mobile, wx, etc
|
||||||
#-3 generic additional station, digi, mobile, wx, etc
|
# -3 generic additional station, digi, mobile, wx, etc
|
||||||
#-4 generic additional station, digi, mobile, wx, etc
|
# -4 generic additional station, digi, mobile, wx, etc
|
||||||
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||||
#-6 Special activity, Satellite ops, camping or 6 meters, etc
|
# -6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||||
#-7 walkie talkies, HT's or other human portable
|
# -7 walkie talkies, HT's or other human portable
|
||||||
#-8 boats, sailboats, RV's or second main mobile
|
# -8 boats, sailboats, RV's or second main mobile
|
||||||
#-9 Primary Mobile (usually message capable)
|
# -9 Primary Mobile (usually message capable)
|
||||||
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||||
#-11 balloons, aircraft, spacecraft, etc
|
# -11 balloons, aircraft, spacecraft, etc
|
||||||
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||||
#-13 Weather stations
|
# -13 Weather stations
|
||||||
#-14 Truckers or generally full time drivers
|
# -14 Truckers or generally full time drivers
|
||||||
#-15 generic additional station, digi, mobile, wx, etc
|
# -15 generic additional station, digi, mobile, wx, etc
|
||||||
|
|
||||||
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
|
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
|
||||||
'''
|
"""
|
||||||
callsign = bytes(bytestring[:7])
|
callsign = bytes(bytestring[:7])
|
||||||
callsign = callsign.rstrip(b'\x00')
|
callsign = callsign.rstrip(b'\x00')
|
||||||
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
|
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
|
||||||
|
@ -229,15 +264,17 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
|
||||||
callsign = callsign.encode('utf-8')
|
callsign = callsign.encode('utf-8')
|
||||||
|
|
||||||
return bytes(callsign)
|
return bytes(callsign)
|
||||||
'''
|
"""
|
||||||
decoded = decode_call(bytestring)
|
decoded = decode_call(bytestring)
|
||||||
callsign = decoded[:-1]
|
callsign = decoded[:-1]
|
||||||
ssid = ord(bytes(decoded[-1], "utf-8"))
|
ssid = ord(bytes(decoded[-1], "utf-8"))
|
||||||
return bytes(f"{callsign}-{ssid}", "utf-8")
|
return bytes(f"{callsign}-{ssid}", "utf-8")
|
||||||
|
|
||||||
def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|
||||||
|
def check_callsign(callsign: bytes, crc_to_check: bytes):
|
||||||
"""
|
"""
|
||||||
Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it
|
Function to check a crc against a callsign to calculate the
|
||||||
|
ssid by generating crc until we find the correct SSID
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
callsign: Callsign which we want to check
|
callsign: Callsign which we want to check
|
||||||
|
@ -249,18 +286,18 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# print(callsign)
|
# print(callsign)
|
||||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Checking:", callsign=callsign)
|
log.debug("[HLP] check_callsign: Checking:", callsign=callsign)
|
||||||
try:
|
try:
|
||||||
# We want the callsign without SSID
|
# We want the callsign without SSID
|
||||||
callsign = callsign.split(b'-')[0]
|
callsign = callsign.split(b"-")[0]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=e)
|
log.debug("[HLP] check_callsign: Error callsign SSID to integer:", e=err)
|
||||||
|
|
||||||
for ssid in static.SSID_LIST:
|
for ssid in static.SSID_LIST:
|
||||||
call_with_ssid = bytearray(callsign)
|
call_with_ssid = bytearray(callsign)
|
||||||
call_with_ssid.extend('-'.encode('utf-8'))
|
call_with_ssid.extend("-".encode("utf-8"))
|
||||||
call_with_ssid.extend(str(ssid).encode('utf-8'))
|
call_with_ssid.extend(str(ssid).encode("utf-8"))
|
||||||
|
|
||||||
callsign_crc = get_crc_24(call_with_ssid)
|
callsign_crc = get_crc_24(call_with_ssid)
|
||||||
|
|
||||||
|
@ -270,6 +307,7 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
||||||
|
|
||||||
return [False, ""]
|
return [False, ""]
|
||||||
|
|
||||||
|
|
||||||
def encode_grid(grid):
|
def encode_grid(grid):
|
||||||
"""
|
"""
|
||||||
@auther: DB1UJ
|
@auther: DB1UJ
|
||||||
|
@ -280,30 +318,31 @@ def encode_grid(grid):
|
||||||
"""
|
"""
|
||||||
out_code_word = 0
|
out_code_word = 0
|
||||||
|
|
||||||
grid = grid.upper() # upper case to be save
|
grid = grid.upper() # upper case to be save
|
||||||
|
|
||||||
int_first = ord(grid[0]) - 65 # -65 offset for 'A' become zero, utf8 table
|
int_first = ord(grid[0]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||||
int_sec = ord(grid[1]) - 65 # -65 offset for 'A' become zero, utf8 table
|
int_sec = ord(grid[1]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||||
|
|
||||||
int_val = (int_first * 18) + int_sec # encode for modulo devision, 2 numbers in 1
|
int_val = (int_first * 18) + int_sec # encode for modulo devision, 2 numbers in 1
|
||||||
|
|
||||||
out_code_word = (int_val & 0b111111111) # only 9 bit LSB A - R * A - R is needed
|
out_code_word = int_val & 0b111111111 # only 9 bit LSB A - R * A - R is needed
|
||||||
out_code_word <<= 9 # shift 9 bit left having space next bits, letter A-R * A-R
|
out_code_word <<= 9 # shift 9 bit left having space next bits, letter A-R * A-R
|
||||||
|
|
||||||
int_val = int(grid[2:4]) # number string to number int, highest value 99
|
int_val = int(grid[2:4]) # number string to number int, highest value 99
|
||||||
out_code_word |= (int_val & 0b1111111) # using bit OR to add new value
|
out_code_word |= int_val & 0b1111111 # using bit OR to add new value
|
||||||
out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X
|
out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X
|
||||||
|
|
||||||
int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table
|
int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||||
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
|
out_code_word |= int_val & 0b11111 # using bit OR to add new value
|
||||||
out_code_word <<= 5 # shift 5 bit left having space next bits, letter A-X
|
out_code_word <<= 5 # shift 5 bit left having space next bits, letter A-X
|
||||||
|
|
||||||
int_val = ord(grid[5]) - 65 # -65 offset for 'A' become zero, utf8 table
|
int_val = ord(grid[5]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||||
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
|
out_code_word |= int_val & 0b11111 # using bit OR to add new value
|
||||||
|
|
||||||
return out_code_word.to_bytes(length=4, byteorder='big')
|
return out_code_word.to_bytes(length=4, byteorder="big")
|
||||||
|
|
||||||
def decode_grid(b_code_word:bytes):
|
|
||||||
|
def decode_grid(b_code_word: bytes):
|
||||||
"""
|
"""
|
||||||
@auther: DB1UJ
|
@auther: DB1UJ
|
||||||
Args:
|
Args:
|
||||||
|
@ -311,7 +350,7 @@ def decode_grid(b_code_word:bytes):
|
||||||
Returns:
|
Returns:
|
||||||
grid:str: upper case maidenhead QTH locater [A-R][A-R][0-9][0-9][A-X][A-X]
|
grid:str: upper case maidenhead QTH locater [A-R][A-R][0-9][0-9][A-X][A-X]
|
||||||
"""
|
"""
|
||||||
code_word = int.from_bytes(b_code_word, byteorder='big', signed=False)
|
code_word = int.from_bytes(b_code_word, byteorder="big", signed=False)
|
||||||
|
|
||||||
grid = chr((code_word & 0b11111) + 65)
|
grid = chr((code_word & 0b11111) + 65)
|
||||||
code_word >>= 5
|
code_word >>= 5
|
||||||
|
@ -321,7 +360,7 @@ def decode_grid(b_code_word:bytes):
|
||||||
|
|
||||||
grid = str(int(code_word & 0b1111111)) + grid
|
grid = str(int(code_word & 0b1111111)) + grid
|
||||||
if (code_word & 0b1111111) < 10:
|
if (code_word & 0b1111111) < 10:
|
||||||
grid = f'0{grid}'
|
grid = f"0{grid}"
|
||||||
code_word >>= 9
|
code_word >>= 9
|
||||||
|
|
||||||
int_val = int(code_word & 0b111111111)
|
int_val = int(code_word & 0b111111111)
|
||||||
|
@ -332,6 +371,7 @@ def decode_grid(b_code_word:bytes):
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
|
||||||
def encode_call(call):
|
def encode_call(call):
|
||||||
"""
|
"""
|
||||||
@auther: DB1UJ
|
@auther: DB1UJ
|
||||||
|
@ -339,23 +379,27 @@ def encode_call(call):
|
||||||
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
|
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
6 bytes contains 6 bits/sign encoded 8 char call sign with binary SSID (only upper letters + numbers, SSID)
|
6 bytes contains 6 bits/sign encoded 8 char call sign with binary SSID
|
||||||
|
(only upper letters + numbers, SSID)
|
||||||
"""
|
"""
|
||||||
out_code_word = 0
|
out_code_word = 0
|
||||||
|
|
||||||
call = call.upper() # upper case to be save
|
call = call.upper() # upper case to be save
|
||||||
|
|
||||||
for x in call:
|
for char in call:
|
||||||
int_val = ord(x) - 48 # -48 reduce bits, begin with first number utf8 table
|
int_val = ord(char) - 48 # -48 reduce bits, begin with first number utf8 table
|
||||||
out_code_word <<= 6 # shift left 6 bit, making space for a new char
|
out_code_word <<= 6 # shift left 6 bit, making space for a new char
|
||||||
out_code_word |= (int_val & 0b111111) # bit OR adds the new char, masked with AND 0b111111
|
out_code_word |= (
|
||||||
out_code_word >>= 6 # clean last char
|
int_val & 0b111111
|
||||||
out_code_word <<= 6 # make clean space
|
) # bit OR adds the new char, masked with AND 0b111111
|
||||||
out_code_word |= (ord(call[-1]) & 0b111111) # add the SSID uncoded only 0 - 63
|
out_code_word >>= 6 # clean last char
|
||||||
|
out_code_word <<= 6 # make clean space
|
||||||
|
out_code_word |= ord(call[-1]) & 0b111111 # add the SSID uncoded only 0 - 63
|
||||||
|
|
||||||
return out_code_word.to_bytes(length=6, byteorder='big')
|
return out_code_word.to_bytes(length=6, byteorder="big")
|
||||||
|
|
||||||
def decode_call(b_code_word:bytes):
|
|
||||||
|
def decode_call(b_code_word: bytes):
|
||||||
"""
|
"""
|
||||||
@auther: DB1UJ
|
@auther: DB1UJ
|
||||||
Args:
|
Args:
|
||||||
|
@ -364,14 +408,14 @@ def decode_call(b_code_word:bytes):
|
||||||
Returns:
|
Returns:
|
||||||
call:str: upper case ham radio call sign [A-Z,0-9] + binary SSID
|
call:str: upper case ham radio call sign [A-Z,0-9] + binary SSID
|
||||||
"""
|
"""
|
||||||
code_word = int.from_bytes(b_code_word, byteorder='big', signed=False)
|
code_word = int.from_bytes(b_code_word, byteorder="big", signed=False)
|
||||||
ssid = chr(code_word & 0b111111) # save the uncoded binary SSID
|
ssid = chr(code_word & 0b111111) # save the uncoded binary SSID
|
||||||
|
|
||||||
call = str()
|
call = str()
|
||||||
while code_word != 0:
|
while code_word != 0:
|
||||||
call = chr((code_word & 0b111111)+48) + call
|
call = chr((code_word & 0b111111) + 48) + call
|
||||||
code_word >>= 6
|
code_word >>= 6
|
||||||
|
|
||||||
call = call[:-1] + ssid # remove the last char from call and replace with SSID
|
call = call[:-1] + ssid # remove the last char from call and replace with SSID
|
||||||
|
|
||||||
return call
|
return call
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
import logging.config
|
||||||
|
|
||||||
|
import structlog
|
||||||
|
|
||||||
|
|
||||||
# https://www.structlog.org/en/stable/standard-library.html
|
# https://www.structlog.org/en/stable/standard-library.html
|
||||||
def setup_logging(filename):
|
def setup_logging(filename):
|
||||||
"""
|
"""
|
||||||
|
@ -8,8 +13,6 @@ def setup_logging(filename):
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import logging.config
|
|
||||||
import structlog
|
|
||||||
|
|
||||||
timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S")
|
timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S")
|
||||||
pre_chain = [
|
pre_chain = [
|
||||||
|
@ -19,7 +22,8 @@ def setup_logging(filename):
|
||||||
timestamper,
|
timestamper,
|
||||||
]
|
]
|
||||||
|
|
||||||
logging.config.dictConfig({
|
logging.config.dictConfig(
|
||||||
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
|
@ -43,7 +47,7 @@ def setup_logging(filename):
|
||||||
"file": {
|
"file": {
|
||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
"class": "logging.handlers.WatchedFileHandler",
|
"class": "logging.handlers.WatchedFileHandler",
|
||||||
"filename": filename + '.log',
|
"filename": f"{filename}.log",
|
||||||
"formatter": "plain",
|
"formatter": "plain",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -53,8 +57,9 @@ def setup_logging(filename):
|
||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
"propagate": True,
|
"propagate": True,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
})
|
}
|
||||||
|
)
|
||||||
structlog.configure(
|
structlog.configure(
|
||||||
processors=[
|
processors=[
|
||||||
structlog.stdlib.add_log_level,
|
structlog.stdlib.add_log_level,
|
||||||
|
|
253
tnc/main.py
253
tnc/main.py
|
@ -16,13 +16,14 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import structlog
|
|
||||||
|
|
||||||
import data_handler
|
import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import log_handler
|
import log_handler
|
||||||
import modem
|
import modem
|
||||||
import static
|
import static
|
||||||
|
import structlog
|
||||||
|
|
||||||
|
log = structlog.get_logger(__file__)
|
||||||
|
|
||||||
# signal handler for closing aplication
|
# signal handler for closing aplication
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
|
@ -35,56 +36,208 @@ def signal_handler(sig, frame):
|
||||||
Returns: system exit
|
Returns: system exit
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print('Closing TNC...')
|
print("Closing TNC...")
|
||||||
sock.CLOSE_SIGNAL = True
|
sock.CLOSE_SIGNAL = True
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
# we need to run this on windows for multiprocessing support
|
# we need to run this on windows for multiprocessing support
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support()
|
||||||
# --------------------------------------------GET PARAMETER INPUTS
|
# --------------------------------------------GET PARAMETER INPUTS
|
||||||
PARSER = argparse.ArgumentParser(description='FreeDATA TNC')
|
PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
|
||||||
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str)
|
PARSER.add_argument(
|
||||||
PARSER.add_argument('--ssid', dest="ssid_list", nargs='*', default=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], help="SSID list we are responding to", type=str)
|
"--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str
|
||||||
PARSER.add_argument('--mygrid', dest="mygrid", default="JN12AA", help="My gridsquare", type=str)
|
)
|
||||||
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int)
|
PARSER.add_argument(
|
||||||
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
"--ssid",
|
||||||
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int)
|
dest="ssid_list",
|
||||||
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
|
nargs="*",
|
||||||
PARSER.add_argument('--devicename', dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str)
|
default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||||
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int)
|
help="SSID list we are responding to",
|
||||||
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", choices=['USB', 'RIG', 'RTS', 'DTR', 'CM108', 'MICDATA', 'PARALLEL', 'DTR-H', 'DTR-L', 'NONE'], default='USB', help="PTT Type", type=str)
|
type=str,
|
||||||
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
)
|
||||||
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int)
|
PARSER.add_argument(
|
||||||
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int)
|
"--mygrid", dest="mygrid", default="JN12AA", help="My gridsquare", type=str
|
||||||
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
|
)
|
||||||
PARSER.add_argument('--radiocontrol', dest="hamlib_radiocontrol", choices=['disabled', 'direct', 'rigctl', 'rigctld'], default="disabled", help="Set how you want to control your radio")
|
PARSER.add_argument(
|
||||||
PARSER.add_argument('--rigctld_port', dest="rigctld_port", default=4532, type=int, help="Set rigctld port")
|
"--rx",
|
||||||
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="localhost", help="Set rigctld ip")
|
dest="audio_input_device",
|
||||||
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network")
|
default=0,
|
||||||
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network")
|
help="listening sound card",
|
||||||
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )")
|
type=int,
|
||||||
PARSER.add_argument('--fsk', dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ")
|
)
|
||||||
PARSER.add_argument('--qrv', dest="enable_respond_to_cq", action="store_true", help="Enable sending a QRV frame if CQ received")
|
PARSER.add_argument(
|
||||||
PARSER.add_argument('--tuning_range_fmin', dest="tuning_range_fmin", choices=[-50.0, -100.0, -150.0, -200.0, -250.0], default=-50.0, help="Tuning range fmin", type=float)
|
"--tx",
|
||||||
PARSER.add_argument('--tuning_range_fmax', dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float)
|
dest="audio_output_device",
|
||||||
PARSER.add_argument('--tx-audio-level', dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int)
|
default=0,
|
||||||
|
help="transmitting sound card",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--port",
|
||||||
|
dest="socket_port",
|
||||||
|
default=3000,
|
||||||
|
help="Socket port in the range of 1024-65536",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--deviceport",
|
||||||
|
dest="hamlib_device_port",
|
||||||
|
default="/dev/ttyUSB0",
|
||||||
|
help="Hamlib device port",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--devicename",
|
||||||
|
dest="hamlib_device_name",
|
||||||
|
default="2028",
|
||||||
|
help="Hamlib device name",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--serialspeed",
|
||||||
|
dest="hamlib_serialspeed",
|
||||||
|
choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200],
|
||||||
|
default=9600,
|
||||||
|
help="Serialspeed",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--pttprotocol",
|
||||||
|
dest="hamlib_ptt_type",
|
||||||
|
choices=[
|
||||||
|
"USB",
|
||||||
|
"RIG",
|
||||||
|
"RTS",
|
||||||
|
"DTR",
|
||||||
|
"CM108",
|
||||||
|
"MICDATA",
|
||||||
|
"PARALLEL",
|
||||||
|
"DTR-H",
|
||||||
|
"DTR-L",
|
||||||
|
"NONE",
|
||||||
|
],
|
||||||
|
default="USB",
|
||||||
|
help="PTT Type",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--pttport",
|
||||||
|
dest="hamlib_ptt_port",
|
||||||
|
default="/dev/ttyUSB0",
|
||||||
|
help="PTT Port",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--data_bits",
|
||||||
|
dest="hamlib_data_bits",
|
||||||
|
choices=[7, 8],
|
||||||
|
default=8,
|
||||||
|
help="Hamlib data bits",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--stop_bits",
|
||||||
|
dest="hamlib_stop_bits",
|
||||||
|
choices=[1, 2],
|
||||||
|
default=1,
|
||||||
|
help="Hamlib stop bits",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--handshake",
|
||||||
|
dest="hamlib_handshake",
|
||||||
|
default="None",
|
||||||
|
help="Hamlib handshake",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--radiocontrol",
|
||||||
|
dest="hamlib_radiocontrol",
|
||||||
|
choices=["disabled", "direct", "rigctl", "rigctld"],
|
||||||
|
default="disabled",
|
||||||
|
help="Set how you want to control your radio",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--rigctld_port",
|
||||||
|
dest="rigctld_port",
|
||||||
|
default=4532,
|
||||||
|
type=int,
|
||||||
|
help="Set rigctld port",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--rigctld_ip", dest="rigctld_ip", default="localhost", help="Set rigctld ip"
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--scatter",
|
||||||
|
dest="send_scatter",
|
||||||
|
action="store_true",
|
||||||
|
help="Send scatter information via network",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--fft",
|
||||||
|
dest="send_fft",
|
||||||
|
action="store_true",
|
||||||
|
help="Send fft information via network",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--500hz",
|
||||||
|
dest="low_bandwith_mode",
|
||||||
|
action="store_true",
|
||||||
|
help="Enable low bandwith mode ( 500 Hz only )",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--fsk",
|
||||||
|
dest="enable_fsk",
|
||||||
|
action="store_true",
|
||||||
|
help="Enable FSK mode for ping, beacon and CQ",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--qrv",
|
||||||
|
dest="enable_respond_to_cq",
|
||||||
|
action="store_true",
|
||||||
|
help="Enable sending a QRV frame if CQ received",
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--tuning_range_fmin",
|
||||||
|
dest="tuning_range_fmin",
|
||||||
|
choices=[-50.0, -100.0, -150.0, -200.0, -250.0],
|
||||||
|
default=-50.0,
|
||||||
|
help="Tuning range fmin",
|
||||||
|
type=float,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--tuning_range_fmax",
|
||||||
|
dest="tuning_range_fmax",
|
||||||
|
choices=[50.0, 100.0, 150.0, 200.0, 250.0],
|
||||||
|
default=50.0,
|
||||||
|
help="Tuning range fmax",
|
||||||
|
type=float,
|
||||||
|
)
|
||||||
|
PARSER.add_argument(
|
||||||
|
"--tx-audio-level",
|
||||||
|
dest="tx_audio_level",
|
||||||
|
default=50,
|
||||||
|
help="Set the tx audio level at an early stage",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
|
||||||
ARGS = PARSER.parse_args()
|
ARGS = PARSER.parse_args()
|
||||||
|
|
||||||
# additional step for beeing sure our callsign is correctly
|
# additional step for beeing sure our callsign is correctly
|
||||||
# in case we are not getting a station ssid
|
# in case we are not getting a station ssid
|
||||||
# then we are forcing a station ssid = 0
|
# then we are forcing a station ssid = 0
|
||||||
mycallsign = bytes(ARGS.mycall.upper(), 'utf-8')
|
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
|
||||||
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
||||||
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
||||||
|
|
||||||
static.SSID_LIST = ARGS.ssid_list
|
static.SSID_LIST = ARGS.ssid_list
|
||||||
|
|
||||||
static.MYGRID = bytes(ARGS.mygrid, 'utf-8')
|
static.MYGRID = bytes(ARGS.mygrid, "utf-8")
|
||||||
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
||||||
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
||||||
static.PORT = ARGS.socket_port
|
static.PORT = ARGS.socket_port
|
||||||
|
@ -113,22 +266,30 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# config logging
|
# config logging
|
||||||
try:
|
try:
|
||||||
if sys.platform == 'linux':
|
if sys.platform == "linux":
|
||||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc'
|
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == "darwin":
|
||||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc'
|
logging_path = (
|
||||||
|
os.getenv("HOME")
|
||||||
|
+ "/Library/"
|
||||||
|
+ "Application Support/"
|
||||||
|
+ "FreeDATA/"
|
||||||
|
+ "tnc"
|
||||||
|
)
|
||||||
|
|
||||||
if sys.platform in ['win32', 'win64']:
|
if sys.platform in ["win32", "win64"]:
|
||||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc'
|
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
|
||||||
|
|
||||||
if not os.path.exists(logging_path):
|
if not os.path.exists(logging_path):
|
||||||
os.makedirs(logging_path)
|
os.makedirs(logging_path)
|
||||||
log_handler.setup_logging(logging_path)
|
log_handler.setup_logging(logging_path)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e)
|
log.error("[DMN] logger init error", exception=err)
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION)
|
log.info(
|
||||||
|
"[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION
|
||||||
|
)
|
||||||
|
|
||||||
# start data handler
|
# start data handler
|
||||||
data_handler.DATA()
|
data_handler.DATA()
|
||||||
|
@ -138,17 +299,19 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# --------------------------------------------START CMD SERVER
|
# --------------------------------------------START CMD SERVER
|
||||||
try:
|
try:
|
||||||
structlog.get_logger("structlog").info("[TNC] Starting TCP/IP socket", port=static.PORT)
|
log.info("[TNC] Starting TCP/IP socket", port=static.PORT)
|
||||||
# https://stackoverflow.com/a/16641793
|
# https://stackoverflow.com/a/16641793
|
||||||
socketserver.TCPServer.allow_reuse_address = True
|
socketserver.TCPServer.allow_reuse_address = True
|
||||||
cmdserver = sock.ThreadedTCPServer((static.HOST, static.PORT), sock.ThreadedTCPRequestHandler)
|
cmdserver = sock.ThreadedTCPServer(
|
||||||
|
(static.HOST, static.PORT), sock.ThreadedTCPRequestHandler
|
||||||
|
)
|
||||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||||
|
|
||||||
server_thread.daemon = True
|
server_thread.daemon = True
|
||||||
server_thread.start()
|
server_thread.start()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e)
|
log.error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
while 1:
|
while 1:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
67
tnc/modem.py
67
tnc/modem.py
|
@ -16,7 +16,6 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import codec2
|
import codec2
|
||||||
import data_handler
|
import data_handler
|
||||||
|
@ -45,6 +44,8 @@ RECEIVE_FSK_LDPC_1 = False
|
||||||
class RF:
|
class RF:
|
||||||
"""Class to encapsulate interactions between the audio device and codec2"""
|
"""Class to encapsulate interactions between the audio device and codec2"""
|
||||||
|
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|
||||||
self.sampler_avg = 0
|
self.sampler_avg = 0
|
||||||
|
@ -188,7 +189,7 @@ class RF:
|
||||||
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||||
self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0)
|
self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0)
|
||||||
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
|
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
|
||||||
# structlog.get_logger("structlog").debug("[MDM] RF: ",datac0_nin=self.datac0_nin)
|
# self.log.debug("[MDM] RF: ",datac0_nin=self.datac0_nin)
|
||||||
|
|
||||||
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
||||||
if not TESTMODE:
|
if not TESTMODE:
|
||||||
|
@ -202,24 +203,24 @@ class RF:
|
||||||
blocksize=4800,
|
blocksize=4800,
|
||||||
)
|
)
|
||||||
atexit.register(self.stream.stop)
|
atexit.register(self.stream.stop)
|
||||||
structlog.get_logger("structlog").info(
|
self.log.info(
|
||||||
"[MDM] init: opened audio devices"
|
"[MDM] init: opened audio devices"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error(
|
self.log.error(
|
||||||
"[MDM] init: can't open audio device. Exit", e=e
|
"[MDM] init: can't open audio device. Exit", e=err
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] init: starting pyaudio callback"
|
"[MDM] init: starting pyaudio callback"
|
||||||
)
|
)
|
||||||
# self.audio_stream.start_stream()
|
# self.audio_stream.start_stream()
|
||||||
self.stream.start()
|
self.stream.start()
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error(
|
self.log.error(
|
||||||
"[MDM] init: starting pyaudio callback failed", e=e
|
"[MDM] init: starting pyaudio callback failed", e=err
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
@ -235,9 +236,9 @@ class RF:
|
||||||
try:
|
try:
|
||||||
os.mkfifo(RXCHANNEL)
|
os.mkfifo(RXCHANNEL)
|
||||||
os.mkfifo(TXCHANNEL)
|
os.mkfifo(TXCHANNEL)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error(
|
self.log.error(
|
||||||
f"[MDM] init:mkfifo: Exception: {e}"
|
f"[MDM] init:mkfifo: Exception: {err}"
|
||||||
)
|
)
|
||||||
|
|
||||||
mkfifo_write_callback_thread = threading.Thread(
|
mkfifo_write_callback_thread = threading.Thread(
|
||||||
|
@ -247,7 +248,7 @@ class RF:
|
||||||
)
|
)
|
||||||
mkfifo_write_callback_thread.start()
|
mkfifo_write_callback_thread.start()
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] Starting mkfifo_read_callback"
|
"[MDM] Starting mkfifo_read_callback"
|
||||||
)
|
)
|
||||||
mkfifo_read_callback_thread = threading.Thread(
|
mkfifo_read_callback_thread = threading.Thread(
|
||||||
|
@ -320,7 +321,7 @@ class RF:
|
||||||
)
|
)
|
||||||
hamlib_thread.start()
|
hamlib_thread.start()
|
||||||
|
|
||||||
# structlog.get_logger("structlog").debug("[MDM] Starting worker_receive")
|
# self.log.debug("[MDM] Starting worker_receive")
|
||||||
worker_received = threading.Thread(
|
worker_received = threading.Thread(
|
||||||
target=self.worker_received, name="WORKER_THREAD", daemon=True
|
target=self.worker_received, name="WORKER_THREAD", daemon=True
|
||||||
)
|
)
|
||||||
|
@ -397,7 +398,7 @@ class RF:
|
||||||
status:
|
status:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# structlog.get_logger("structlog").debug("[MDM] callback")
|
# self.log.debug("[MDM] callback")
|
||||||
x = np.frombuffer(data_in48k, dtype=np.int16)
|
x = np.frombuffer(data_in48k, dtype=np.int16)
|
||||||
x = self.resampler.resample48_to_8(x)
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
|
||||||
|
@ -429,8 +430,10 @@ class RF:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
outdata[:] = data_out48k[:frames]
|
outdata[:] = data_out48k[:frames]
|
||||||
except IndexError as e:
|
except IndexError as err:
|
||||||
structlog.get_logger("structlog").debug(f"[MDM] callback: IndexError: {e}")
|
self.log.debug(
|
||||||
|
f"[MDM] callback: IndexError: {err}"
|
||||||
|
)
|
||||||
|
|
||||||
# return (data_out48k, audio.pyaudio.paContinue)
|
# return (data_out48k, audio.pyaudio.paContinue)
|
||||||
|
|
||||||
|
@ -447,7 +450,7 @@ class RF:
|
||||||
frames:
|
frames:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
structlog.get_logger("structlog").debug("[MDM] transmit", mode=mode)
|
self.log.debug("[MDM] transmit", mode=mode)
|
||||||
static.TRANSMITTING = True
|
static.TRANSMITTING = True
|
||||||
# Toggle ptt early to save some time and send ptt state via socket
|
# Toggle ptt early to save some time and send ptt state via socket
|
||||||
static.PTT_STATE = self.hamlib.set_ptt(True)
|
static.PTT_STATE = self.hamlib.set_ptt(True)
|
||||||
|
@ -487,7 +490,7 @@ class RF:
|
||||||
mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
|
mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
|
||||||
txbuffer = bytes(mod_out_silence)
|
txbuffer = bytes(mod_out_silence)
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame
|
"[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -625,7 +628,7 @@ class RF:
|
||||||
audiobuffer.pop(nin)
|
audiobuffer.pop(nin)
|
||||||
nin = codec2.api.freedv_nin(freedv)
|
nin = codec2.api.freedv_nin(freedv)
|
||||||
if nbytes == bytes_per_frame:
|
if nbytes == bytes_per_frame:
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] [demod_audio] Pushing received data to received_queue"
|
"[MDM] [demod_audio] Pushing received data to received_queue"
|
||||||
)
|
)
|
||||||
self.modem_received_queue.put([bytes_out, freedv, bytes_per_frame])
|
self.modem_received_queue.put([bytes_out, freedv, bytes_per_frame])
|
||||||
|
@ -688,7 +691,7 @@ class RF:
|
||||||
while True:
|
while True:
|
||||||
data = self.modem_transmit_queue.get()
|
data = self.modem_transmit_queue.get()
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] worker_transmit", mode=data[0]
|
"[MDM] worker_transmit", mode=data[0]
|
||||||
)
|
)
|
||||||
self.transmit(
|
self.transmit(
|
||||||
|
@ -700,7 +703,7 @@ class RF:
|
||||||
"""Worker for FIFO queue for processing received frames"""
|
"""Worker for FIFO queue for processing received frames"""
|
||||||
while True:
|
while True:
|
||||||
data = self.modem_received_queue.get()
|
data = self.modem_received_queue.get()
|
||||||
structlog.get_logger("structlog").debug(
|
self.log.debug(
|
||||||
"[MDM] worker_received: received data!"
|
"[MDM] worker_received: received data!"
|
||||||
)
|
)
|
||||||
# data[0] = bytes_out
|
# data[0] = bytes_out
|
||||||
|
@ -783,15 +786,15 @@ class RF:
|
||||||
modem_stats_sync = modem_stats_sync.value
|
modem_stats_sync = modem_stats_sync.value
|
||||||
|
|
||||||
snr = round(modem_stats_snr, 1)
|
snr = round(modem_stats_snr, 1)
|
||||||
structlog.get_logger("structlog").info("[MDM] calculate_snr: ", snr=snr)
|
self.log.info("[MDM] calculate_snr: ", snr=snr)
|
||||||
# static.SNR = np.clip(snr, 0, 255) # limit to max value of 255
|
# static.SNR = np.clip(snr, 0, 255) # limit to max value of 255
|
||||||
static.SNR = np.clip(
|
static.SNR = np.clip(
|
||||||
snr, -128, 128
|
snr, -128, 128
|
||||||
) # limit to max value of -128/128 as a possible fix of #188
|
) # limit to max value of -128/128 as a possible fix of #188
|
||||||
return static.SNR
|
return static.SNR
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error(
|
self.log.error(
|
||||||
f"[MDM] calculate_snr: Exception: {e}"
|
f"[MDM] calculate_snr: Exception: {err}"
|
||||||
)
|
)
|
||||||
static.SNR = 0
|
static.SNR = 0
|
||||||
return static.SNR
|
return static.SNR
|
||||||
|
@ -813,7 +816,7 @@ class RF:
|
||||||
def calculate_fft(self) -> None:
|
def calculate_fft(self) -> None:
|
||||||
"""
|
"""
|
||||||
Calculate an average signal strength of the channel to assess
|
Calculate an average signal strength of the channel to assess
|
||||||
whether the channel is 'busy.'
|
whether the channel is "busy."
|
||||||
"""
|
"""
|
||||||
# Initialize channel_busy_delay counter
|
# Initialize channel_busy_delay counter
|
||||||
channel_busy_delay = 0
|
channel_busy_delay = 0
|
||||||
|
@ -870,11 +873,11 @@ class RF:
|
||||||
dfftlist = dfft.tolist()
|
dfftlist = dfft.tolist()
|
||||||
|
|
||||||
static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
|
static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error(
|
self.log.error(
|
||||||
f"[MDM] calculate_fft: Exception: {e}"
|
f"[MDM] calculate_fft: Exception: {err}"
|
||||||
)
|
)
|
||||||
structlog.get_logger("structlog").debug("[MDM] Setting fft=0")
|
self.log.debug("[MDM] Setting fft=0")
|
||||||
# else 0
|
# else 0
|
||||||
static.FFT = [0]
|
static.FFT = [0]
|
||||||
|
|
||||||
|
|
180
tnc/rig.py
180
tnc/rig.py
|
@ -1,11 +1,12 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import structlog
|
|
||||||
import atexit
|
import atexit
|
||||||
import subprocess
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import structlog
|
||||||
|
|
||||||
|
mainlog = structlog.get_logger(__file__)
|
||||||
|
|
||||||
# set global hamlib version
|
# set global hamlib version
|
||||||
hamlib_version = 0
|
hamlib_version = 0
|
||||||
|
@ -20,26 +21,26 @@ else:
|
||||||
# try importing hamlib
|
# try importing hamlib
|
||||||
try:
|
try:
|
||||||
# get python version
|
# get python version
|
||||||
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
||||||
|
|
||||||
# installation path for Ubuntu 20.04 LTS python modules
|
# installation path for Ubuntu 20.04 LTS python modules
|
||||||
#sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
# sys.path.append(f"/usr/local/lib/python{python_version}/site-packages")
|
||||||
|
|
||||||
# installation path for Ubuntu 20.10 +
|
# installation path for Ubuntu 20.10 +
|
||||||
sys.path.append('/usr/local/lib/')
|
sys.path.append("/usr/local/lib/")
|
||||||
|
|
||||||
# installation path for Suse
|
# installation path for Suse
|
||||||
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages')
|
sys.path.append(f"/usr/local/lib64/python{python_version}/site-packages")
|
||||||
|
|
||||||
# everything else... not nice, but an attempt to see how its running within app bundle
|
# everything else... not nice, but an attempt to see how its running within app bundle
|
||||||
# this is not needed as python will be shipped with app bundle
|
# this is not needed as python will be shipped with app bundle
|
||||||
sys.path.append('/usr/local/lib/python3.6/site-packages')
|
sys.path.append("/usr/local/lib/python3.6/site-packages")
|
||||||
sys.path.append('/usr/local/lib/python3.7/site-packages')
|
sys.path.append("/usr/local/lib/python3.7/site-packages")
|
||||||
sys.path.append('/usr/local/lib/python3.8/site-packages')
|
sys.path.append("/usr/local/lib/python3.8/site-packages")
|
||||||
sys.path.append('/usr/local/lib/python3.9/site-packages')
|
sys.path.append("/usr/local/lib/python3.9/site-packages")
|
||||||
sys.path.append('/usr/local/lib/python3.10/site-packages')
|
sys.path.append("/usr/local/lib/python3.10/site-packages")
|
||||||
|
|
||||||
sys.path.append('lib/hamlib/linux/python3.8/site-packages')
|
sys.path.append("lib/hamlib/linux/python3.8/site-packages")
|
||||||
import Hamlib
|
import Hamlib
|
||||||
|
|
||||||
# https://stackoverflow.com/a/4703409
|
# https://stackoverflow.com/a/4703409
|
||||||
|
@ -48,43 +49,68 @@ try:
|
||||||
|
|
||||||
min_hamlib_version = 4.1
|
min_hamlib_version = 4.1
|
||||||
if hamlib_version > min_hamlib_version:
|
if hamlib_version > min_hamlib_version:
|
||||||
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version)
|
mainlog.info("[RIG] Hamlib found", version=hamlib_version)
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
mainlog.warning(
|
||||||
except Exception as e:
|
"[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version
|
||||||
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e)
|
)
|
||||||
|
except Exception as err:
|
||||||
|
mainlog.warning("[RIG] Python Hamlib binding not found", error=err)
|
||||||
try:
|
try:
|
||||||
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl")
|
mainlog.warning("[RIG] Trying to open rigctl")
|
||||||
rigctl = subprocess.Popen("rigctl -V",shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
rigctl = subprocess.Popen(
|
||||||
|
"rigctl -V",
|
||||||
|
shell=True,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
hamlib_version = rigctl.stdout.readline()
|
hamlib_version = rigctl.stdout.readline()
|
||||||
hamlib_version = hamlib_version.split(' ')
|
hamlib_version = hamlib_version.split(" ")
|
||||||
|
|
||||||
if hamlib_version[1] == 'Hamlib':
|
if hamlib_version[1] == "Hamlib":
|
||||||
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
|
mainlog.warning(
|
||||||
|
"[RIG] Rigctl found! Please try using this", version=hamlib_version[2]
|
||||||
|
)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
raise Exception
|
raise Exception
|
||||||
except Exception as e:
|
except Exception as err1:
|
||||||
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=e)
|
mainlog.critical("[RIG] HAMLIB NOT INSTALLED", error=err1)
|
||||||
hamlib_version = 0
|
hamlib_version = 0
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
class radio:
|
class radio:
|
||||||
""" """
|
""" """
|
||||||
def __init__(self):
|
|
||||||
self.devicename = ''
|
|
||||||
self.devicenumber = ''
|
|
||||||
self.deviceport = ''
|
|
||||||
self.serialspeed = ''
|
|
||||||
self.hamlib_ptt_type = ''
|
|
||||||
self.my_rig = ''
|
|
||||||
self.pttport = ''
|
|
||||||
self.data_bits = ''
|
|
||||||
self.stop_bits = ''
|
|
||||||
self.handshake = ''
|
|
||||||
|
|
||||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip):
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.devicename = ""
|
||||||
|
self.devicenumber = ""
|
||||||
|
self.deviceport = ""
|
||||||
|
self.serialspeed = ""
|
||||||
|
self.hamlib_ptt_type = ""
|
||||||
|
self.my_rig = ""
|
||||||
|
self.pttport = ""
|
||||||
|
self.data_bits = ""
|
||||||
|
self.stop_bits = ""
|
||||||
|
self.handshake = ""
|
||||||
|
|
||||||
|
def open_rig(
|
||||||
|
self,
|
||||||
|
devicename,
|
||||||
|
deviceport,
|
||||||
|
hamlib_ptt_type,
|
||||||
|
serialspeed,
|
||||||
|
pttport,
|
||||||
|
data_bits,
|
||||||
|
stop_bits,
|
||||||
|
handshake,
|
||||||
|
rigctld_port,
|
||||||
|
rigctld_ip,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -99,12 +125,11 @@ class radio:
|
||||||
rigctld_port:
|
rigctld_port:
|
||||||
rigctld_ip:
|
rigctld_ip:
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.devicename = devicename
|
self.devicename = devicename
|
||||||
self.deviceport = str(deviceport)
|
self.deviceport = str(deviceport)
|
||||||
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
# we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||||
|
self.serialspeed = str(serialspeed)
|
||||||
self.hamlib_ptt_type = str(hamlib_ptt_type)
|
self.hamlib_ptt_type = str(hamlib_ptt_type)
|
||||||
self.pttport = str(pttport)
|
self.pttport = str(pttport)
|
||||||
self.data_bits = str(data_bits)
|
self.data_bits = str(data_bits)
|
||||||
|
@ -118,8 +143,8 @@ class radio:
|
||||||
# get devicenumber by looking for deviceobject in Hamlib module
|
# get devicenumber by looking for deviceobject in Hamlib module
|
||||||
try:
|
try:
|
||||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||||
except:
|
except Exception:
|
||||||
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
|
self.log.error("[RIG] Hamlib: rig not supported...")
|
||||||
self.devicenumber = 0
|
self.devicenumber = 0
|
||||||
|
|
||||||
self.my_rig = Hamlib.Rig(self.devicenumber)
|
self.my_rig = Hamlib.Rig(self.devicenumber)
|
||||||
|
@ -131,73 +156,84 @@ class radio:
|
||||||
self.my_rig.set_conf("data_bits", self.data_bits)
|
self.my_rig.set_conf("data_bits", self.data_bits)
|
||||||
self.my_rig.set_conf("ptt_pathname", self.pttport)
|
self.my_rig.set_conf("ptt_pathname", self.pttport)
|
||||||
|
|
||||||
if self.hamlib_ptt_type == 'RIG':
|
if self.hamlib_ptt_type == "RIG":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
||||||
self.my_rig.set_conf("ptt_type", 'RIG')
|
self.my_rig.set_conf("ptt_type", "RIG")
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'USB':
|
elif self.hamlib_ptt_type == "USB":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
|
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
|
||||||
self.my_rig.set_conf("ptt_type", 'USB')
|
self.my_rig.set_conf("ptt_type", "USB")
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'DTR-H':
|
elif self.hamlib_ptt_type == "DTR-H":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||||
self.my_rig.set_conf("dtr_state", "HIGH")
|
self.my_rig.set_conf("dtr_state", "HIGH")
|
||||||
self.my_rig.set_conf("ptt_type", "DTR")
|
self.my_rig.set_conf("ptt_type", "DTR")
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'DTR-L':
|
elif self.hamlib_ptt_type == "DTR-L":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||||
self.my_rig.set_conf("dtr_state", "LOW")
|
self.my_rig.set_conf("dtr_state", "LOW")
|
||||||
self.my_rig.set_conf("ptt_type", "DTR")
|
self.my_rig.set_conf("ptt_type", "DTR")
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'RTS':
|
elif self.hamlib_ptt_type == "RTS":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
||||||
self.my_rig.set_conf("dtr_state", "OFF")
|
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 self.hamlib_ptt_type == 'PARALLEL':
|
elif self.hamlib_ptt_type == "PARALLEL":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'MICDATA':
|
elif self.hamlib_ptt_type == "MICDATA":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'CM108':
|
elif self.hamlib_ptt_type == "CM108":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
||||||
|
|
||||||
elif self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
elif self.hamlib_ptt_type == "RIG_PTT_NONE":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||||
|
|
||||||
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
else: # self.hamlib_ptt_type == "RIG_PTT_NONE":
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname"))
|
self.log.info(
|
||||||
|
"[RIG] Opening...",
|
||||||
|
device=self.devicenumber,
|
||||||
|
path=self.my_rig.get_conf("rig_pathname"),
|
||||||
|
serial_speed=self.my_rig.get_conf("serial_speed"),
|
||||||
|
serial_handshake=self.my_rig.get_conf("serial_handshake"),
|
||||||
|
stop_bits=self.my_rig.get_conf("stop_bits"),
|
||||||
|
data_bits=self.my_rig.get_conf("data_bits"),
|
||||||
|
ptt_pathname=self.my_rig.get_conf("ptt_pathname"),
|
||||||
|
)
|
||||||
|
|
||||||
self.my_rig.open()
|
self.my_rig.open()
|
||||||
atexit.register(self.my_rig.close)
|
atexit.register(self.my_rig.close)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# lets determine the error message when opening rig
|
# lets determine the error message when opening rig
|
||||||
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
|
error = str(Hamlib.rigerror(self.my_rig.error_status)).splitlines()
|
||||||
error = error[1].split('err=')
|
error = error[1].split("err=")
|
||||||
error = error[1]
|
error = error[1]
|
||||||
|
|
||||||
if error == 'Permission denied':
|
if error == "Permission denied":
|
||||||
structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error)
|
self.log.error("[RIG] Hamlib has no permissions", e=error)
|
||||||
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions'
|
help_url = "https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions"
|
||||||
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url)
|
self.log.error("[RIG] HELP:", check=help_url)
|
||||||
except:
|
except Exception:
|
||||||
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS')
|
self.log.info("[RIG] Hamlib device opened", status="SUCCESS")
|
||||||
|
|
||||||
# set ptt to false if ptt is stuck for some reason
|
# set ptt to false if ptt is stuck for some reason
|
||||||
self.set_ptt(False)
|
self.set_ptt(False)
|
||||||
|
|
||||||
# set rig mode to USB
|
# set rig mode to USB
|
||||||
# temporarly outcommented because of possible problems.
|
# temporarly outcommented because of possible problems.
|
||||||
#self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
# self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
||||||
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
|
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err2:
|
||||||
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0])
|
mainlog.error(
|
||||||
|
"[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0]
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_frequency(self):
|
def get_frequency(self):
|
||||||
|
@ -206,16 +242,16 @@ class radio:
|
||||||
|
|
||||||
def get_mode(self):
|
def get_mode(self):
|
||||||
""" """
|
""" """
|
||||||
(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
(hamlib_mode, bandwidth) = self.my_rig.get_mode()
|
||||||
return Hamlib.rig_strrmode(hamlib_mode)
|
return Hamlib.rig_strrmode(hamlib_mode)
|
||||||
|
|
||||||
def get_bandwith(self):
|
def get_bandwith(self):
|
||||||
""" """
|
""" """
|
||||||
(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
(hamlib_mode, bandwidth) = self.my_rig.get_mode()
|
||||||
return bandwith
|
return bandwidth
|
||||||
|
|
||||||
# not needed yet beacuse of some possible problems
|
# not needed yet beacuse of some possible problems
|
||||||
#def set_mode(self, mode):
|
# def set_mode(self, mode):
|
||||||
# return 0
|
# return 0
|
||||||
|
|
||||||
def get_ptt(self):
|
def get_ptt(self):
|
||||||
|
|
121
tnc/rigctl.py
121
tnc/rigctl.py
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# Intially created by Franco Spinelli, IW2DHW, 01/2022
|
# Intially created by Franco Spinelli, IW2DHW, 01/2022
|
||||||
# Updated by DJ2LS
|
# Updated by DJ2LS
|
||||||
#
|
#
|
||||||
|
@ -22,19 +21,35 @@ hamlib_version = 0
|
||||||
|
|
||||||
class radio:
|
class radio:
|
||||||
""" """
|
""" """
|
||||||
def __init__(self):
|
|
||||||
self.devicename = ''
|
|
||||||
self.devicenumber = ''
|
|
||||||
self.deviceport = ''
|
|
||||||
self.serialspeed = ''
|
|
||||||
self.hamlib_ptt_type = ''
|
|
||||||
self.my_rig = ''
|
|
||||||
self.pttport = ''
|
|
||||||
self.data_bits = ''
|
|
||||||
self.stop_bits = ''
|
|
||||||
self.handshake = ''
|
|
||||||
|
|
||||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.devicename = ""
|
||||||
|
self.devicenumber = ""
|
||||||
|
self.deviceport = ""
|
||||||
|
self.serialspeed = ""
|
||||||
|
self.hamlib_ptt_type = ""
|
||||||
|
self.my_rig = ""
|
||||||
|
self.pttport = ""
|
||||||
|
self.data_bits = ""
|
||||||
|
self.stop_bits = ""
|
||||||
|
self.handshake = ""
|
||||||
|
self.cmd = ""
|
||||||
|
|
||||||
|
def open_rig(
|
||||||
|
self,
|
||||||
|
devicename,
|
||||||
|
deviceport,
|
||||||
|
hamlib_ptt_type,
|
||||||
|
serialspeed,
|
||||||
|
pttport,
|
||||||
|
data_bits,
|
||||||
|
stop_bits,
|
||||||
|
handshake,
|
||||||
|
rigctld_ip,
|
||||||
|
rigctld_port,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -54,14 +69,15 @@ class radio:
|
||||||
"""
|
"""
|
||||||
self.devicename = devicename
|
self.devicename = devicename
|
||||||
self.deviceport = deviceport
|
self.deviceport = deviceport
|
||||||
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
# we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||||
|
self.serialspeed = str(serialspeed)
|
||||||
self.hamlib_ptt_type = hamlib_ptt_type
|
self.hamlib_ptt_type = hamlib_ptt_type
|
||||||
self.pttport = pttport
|
self.pttport = pttport
|
||||||
self.data_bits = data_bits
|
self.data_bits = data_bits
|
||||||
self.stop_bits = stop_bits
|
self.stop_bits = stop_bits
|
||||||
self.handshake = handshake
|
self.handshake = handshake
|
||||||
|
|
||||||
# check if we are running in a pyinstaller environment
|
# check if we are running in a pyinstaller environment
|
||||||
if hasattr(sys, "_MEIPASS"):
|
if hasattr(sys, "_MEIPASS"):
|
||||||
sys.path.append(getattr(sys, "_MEIPASS"))
|
sys.path.append(getattr(sys, "_MEIPASS"))
|
||||||
else:
|
else:
|
||||||
|
@ -70,27 +86,41 @@ class radio:
|
||||||
# get devicenumber by looking for deviceobject in Hamlib module
|
# get devicenumber by looking for deviceobject in Hamlib module
|
||||||
try:
|
try:
|
||||||
import Hamlib
|
import Hamlib
|
||||||
|
|
||||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
if int(self.devicename):
|
if int(self.devicename):
|
||||||
self.devicenumber = int(self.devicename)
|
self.devicenumber = int(self.devicename)
|
||||||
else:
|
else:
|
||||||
self.devicenumber = 6 #dummy
|
self.devicenumber = 6 # dummy
|
||||||
structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=e)
|
self.log.warning("[RIGCTL] Radio not found. Using DUMMY!", error=err)
|
||||||
|
|
||||||
# set deviceport to dummy port, if we selected dummy model
|
# set deviceport to dummy port, if we selected dummy model
|
||||||
if self.devicenumber == 1 or self.devicenumber == 6:
|
if self.devicenumber in {1, 6}:
|
||||||
self.deviceport = '/dev/ttyUSB0'
|
self.deviceport = "/dev/ttyUSB0"
|
||||||
|
|
||||||
print(self.devicenumber, self.deviceport, self.serialspeed)
|
print(self.devicenumber, self.deviceport, self.serialspeed)
|
||||||
|
|
||||||
# select precompiled executable for win32/win64 rigctl
|
# select precompiled executable for win32/win64 rigctl
|
||||||
# this is really a hack...somewhen we need a native hamlib integration for windows
|
# this is really a hack...somewhen we need a native hamlib integration for windows
|
||||||
if sys.platform in ['win32', 'win64']:
|
if sys.platform in ["win32", "win64"]:
|
||||||
self.cmd = app_path + 'lib\\hamlib\\'+sys.platform+'\\rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
self.cmd = (
|
||||||
|
app_path
|
||||||
|
+ "lib\\hamlib\\"
|
||||||
|
+ sys.platform
|
||||||
|
+ (
|
||||||
|
f"\\rigctl -m {self.devicenumber} "
|
||||||
|
f"-r {self.deviceport} "
|
||||||
|
f"-s {int(self.serialspeed)} "
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
self.cmd = "rigctl -m %d -r %s -s %d " % (
|
||||||
|
self.devicenumber,
|
||||||
|
self.deviceport,
|
||||||
|
int(self.serialspeed),
|
||||||
|
)
|
||||||
|
|
||||||
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
|
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
|
||||||
# il set e t per il get
|
# il set e t per il get
|
||||||
|
@ -101,33 +131,35 @@ class radio:
|
||||||
|
|
||||||
def get_frequency(self):
|
def get_frequency(self):
|
||||||
""" """
|
""" """
|
||||||
cmd = self.cmd + ' f'
|
cmd = f"{self.cmd} f"
|
||||||
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
sw_proc = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
|
||||||
|
)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
freq = sw_proc.communicate()[0]
|
freq = sw_proc.communicate()[0]
|
||||||
#print('get_frequency', freq, sw_proc.communicate())
|
# print("get_frequency", freq, sw_proc.communicate())
|
||||||
try:
|
try:
|
||||||
return int(freq)
|
return int(freq)
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_mode(self):
|
def get_mode(self):
|
||||||
""" """
|
""" """
|
||||||
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||||
#return Hamlib.rig_strrmode(hamlib_mode)
|
# return Hamlib.rig_strrmode(hamlib_mode)
|
||||||
try:
|
try:
|
||||||
return 'PKTUSB'
|
return "PKTUSB"
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_bandwith(self):
|
def get_bandwith(self):
|
||||||
""" """
|
""" """
|
||||||
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||||
bandwith = 2700
|
bandwith = 2700
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return bandwith
|
return bandwith
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_mode(self, mode):
|
def set_mode(self, mode):
|
||||||
|
@ -144,14 +176,16 @@ class radio:
|
||||||
|
|
||||||
def get_ptt(self):
|
def get_ptt(self):
|
||||||
""" """
|
""" """
|
||||||
cmd = self.cmd + ' t'
|
cmd = f"{self.cmd} t"
|
||||||
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
sw_proc = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
|
||||||
|
)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
status = sw_proc.communicate()[0]
|
status = sw_proc.communicate()[0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return status
|
return status
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_ptt(self, state):
|
def set_ptt(self, state):
|
||||||
|
@ -163,21 +197,18 @@ class radio:
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
cmd = self.cmd + ' T '
|
cmd = f"{self.cmd} T "
|
||||||
print('set_ptt', state)
|
print("set_ptt", state)
|
||||||
if state:
|
cmd = f"{cmd}1" if state else f"{cmd}0"
|
||||||
cmd = cmd + '1'
|
print("set_ptt", cmd)
|
||||||
else:
|
|
||||||
cmd = cmd + '0'
|
|
||||||
print('set_ptt', cmd)
|
|
||||||
|
|
||||||
sw_proc = subprocess.Popen(cmd, shell=True, text=True)
|
sw_proc = subprocess.Popen(cmd, shell=True, text=True)
|
||||||
try:
|
try:
|
||||||
return state
|
return state
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def close_rig(self):
|
def close_rig(self):
|
||||||
""" """
|
""" """
|
||||||
#self.my_rig.close()
|
# self.my_rig.close()
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,34 +4,45 @@
|
||||||
#
|
#
|
||||||
# modified and adjusted to FreeDATA needs by DJ2LS
|
# modified and adjusted to FreeDATA needs by DJ2LS
|
||||||
|
|
||||||
import logging
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
import log_handler
|
|
||||||
import static
|
|
||||||
|
|
||||||
# set global hamlib version
|
# set global hamlib version
|
||||||
hamlib_version = 0
|
hamlib_version = 0
|
||||||
|
|
||||||
|
|
||||||
class radio():
|
class radio:
|
||||||
"""rigctld (hamlib) communication class"""
|
"""rigctld (hamlib) communication class"""
|
||||||
|
|
||||||
# Note: This is a massive hack.
|
# Note: This is a massive hack.
|
||||||
|
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
||||||
""" Open a connection to rotctld, and test it for validity """
|
"""Open a connection to rotctld, and test it for validity"""
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
#self.sock.settimeout(timeout)
|
# self.sock.settimeout(timeout)
|
||||||
|
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.port = port
|
self.port = port
|
||||||
self.connection_attempts = 5
|
self.connection_attempts = 5
|
||||||
|
|
||||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
|
def open_rig(
|
||||||
|
self,
|
||||||
|
devicename,
|
||||||
|
deviceport,
|
||||||
|
hamlib_ptt_type,
|
||||||
|
serialspeed,
|
||||||
|
pttport,
|
||||||
|
data_bits,
|
||||||
|
stop_bits,
|
||||||
|
handshake,
|
||||||
|
rigctld_ip,
|
||||||
|
rigctld_port,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -53,24 +64,33 @@ class radio():
|
||||||
self.port = int(rigctld_port)
|
self.port = int(rigctld_port)
|
||||||
|
|
||||||
if self.connect():
|
if self.connect():
|
||||||
logging.debug("Rigctl intialized")
|
self.log.debug("Rigctl initialized")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
structlog.get_logger("structlog").error("[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port)
|
self.log.error(
|
||||||
|
"[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""Connect to rigctld instance"""
|
"""Connect to rigctld instance"""
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
try:
|
try:
|
||||||
self.connection = socket.create_connection((self.hostname,self.port))
|
self.connection = socket.create_connection((self.hostname, self.port))
|
||||||
self.connected = True
|
self.connected = True
|
||||||
structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port)
|
self.log.info(
|
||||||
|
"[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
# ConnectionRefusedError: [Errno 111] Connection refused
|
# ConnectionRefusedError: [Errno 111] Connection refused
|
||||||
self.close_rig()
|
self.close_rig()
|
||||||
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=e)
|
self.log.warning(
|
||||||
|
"[RIGCTLD] Connection to rigctld refused! Reconnect...",
|
||||||
|
ip=self.hostname,
|
||||||
|
port=self.port,
|
||||||
|
e=err,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def close_rig(self):
|
def close_rig(self):
|
||||||
|
@ -85,20 +105,28 @@ class radio():
|
||||||
Args:
|
Args:
|
||||||
command:
|
command:
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.connected:
|
if self.connected:
|
||||||
try:
|
try:
|
||||||
self.connection.sendall(command+b'\n')
|
self.connection.sendall(command + b"\n")
|
||||||
except:
|
except Exception:
|
||||||
structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port)
|
self.log.warning(
|
||||||
|
"[RIGCTLD] Command not executed!",
|
||||||
|
command=command,
|
||||||
|
ip=self.hostname,
|
||||||
|
port=self.port,
|
||||||
|
)
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.connection.recv(1024)
|
return self.connection.recv(1024)
|
||||||
except:
|
except Exception:
|
||||||
structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port)
|
self.log.warning(
|
||||||
|
"[RIGCTLD] No command response!",
|
||||||
|
command=command,
|
||||||
|
ip=self.hostname,
|
||||||
|
port=self.port,
|
||||||
|
)
|
||||||
self.connected = False
|
self.connected = False
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
@ -110,20 +138,20 @@ class radio():
|
||||||
""" """
|
""" """
|
||||||
try:
|
try:
|
||||||
data = self.send_command(b"m")
|
data = self.send_command(b"m")
|
||||||
data = data.split(b'\n')
|
data = data.split(b"\n")
|
||||||
mode = data[0]
|
mode = data[0]
|
||||||
return mode.decode("utf-8")
|
return mode.decode("utf-8")
|
||||||
except:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_bandwith(self):
|
def get_bandwith(self):
|
||||||
""" """
|
""" """
|
||||||
try:
|
try:
|
||||||
data = self.send_command(b"m")
|
data = self.send_command(b"m")
|
||||||
data = data.split(b'\n')
|
data = data.split(b"\n")
|
||||||
bandwith = data[1]
|
bandwith = data[1]
|
||||||
return bandwith.decode("utf-8")
|
return bandwith.decode("utf-8")
|
||||||
except:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_frequency(self):
|
def get_frequency(self):
|
||||||
|
@ -131,14 +159,14 @@ class radio():
|
||||||
try:
|
try:
|
||||||
frequency = self.send_command(b"f")
|
frequency = self.send_command(b"f")
|
||||||
return frequency.decode("utf-8")
|
return frequency.decode("utf-8")
|
||||||
except:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_ptt(self):
|
def get_ptt(self):
|
||||||
""" """
|
""" """
|
||||||
try:
|
try:
|
||||||
return self.send_command(b"t")
|
return self.send_command(b"t")
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_ptt(self, state):
|
def set_ptt(self, state):
|
||||||
|
@ -152,9 +180,9 @@ class radio():
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if state:
|
if state:
|
||||||
self.send_command(b"T 1")
|
self.send_command(b"T 1")
|
||||||
else:
|
else:
|
||||||
self.send_command(b"T 0")
|
self.send_command(b"T 0")
|
||||||
return state
|
return state
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import structlog
|
|
||||||
|
|
||||||
hamlib_version = 0
|
hamlib_version = 0
|
||||||
|
|
||||||
|
|
||||||
class radio:
|
class radio:
|
||||||
""" """
|
""" """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
444
tnc/sock.py
444
tnc/sock.py
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Fri Dec 25 21:25:14 2020
|
Created on Fri Dec 25 21:25:14 2020
|
||||||
|
@ -21,23 +20,17 @@ Created on Fri Dec 25 21:25:14 2020
|
||||||
"""
|
"""
|
||||||
import atexit
|
import atexit
|
||||||
import base64
|
import base64
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import queue
|
import queue
|
||||||
import socketserver
|
import socketserver
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import psutil
|
|
||||||
import structlog
|
|
||||||
import ujson as json
|
|
||||||
|
|
||||||
import audio
|
|
||||||
import data_handler
|
import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import log_handler
|
|
||||||
import static
|
import static
|
||||||
|
import structlog
|
||||||
|
import ujson as json
|
||||||
|
|
||||||
SOCKET_QUEUE = queue.Queue()
|
SOCKET_QUEUE = queue.Queue()
|
||||||
DAEMON_QUEUE = queue.Queue()
|
DAEMON_QUEUE = queue.Queue()
|
||||||
|
@ -50,19 +43,22 @@ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||||
"""
|
"""
|
||||||
the socket handler base class
|
the socket handler base class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
""" """
|
""" """
|
||||||
|
|
||||||
connection_alive = False
|
connection_alive = False
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
def send_to_client(self):
|
def send_to_client(self):
|
||||||
"""
|
"""
|
||||||
function called by socket handler
|
function called by socket handler
|
||||||
send data to a network client if available
|
send data to a network client if available
|
||||||
"""
|
"""
|
||||||
tempdata = b''
|
tempdata = b""
|
||||||
while self.connection_alive and not CLOSE_SIGNAL:
|
while self.connection_alive and not CLOSE_SIGNAL:
|
||||||
# send tnc state as network stream
|
# send tnc state as network stream
|
||||||
# check server port against daemon port and send corresponding data
|
# check server port against daemon port and send corresponding data
|
||||||
|
@ -80,24 +76,24 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
while not SOCKET_QUEUE.empty():
|
while not SOCKET_QUEUE.empty():
|
||||||
data = SOCKET_QUEUE.get()
|
data = SOCKET_QUEUE.get()
|
||||||
sock_data = bytes(data, 'utf-8')
|
sock_data = bytes(data, "utf-8")
|
||||||
sock_data += b'\n' # append line limiter
|
sock_data += b"\n" # append line limiter
|
||||||
|
|
||||||
# send data to all clients
|
# send data to all clients
|
||||||
#try:
|
# try:
|
||||||
for client in CONNECTED_CLIENTS:
|
for client in CONNECTED_CLIENTS:
|
||||||
try:
|
try:
|
||||||
client.send(sock_data)
|
client.send(sock_data)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
# print("connection lost...")
|
# print("connection lost...")
|
||||||
structlog.get_logger("structlog").info("[SCK] Connection lost", e=e)
|
self.log.info("[SCK] Connection lost", e=err)
|
||||||
self.connection_alive = False
|
self.connection_alive = False
|
||||||
|
|
||||||
# we want to transmit scatter data only once to reduce network traffic
|
# we want to transmit scatter data only once to reduce network traffic
|
||||||
static.SCATTER = []
|
static.SCATTER = []
|
||||||
# we want to display INFO messages only once
|
# we want to display INFO messages only once
|
||||||
static.INFO = []
|
static.INFO = []
|
||||||
#self.request.sendall(sock_data)
|
# self.request.sendall(sock_data)
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
def receive_from_client(self):
|
def receive_from_client(self):
|
||||||
|
@ -111,15 +107,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
chunk = self.request.recv(1024)
|
chunk = self.request.recv(1024)
|
||||||
data += chunk
|
data += chunk
|
||||||
|
|
||||||
if chunk == b'':
|
if chunk == b"":
|
||||||
#print("connection broken. Closing...")
|
# print("connection broken. Closing...")
|
||||||
self.connection_alive = False
|
self.connection_alive = False
|
||||||
|
|
||||||
if data.startswith(b'{') and data.endswith(b'}\n'):
|
if data.startswith(b"{") and data.endswith(b"}\n"):
|
||||||
# split data by \n if we have multiple commands in socket buffer
|
# split data by \n if we have multiple commands in socket buffer
|
||||||
data = data.split(b'\n')
|
data = data.split(b"\n")
|
||||||
# remove empty data
|
# remove empty data
|
||||||
data.remove(b'')
|
data.remove(b"")
|
||||||
|
|
||||||
# iterate thorugh data list
|
# iterate thorugh data list
|
||||||
for commands in data:
|
for commands in data:
|
||||||
|
@ -137,8 +133,13 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
# finally delete our rx buffer to be ready for new commands
|
# finally delete our rx buffer to be ready for new commands
|
||||||
data = bytes()
|
data = bytes()
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e)
|
self.log.info(
|
||||||
|
"[SCK] Connection closed",
|
||||||
|
ip=self.client_address[0],
|
||||||
|
port=self.client_address[1],
|
||||||
|
e=err,
|
||||||
|
)
|
||||||
self.connection_alive = False
|
self.connection_alive = False
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
|
@ -147,11 +148,19 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
"""
|
"""
|
||||||
CONNECTED_CLIENTS.add(self.request)
|
CONNECTED_CLIENTS.add(self.request)
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1])
|
self.log.debug(
|
||||||
|
"[SCK] Client connected",
|
||||||
|
ip=self.client_address[0],
|
||||||
|
port=self.client_address[1],
|
||||||
|
)
|
||||||
self.connection_alive = True
|
self.connection_alive = True
|
||||||
|
|
||||||
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start()
|
self.sendThread = threading.Thread(
|
||||||
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start()
|
target=self.send_to_client, args=[], daemon=True
|
||||||
|
).start()
|
||||||
|
self.receiveThread = threading.Thread(
|
||||||
|
target=self.receive_from_client, args=[], daemon=True
|
||||||
|
).start()
|
||||||
|
|
||||||
# keep connection alive until we close it
|
# keep connection alive until we close it
|
||||||
while self.connection_alive and not CLOSE_SIGNAL:
|
while self.connection_alive and not CLOSE_SIGNAL:
|
||||||
|
@ -159,11 +168,19 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
""" """
|
""" """
|
||||||
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1])
|
self.log.warning(
|
||||||
|
"[SCK] Closing client socket",
|
||||||
|
ip=self.client_address[0],
|
||||||
|
port=self.client_address[1],
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
CONNECTED_CLIENTS.remove(self.request)
|
CONNECTED_CLIENTS.remove(self.request)
|
||||||
except:
|
except Exception:
|
||||||
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request)
|
self.log.warning(
|
||||||
|
"[SCK] client connection already removed from client list",
|
||||||
|
client=self.request,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def process_tnc_commands(data):
|
def process_tnc_commands(data):
|
||||||
"""
|
"""
|
||||||
|
@ -175,64 +192,82 @@ def process_tnc_commands(data):
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
# we need to do some error handling in case of socket timeout or decoding issue
|
# we need to do some error handling in case of socket timeout or decoding issue
|
||||||
try:
|
try:
|
||||||
# convert data to json object
|
# convert data to json object
|
||||||
received_json = json.loads(data)
|
received_json = json.loads(data)
|
||||||
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
|
log.debug("[SCK] CMD", command=received_json)
|
||||||
# SET TX AUDIO LEVEL -----------------------------------------------------
|
# SET TX AUDIO LEVEL -----------------------------------------------------
|
||||||
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level":
|
if (
|
||||||
|
received_json["type"] == "set"
|
||||||
|
and received_json["command"] == "tx_audio_level"
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
||||||
command_response("tx_audio_level", True)
|
command_response("tx_audio_level", True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("tx_audio_level", False)
|
command_response("tx_audio_level", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# TRANSMIT SINE WAVE -----------------------------------------------------
|
# TRANSMIT SINE WAVE -----------------------------------------------------
|
||||||
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
|
if (
|
||||||
|
received_json["type"] == "set"
|
||||||
|
and received_json["command"] == "send_test_frame"
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME'])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
||||||
command_response("send_test_frame", True)
|
command_response("send_test_frame", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("send_test_frame", False)
|
command_response("send_test_frame", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# CQ CQ CQ -----------------------------------------------------
|
# CQ CQ CQ -----------------------------------------------------
|
||||||
if received_json["command"] == "cqcqcq":
|
if received_json["command"] == "cqcqcq":
|
||||||
try:
|
try:
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ'])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
|
||||||
command_response("cqcqcq", True)
|
command_response("cqcqcq", True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("cqcqcq", False)
|
command_response("cqcqcq", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# START_BEACON -----------------------------------------------------
|
# START_BEACON -----------------------------------------------------
|
||||||
if received_json["command"] == "start_beacon":
|
if received_json["command"] == "start_beacon":
|
||||||
try:
|
try:
|
||||||
static.BEACON_STATE = True
|
static.BEACON_STATE = True
|
||||||
interval = int(received_json["parameter"])
|
interval = int(received_json["parameter"])
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
||||||
command_response("start_beacon", True)
|
command_response("start_beacon", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("start_beacon", False)
|
command_response("start_beacon", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# STOP_BEACON -----------------------------------------------------
|
# STOP_BEACON -----------------------------------------------------
|
||||||
if received_json["command"] == "stop_beacon":
|
if received_json["command"] == "stop_beacon":
|
||||||
try:
|
try:
|
||||||
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
|
log.warning("[TNC] Stopping beacon!")
|
||||||
static.BEACON_STATE = False
|
static.BEACON_STATE = False
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
||||||
command_response("stop_beacon", True)
|
command_response("stop_beacon", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("stop_beacon", False)
|
command_response("stop_beacon", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# PING ----------------------------------------------------------
|
# PING ----------------------------------------------------------
|
||||||
if received_json["type"] == 'ping' and received_json["command"] == "ping":
|
if received_json["type"] == "ping" and received_json["command"] == "ping":
|
||||||
# send ping frame and wait for ACK
|
# send ping frame and wait for ACK
|
||||||
try:
|
try:
|
||||||
dxcallsign = received_json["dxcallsign"]
|
dxcallsign = received_json["dxcallsign"]
|
||||||
|
@ -243,14 +278,16 @@ def process_tnc_commands(data):
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
|
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["PING", dxcallsign])
|
||||||
command_response("ping", True)
|
command_response("ping", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("ping", False)
|
command_response("ping", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# CONNECT ----------------------------------------------------------
|
# CONNECT ----------------------------------------------------------
|
||||||
if received_json["type"] == 'arq' and received_json["command"] == "connect":
|
if received_json["type"] == "arq" and received_json["command"] == "connect":
|
||||||
static.BEACON_PAUSE = True
|
static.BEACON_PAUSE = True
|
||||||
# send ping frame and wait for ACK
|
# send ping frame and wait for ACK
|
||||||
try:
|
try:
|
||||||
|
@ -265,24 +302,28 @@ def process_tnc_commands(data):
|
||||||
static.DXCALLSIGN = dxcallsign
|
static.DXCALLSIGN = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
||||||
|
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['CONNECT', dxcallsign])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["CONNECT", dxcallsign])
|
||||||
command_response("connect", True)
|
command_response("connect", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("connect", False)
|
command_response("connect", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# DISCONNECT ----------------------------------------------------------
|
# DISCONNECT ----------------------------------------------------------
|
||||||
if received_json["type"] == 'arq' and received_json["command"] == "disconnect":
|
if received_json["type"] == "arq" and received_json["command"] == "disconnect":
|
||||||
# send ping frame and wait for ACK
|
# send ping frame and wait for ACK
|
||||||
try:
|
try:
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT'])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
||||||
command_response("disconnect", True)
|
command_response("disconnect", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("disconnect", False)
|
command_response("disconnect", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# TRANSMIT RAW DATA -------------------------------------------
|
# TRANSMIT RAW DATA -------------------------------------------
|
||||||
if received_json["type"] == 'arq' and received_json["command"] == "send_raw":
|
if received_json["type"] == "arq" and received_json["command"] == "send_raw":
|
||||||
static.BEACON_PAUSE = True
|
static.BEACON_PAUSE = True
|
||||||
try:
|
try:
|
||||||
if not static.ARQ_SESSION:
|
if not static.ARQ_SESSION:
|
||||||
|
@ -306,39 +347,48 @@ def process_tnc_commands(data):
|
||||||
# check if specific callsign is set with different SSID than the TNC is initialized
|
# check if specific callsign is set with different SSID than the TNC is initialized
|
||||||
try:
|
try:
|
||||||
mycallsign = received_json["parameter"][0]["mycallsign"]
|
mycallsign = received_json["parameter"][0]["mycallsign"]
|
||||||
except:
|
except Exception:
|
||||||
mycallsign = static.MYCALLSIGN
|
mycallsign = static.MYCALLSIGN
|
||||||
|
|
||||||
# check if transmission uuid provided else set no-uuid
|
# check if transmission uuid provided else set no-uuid
|
||||||
try:
|
try:
|
||||||
arq_uuid = received_json["uuid"]
|
arq_uuid = received_json["uuid"]
|
||||||
except:
|
except Exception:
|
||||||
arq_uuid = 'no-uuid'
|
arq_uuid = "no-uuid"
|
||||||
|
|
||||||
if not len(base64data) % 4:
|
if not len(base64data) % 4:
|
||||||
binarydata = base64.b64decode(base64data)
|
binarydata = base64.b64decode(base64data)
|
||||||
|
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', binarydata, mode, n_frames, arq_uuid, mycallsign])
|
data_handler.DATA_QUEUE_TRANSMIT.put(
|
||||||
|
["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("send_raw", False)
|
command_response("send_raw", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# STOP TRANSMISSION ----------------------------------------------------------
|
# STOP TRANSMISSION ----------------------------------------------------------
|
||||||
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission":
|
if (
|
||||||
|
received_json["type"] == "arq"
|
||||||
|
and received_json["command"] == "stop_transmission"
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE:
|
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
|
||||||
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP'])
|
data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
|
||||||
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
|
log.warning("[TNC] Stopping transmission!")
|
||||||
static.TNC_STATE = 'IDLE'
|
static.TNC_STATE = "IDLE"
|
||||||
static.ARQ_STATE = False
|
static.ARQ_STATE = False
|
||||||
command_response("stop_transmission", True)
|
command_response("stop_transmission", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("stop_transmission", False)
|
command_response("stop_transmission", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
if received_json["type"] == 'get' and received_json["command"] == 'rx_buffer':
|
if received_json["type"] == "get" and received_json["command"] == "rx_buffer":
|
||||||
try:
|
try:
|
||||||
output = {
|
output = {
|
||||||
"command": "rx_buffer",
|
"command": "rx_buffer",
|
||||||
|
@ -346,37 +396,53 @@ def process_tnc_commands(data):
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in range(len(static.RX_BUFFER)):
|
for i in range(len(static.RX_BUFFER)):
|
||||||
#print(static.RX_BUFFER[i][4])
|
# print(static.RX_BUFFER[i][4])
|
||||||
#rawdata = json.loads(static.RX_BUFFER[i][4])
|
# rawdata = json.loads(static.RX_BUFFER[i][4])
|
||||||
base64_data = static.RX_BUFFER[i][4]
|
base64_data = static.RX_BUFFER[i][4]
|
||||||
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data})
|
output["data-array"].append(
|
||||||
|
{
|
||||||
|
"uuid": static.RX_BUFFER[i][0],
|
||||||
|
"timestamp": static.RX_BUFFER[i][1],
|
||||||
|
"dxcallsign": str(static.RX_BUFFER[i][2], "utf-8"),
|
||||||
|
"dxgrid": str(static.RX_BUFFER[i][3], "utf-8"),
|
||||||
|
"data": base64_data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
jsondata = json.dumps(output)
|
jsondata = json.dumps(output)
|
||||||
#self.request.sendall(bytes(jsondata, encoding))
|
# self.request.sendall(bytes(jsondata, encoding))
|
||||||
SOCKET_QUEUE.put(jsondata)
|
SOCKET_QUEUE.put(jsondata)
|
||||||
command_response("rx_buffer", True)
|
command_response("rx_buffer", True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("rx_buffer", False)
|
command_response("rx_buffer", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer':
|
if (
|
||||||
|
received_json["type"] == "set"
|
||||||
|
and received_json["command"] == "del_rx_buffer"
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
static.RX_BUFFER = []
|
static.RX_BUFFER = []
|
||||||
command_response("del_rx_buffer", True)
|
command_response("del_rx_buffer", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("del_rx_buffer", False)
|
command_response("del_rx_buffer", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning(
|
||||||
|
"[SCK] command execution error", e=err, command=received_json
|
||||||
|
)
|
||||||
|
|
||||||
# exception, if JSON cant be decoded
|
# exception, if JSON cant be decoded
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
|
log.error("[TNC] JSON decoding error", e=err)
|
||||||
|
|
||||||
|
|
||||||
def send_tnc_state():
|
def send_tnc_state():
|
||||||
"""
|
"""
|
||||||
send the tnc state to network
|
send the tnc state to network
|
||||||
"""
|
"""
|
||||||
encoding = 'utf-8'
|
encoding = "utf-8"
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"command": "tnc_state",
|
"command": "tnc_state",
|
||||||
|
@ -401,8 +467,8 @@ def send_tnc_state():
|
||||||
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
|
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
|
||||||
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
|
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
|
||||||
"total_bytes": str(static.TOTAL_BYTES),
|
"total_bytes": str(static.TOTAL_BYTES),
|
||||||
"info" : static.INFO,
|
"info": static.INFO,
|
||||||
"beacon_state" : str(static.BEACON_STATE),
|
"beacon_state": str(static.BEACON_STATE),
|
||||||
"stations": [],
|
"stations": [],
|
||||||
"mycallsign": str(static.MYCALLSIGN, encoding),
|
"mycallsign": str(static.MYCALLSIGN, encoding),
|
||||||
"dxcallsign": str(static.DXCALLSIGN, encoding),
|
"dxcallsign": str(static.DXCALLSIGN, encoding),
|
||||||
|
@ -411,17 +477,21 @@ def send_tnc_state():
|
||||||
|
|
||||||
# add heard stations to heard stations object
|
# add heard stations to heard stations object
|
||||||
for heard in static.HEARD_STATIONS:
|
for heard in static.HEARD_STATIONS:
|
||||||
output["stations"].append({
|
output["stations"].append(
|
||||||
"dxcallsign": str(heard[0], 'utf-8'),
|
{
|
||||||
"dxgrid": str(heard[1], 'utf-8'),
|
"dxcallsign": str(heard[0], "utf-8"),
|
||||||
"timestamp": heard[2],
|
"dxgrid": str(heard[1], "utf-8"),
|
||||||
"datatype": heard[3],
|
"timestamp": heard[2],
|
||||||
"snr": heard[4],
|
"datatype": heard[3],
|
||||||
"offset": heard[5],
|
"snr": heard[4],
|
||||||
"frequency": heard[6]})
|
"offset": heard[5],
|
||||||
|
"frequency": heard[6],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return json.dumps(output)
|
return json.dumps(output)
|
||||||
|
|
||||||
|
|
||||||
def process_daemon_commands(data):
|
def process_daemon_commands(data):
|
||||||
"""
|
"""
|
||||||
process daemon commands
|
process daemon commands
|
||||||
|
@ -432,41 +502,55 @@ def process_daemon_commands(data):
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
# convert data to json object
|
# convert data to json object
|
||||||
received_json = json.loads(data)
|
received_json = json.loads(data)
|
||||||
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
|
log.debug("[SCK] CMD", command=received_json)
|
||||||
if received_json["type"] == 'set' and received_json["command"] == 'mycallsign':
|
if received_json["type"] == "set" and received_json["command"] == "mycallsign":
|
||||||
try:
|
try:
|
||||||
callsign = received_json["parameter"]
|
callsign = received_json["parameter"]
|
||||||
|
|
||||||
if bytes(callsign, 'utf-8') == b'':
|
if bytes(callsign, "utf-8") == b"":
|
||||||
self.request.sendall(b'INVALID CALLSIGN')
|
self.request.sendall(b"INVALID CALLSIGN")
|
||||||
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
log.warning(
|
||||||
|
"[DMN] SET MYCALL FAILED",
|
||||||
|
call=static.MYCALLSIGN,
|
||||||
|
crc=static.MYCALLSIGN_CRC,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
static.MYCALLSIGN = bytes(callsign, 'utf-8')
|
static.MYCALLSIGN = bytes(callsign, "utf-8")
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
||||||
|
|
||||||
command_response("mycallsign", True)
|
command_response("mycallsign", True)
|
||||||
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
log.info(
|
||||||
except Exception as e:
|
"[DMN] SET MYCALL",
|
||||||
|
call=static.MYCALLSIGN,
|
||||||
|
crc=static.MYCALLSIGN_CRC,
|
||||||
|
)
|
||||||
|
except Exception as err:
|
||||||
command_response("mycallsign", False)
|
command_response("mycallsign", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||||
|
|
||||||
if received_json["type"] == 'set' and received_json["command"] == 'mygrid':
|
if received_json["type"] == "set" and received_json["command"] == "mygrid":
|
||||||
try:
|
try:
|
||||||
mygrid = received_json["parameter"]
|
mygrid = received_json["parameter"]
|
||||||
|
|
||||||
if bytes(mygrid, 'utf-8') == b'':
|
if bytes(mygrid, "utf-8") == b"":
|
||||||
self.request.sendall(b'INVALID GRID')
|
self.request.sendall(b"INVALID GRID")
|
||||||
else:
|
else:
|
||||||
static.MYGRID = bytes(mygrid, 'utf-8')
|
static.MYGRID = bytes(mygrid, "utf-8")
|
||||||
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID)
|
log.info("[SCK] SET MYGRID", grid=static.MYGRID)
|
||||||
command_response("mygrid", True)
|
command_response("mygrid", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("mygrid", False)
|
command_response("mygrid", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||||
|
|
||||||
if received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED:
|
if (
|
||||||
|
received_json["type"] == "set"
|
||||||
|
and received_json["command"] == "start_tnc"
|
||||||
|
and not static.TNCSTARTED
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
mycall = str(received_json["parameter"][0]["mycall"])
|
mycall = str(received_json["parameter"][0]["mycall"])
|
||||||
mygrid = str(received_json["parameter"][0]["mygrid"])
|
mygrid = str(received_json["parameter"][0]["mygrid"])
|
||||||
|
@ -494,40 +578,45 @@ def process_daemon_commands(data):
|
||||||
|
|
||||||
# print some debugging parameters
|
# print some debugging parameters
|
||||||
for item in received_json["parameter"][0]:
|
for item in received_json["parameter"][0]:
|
||||||
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item])
|
log.debug(
|
||||||
|
f"[DMN] TNC Startup Config : {item}",
|
||||||
|
value=received_json["parameter"][0][item],
|
||||||
|
)
|
||||||
|
|
||||||
DAEMON_QUEUE.put(['STARTTNC',
|
DAEMON_QUEUE.put(
|
||||||
mycall,
|
[
|
||||||
mygrid,
|
"STARTTNC",
|
||||||
rx_audio,
|
mycall,
|
||||||
tx_audio,
|
mygrid,
|
||||||
devicename,
|
rx_audio,
|
||||||
deviceport,
|
tx_audio,
|
||||||
serialspeed,
|
devicename,
|
||||||
pttprotocol,
|
deviceport,
|
||||||
pttport,
|
serialspeed,
|
||||||
data_bits,
|
pttprotocol,
|
||||||
stop_bits,
|
pttport,
|
||||||
handshake,
|
data_bits,
|
||||||
radiocontrol,
|
stop_bits,
|
||||||
rigctld_ip,
|
handshake,
|
||||||
rigctld_port,
|
radiocontrol,
|
||||||
enable_scatter,
|
rigctld_ip,
|
||||||
enable_fft,
|
rigctld_port,
|
||||||
low_bandwith_mode,
|
enable_scatter,
|
||||||
tuning_range_fmin,
|
enable_fft,
|
||||||
tuning_range_fmax,
|
low_bandwith_mode,
|
||||||
enable_fsk,
|
tuning_range_fmin,
|
||||||
tx_audio_level,
|
tuning_range_fmax,
|
||||||
respond_to_cq,
|
enable_fsk,
|
||||||
])
|
tx_audio_level,
|
||||||
|
respond_to_cq,
|
||||||
|
]
|
||||||
|
)
|
||||||
command_response("start_tnc", True)
|
command_response("start_tnc", True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("start_tnc", False)
|
command_response("start_tnc", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||||
|
if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
|
||||||
if received_json["type"] == 'get' and received_json["command"] == 'test_hamlib':
|
|
||||||
try:
|
try:
|
||||||
devicename = str(received_json["parameter"][0]["devicename"])
|
devicename = str(received_json["parameter"][0]["devicename"])
|
||||||
deviceport = str(received_json["parameter"][0]["deviceport"])
|
deviceport = str(received_json["parameter"][0]["deviceport"])
|
||||||
|
@ -541,56 +630,62 @@ def process_daemon_commands(data):
|
||||||
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
||||||
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||||
|
|
||||||
DAEMON_QUEUE.put(['TEST_HAMLIB',
|
DAEMON_QUEUE.put(
|
||||||
devicename,
|
[
|
||||||
deviceport,
|
"TEST_HAMLIB",
|
||||||
serialspeed,
|
devicename,
|
||||||
pttprotocol,
|
deviceport,
|
||||||
pttport,
|
serialspeed,
|
||||||
data_bits,
|
pttprotocol,
|
||||||
stop_bits,
|
pttport,
|
||||||
handshake,
|
data_bits,
|
||||||
radiocontrol,
|
stop_bits,
|
||||||
rigctld_ip,
|
handshake,
|
||||||
rigctld_port,
|
radiocontrol,
|
||||||
])
|
rigctld_ip,
|
||||||
|
rigctld_port,
|
||||||
|
]
|
||||||
|
)
|
||||||
command_response("test_hamlib", True)
|
command_response("test_hamlib", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("test_hamlib", False)
|
command_response("test_hamlib", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||||
|
|
||||||
if received_json["type"] == 'set' and received_json["command"] == 'stop_tnc':
|
if received_json["type"] == "set" and received_json["command"] == "stop_tnc":
|
||||||
try:
|
try:
|
||||||
static.TNCPROCESS.kill()
|
static.TNCPROCESS.kill()
|
||||||
# unregister process from atexit to avoid process zombies
|
# unregister process from atexit to avoid process zombies
|
||||||
atexit.unregister(static.TNCPROCESS.kill)
|
atexit.unregister(static.TNCPROCESS.kill)
|
||||||
|
|
||||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
log.warning("[DMN] Stopping TNC")
|
||||||
static.TNCSTARTED = False
|
static.TNCSTARTED = False
|
||||||
command_response("stop_tnc", True)
|
command_response("stop_tnc", True)
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
command_response("stop_tnc", False)
|
command_response("stop_tnc", False)
|
||||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||||
|
|
||||||
|
|
||||||
def send_daemon_state():
|
def send_daemon_state():
|
||||||
"""
|
"""
|
||||||
send the daemon state to network
|
send the daemon state to network
|
||||||
"""
|
"""
|
||||||
|
log = structlog.get_logger(__name__)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
'command': 'daemon_state',
|
"command": "daemon_state",
|
||||||
'daemon_state': [],
|
"daemon_state": [],
|
||||||
'python_version': str(python_version),
|
"python_version": str(python_version),
|
||||||
'hamlib_version': static.HAMLIB_VERSION,
|
"hamlib_version": static.HAMLIB_VERSION,
|
||||||
'input_devices': static.AUDIO_INPUT_DEVICES,
|
"input_devices": static.AUDIO_INPUT_DEVICES,
|
||||||
'output_devices': static.AUDIO_OUTPUT_DEVICES,
|
"output_devices": static.AUDIO_OUTPUT_DEVICES,
|
||||||
'serial_devices': static.SERIAL_DEVICES,
|
"serial_devices": static.SERIAL_DEVICES,
|
||||||
#'cpu': str(psutil.cpu_percent()),
|
#'cpu': str(psutil.cpu_percent()),
|
||||||
#'ram': str(psutil.virtual_memory().percent),
|
#'ram': str(psutil.virtual_memory().percent),
|
||||||
'version': '0.1'
|
"version": "0.1",
|
||||||
}
|
}
|
||||||
|
|
||||||
if static.TNCSTARTED:
|
if static.TNCSTARTED:
|
||||||
output["daemon_state"].append({"status": "running"})
|
output["daemon_state"].append({"status": "running"})
|
||||||
|
@ -600,12 +695,13 @@ def send_daemon_state():
|
||||||
jsondata = json.dumps(output)
|
jsondata = json.dumps(output)
|
||||||
|
|
||||||
return jsondata
|
return jsondata
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
structlog.get_logger("structlog").warning("[SCK] error", e=e)
|
log.warning("[SCK] error", e=err)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def command_response(command, status):
|
def command_response(command, status):
|
||||||
s_status = "OK" if status else "Failed"
|
s_status = "OK" if status else "Failed"
|
||||||
jsondata = {"command_response": command, "status" : s_status}
|
jsondata = {"command_response": command, "status": s_status}
|
||||||
data_out = json.dumps(jsondata)
|
data_out = json.dumps(jsondata)
|
||||||
SOCKET_QUEUE.put(data_out)
|
SOCKET_QUEUE.put(data_out)
|
||||||
|
|
|
@ -8,7 +8,7 @@ Here we are saving application wide variables and stats, which have to be access
|
||||||
Not nice, suggestions are appreciated :-)
|
Not nice, suggestions are appreciated :-)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = '0.4.0-alpha'
|
VERSION = "0.4.0-alpha"
|
||||||
|
|
||||||
# DAEMON
|
# DAEMON
|
||||||
DAEMONPORT = 3001
|
DAEMONPORT = 3001
|
||||||
|
@ -16,16 +16,16 @@ TNCSTARTED = False
|
||||||
TNCPROCESS = 0
|
TNCPROCESS = 0
|
||||||
|
|
||||||
# Operator Defaults
|
# Operator Defaults
|
||||||
MYCALLSIGN = b'AA0AA'
|
MYCALLSIGN = b"AA0AA"
|
||||||
MYCALLSIGN_CRC = b'A'
|
MYCALLSIGN_CRC = b"A"
|
||||||
|
|
||||||
DXCALLSIGN = b'AA0AA'
|
DXCALLSIGN = b"AA0AA"
|
||||||
DXCALLSIGN_CRC = b'A'
|
DXCALLSIGN_CRC = b"A"
|
||||||
|
|
||||||
MYGRID = b''
|
MYGRID = b""
|
||||||
DXGRID = b''
|
DXGRID = b""
|
||||||
|
|
||||||
SSID_LIST = [] # ssid list we are responding to
|
SSID_LIST = [] # ssid list we are responding to
|
||||||
|
|
||||||
LOW_BANDWITH_MODE = False
|
LOW_BANDWITH_MODE = False
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
|
@ -33,7 +33,7 @@ LOW_BANDWITH_MODE = False
|
||||||
# Server Defaults
|
# Server Defaults
|
||||||
HOST = "0.0.0.0"
|
HOST = "0.0.0.0"
|
||||||
PORT = 3000
|
PORT = 3000
|
||||||
SOCKET_TIMEOUT = 1 # seconds
|
SOCKET_TIMEOUT = 1 # seconds
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
SERIAL_DEVICES = []
|
SERIAL_DEVICES = []
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
|
@ -41,21 +41,21 @@ SERIAL_DEVICES = []
|
||||||
PTT_STATE = False
|
PTT_STATE = False
|
||||||
TRANSMITTING = False
|
TRANSMITTING = False
|
||||||
|
|
||||||
HAMLIB_VERSION = '0'
|
HAMLIB_VERSION = "0"
|
||||||
HAMLIB_PTT_TYPE = 'RTS'
|
HAMLIB_PTT_TYPE = "RTS"
|
||||||
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
|
HAMLIB_DEVICE_NAME = "RIG_MODEL_DUMMY_NOVFO"
|
||||||
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
|
HAMLIB_DEVICE_PORT = "/dev/ttyUSB0"
|
||||||
HAMLIB_SERIAL_SPEED = '9600'
|
HAMLIB_SERIAL_SPEED = "9600"
|
||||||
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
|
HAMLIB_PTT_PORT = "/dev/ttyUSB0"
|
||||||
HAMLIB_STOP_BITS = '1'
|
HAMLIB_STOP_BITS = "1"
|
||||||
HAMLIB_DATA_BITS = '8'
|
HAMLIB_DATA_BITS = "8"
|
||||||
HAMLIB_HANDSHAKE = 'None'
|
HAMLIB_HANDSHAKE = "None"
|
||||||
HAMLIB_RADIOCONTROL = 'direct'
|
HAMLIB_RADIOCONTROL = "direct"
|
||||||
HAMLIB_RIGCTLD_IP = '127.0.0.1'
|
HAMLIB_RIGCTLD_IP = "127.0.0.1"
|
||||||
HAMLIB_RIGCTLD_PORT = '4532'
|
HAMLIB_RIGCTLD_PORT = "4532"
|
||||||
|
|
||||||
HAMLIB_FREQUENCY = 0
|
HAMLIB_FREQUENCY = 0
|
||||||
HAMLIB_MODE = ''
|
HAMLIB_MODE = ""
|
||||||
HAMLIB_BANDWIDTH = 0
|
HAMLIB_BANDWIDTH = 0
|
||||||
# -------------------------
|
# -------------------------
|
||||||
# FreeDV Defaults
|
# FreeDV Defaults
|
||||||
|
@ -74,7 +74,7 @@ AUDIO_INPUT_DEVICES = []
|
||||||
AUDIO_OUTPUT_DEVICES = []
|
AUDIO_OUTPUT_DEVICES = []
|
||||||
AUDIO_INPUT_DEVICE = -2
|
AUDIO_INPUT_DEVICE = -2
|
||||||
AUDIO_OUTPUT_DEVICE = -2
|
AUDIO_OUTPUT_DEVICE = -2
|
||||||
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0]
|
BUFFER_OVERFLOW_COUNTER = [0, 0, 0, 0, 0]
|
||||||
|
|
||||||
AUDIO_RMS = 0
|
AUDIO_RMS = 0
|
||||||
FFT = [0]
|
FFT = [0]
|
||||||
|
@ -94,11 +94,12 @@ ARQ_TRANSMISSION_PERCENT = 0
|
||||||
ARQ_SPEED_LEVEL = 0
|
ARQ_SPEED_LEVEL = 0
|
||||||
TOTAL_BYTES = 0
|
TOTAL_BYTES = 0
|
||||||
|
|
||||||
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||||
TNC_STATE = 'IDLE'
|
TNC_STATE = "IDLE"
|
||||||
ARQ_STATE = False
|
ARQ_STATE = False
|
||||||
ARQ_SESSION = False
|
ARQ_SESSION = False
|
||||||
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed
|
# disconnected, connecting, connected, disconnecting, failed
|
||||||
|
ARQ_SESSION_STATE = "disconnected"
|
||||||
|
|
||||||
# BEACON STATE
|
# BEACON STATE
|
||||||
BEACON_STATE = False
|
BEACON_STATE = False
|
||||||
|
@ -108,8 +109,8 @@ BEACON_PAUSE = False
|
||||||
RX_BUFFER = []
|
RX_BUFFER = []
|
||||||
RX_MSG_BUFFER = []
|
RX_MSG_BUFFER = []
|
||||||
RX_BURST_BUFFER = []
|
RX_BURST_BUFFER = []
|
||||||
RX_FRAME_BUFFER = b''
|
RX_FRAME_BUFFER = b""
|
||||||
#RX_BUFFER_SIZE = 0
|
# RX_BUFFER_SIZE = 0
|
||||||
|
|
||||||
# ------- HEARD STATIOS BUFFER
|
# ------- HEARD STATIOS BUFFER
|
||||||
HEARD_STATIONS = []
|
HEARD_STATIONS = []
|
||||||
|
|
Loading…
Reference in a new issue