mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #203 from DJ2LS/refactor_N2KIQ-202205-2
Refactor TNC for 2022-May
This commit is contained in:
commit
98fcd8f3b9
|
@ -7,6 +7,7 @@ import sys
|
|||
import time
|
||||
|
||||
import pytest
|
||||
import structlog
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
sys.path.insert(0, "..")
|
||||
|
@ -21,19 +22,28 @@ import test_tnc_ISS as iss
|
|||
@pytest.mark.parametrize("command", ["CQ", "PING", "BEACON"])
|
||||
def test_tnc(command):
|
||||
|
||||
iss_proc = multiprocessing.Process(target=iss.t_arq_iss, args=[command])
|
||||
irs_proc = multiprocessing.Process(target=irs.t_arq_irs, args=[command])
|
||||
# print("Starting threads.")
|
||||
iss_proc.start()
|
||||
irs_proc.start()
|
||||
# This test is currently a little inconsistent.
|
||||
iss_proc: multiprocessing.Process = None
|
||||
irs_proc: multiprocessing.Process = None
|
||||
for _ in range(3):
|
||||
iss_proc = multiprocessing.Process(target=iss.t_arq_iss, args=[command])
|
||||
irs_proc = multiprocessing.Process(target=irs.t_arq_irs, args=[command])
|
||||
# print("Starting threads.")
|
||||
iss_proc.start()
|
||||
irs_proc.start()
|
||||
|
||||
time.sleep(12)
|
||||
time.sleep(12)
|
||||
|
||||
# print("Terminating threads.")
|
||||
irs_proc.terminate()
|
||||
iss_proc.terminate()
|
||||
irs_proc.join()
|
||||
iss_proc.join()
|
||||
# print("Terminating threads.")
|
||||
irs_proc.terminate()
|
||||
iss_proc.terminate()
|
||||
irs_proc.join()
|
||||
iss_proc.join()
|
||||
|
||||
if iss_proc.exitcode == 0 and irs_proc.exitcode == 0:
|
||||
break
|
||||
|
||||
structlog.get_logger(__name__).error("Retrying.")
|
||||
|
||||
for idx in range(2):
|
||||
try:
|
||||
|
|
|
@ -28,7 +28,9 @@ def get_audio_devices():
|
|||
proxy_input_devices = manager.list()
|
||||
proxy_output_devices = manager.list()
|
||||
# print(multiprocessing.get_start_method())
|
||||
proc = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
|
||||
proc = multiprocessing.Process(
|
||||
target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)
|
||||
)
|
||||
proc.start()
|
||||
proc.join()
|
||||
|
||||
|
@ -48,7 +50,7 @@ def fetch_audio_devices(input_devices, output_devices):
|
|||
"""
|
||||
devices = sd.query_devices(device=None, kind=None)
|
||||
for index, device in enumerate(devices):
|
||||
# we need to do a try exception, because for windows there's no audio device range
|
||||
# Use a try/except block beacuse Windows doesn't have an audio device range
|
||||
try:
|
||||
name = device["name"]
|
||||
|
||||
|
|
151
tnc/codec2.py
151
tnc/codec2.py
|
@ -1,8 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Python interface to the C-language codec2 library.
|
||||
"""
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# pylint: disable=invalid-name, line-too-long, c-extension-no-member
|
||||
# pylint: disable=import-outside-toplevel
|
||||
# pylint: disable=import-outside-toplevel, attribute-defined-outside-init
|
||||
|
||||
import ctypes
|
||||
import glob
|
||||
|
@ -14,19 +16,21 @@ from threading import Lock
|
|||
import numpy as np
|
||||
import structlog
|
||||
|
||||
log = structlog.get_logger("codec2")
|
||||
|
||||
# Enum for codec2 modes
|
||||
class FREEDV_MODE(Enum):
|
||||
"""
|
||||
Enumeration for codec2 modes and names
|
||||
"""
|
||||
fsk_ldpc_0 = 200
|
||||
fsk_ldpc_1 = 201
|
||||
fsk_ldpc = 9
|
||||
|
||||
allmodes = 255
|
||||
datac0 = 14
|
||||
datac1 = 10
|
||||
datac3 = 12
|
||||
allmodes = 255
|
||||
fsk_ldpc = 9
|
||||
fsk_ldpc_0 = 200
|
||||
fsk_ldpc_1 = 201
|
||||
|
||||
|
||||
# Function for returning the mode value
|
||||
|
@ -35,20 +39,20 @@ def freedv_get_mode_value_by_name(mode: str) -> int:
|
|||
Get the codec2 mode by entering its string
|
||||
|
||||
Args:
|
||||
mode:
|
||||
mode: String representation of the codec2 mode.
|
||||
|
||||
Returns:
|
||||
int
|
||||
"""
|
||||
return FREEDV_MODE[mode].value
|
||||
return FREEDV_MODE[mode.lower()].value
|
||||
|
||||
|
||||
# Function for returning the mode name
|
||||
def freedv_get_mode_name_by_value(mode: int) -> str:
|
||||
"""
|
||||
get the codec2 mode name as string
|
||||
Get the codec2 mode name as string
|
||||
Args:
|
||||
mode:
|
||||
mode: Integer value of the codec2 mode.
|
||||
|
||||
Returns:
|
||||
string
|
||||
|
@ -62,7 +66,7 @@ if hasattr(sys, "_MEIPASS"):
|
|||
else:
|
||||
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":
|
||||
files = glob.glob(r"**/*libcodec2*", recursive=True)
|
||||
files.append("libcodec2.so")
|
||||
|
@ -77,14 +81,14 @@ api = None
|
|||
for file in files:
|
||||
try:
|
||||
api = ctypes.CDLL(file)
|
||||
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
|
||||
log.info("[C2 ] Libcodec2 loaded", path=file)
|
||||
break
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=err)
|
||||
except OSError as err:
|
||||
log.warning("[C2 ] Libcodec2 found but not loaded", path=file, e=err)
|
||||
|
||||
# Quit module if codec2 cant be loaded
|
||||
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)
|
||||
|
||||
# ctypes function init
|
||||
|
@ -92,66 +96,67 @@ if api is None or "api" not in locals():
|
|||
# api.freedv_set_tuning_range.restype = ctypes.c_int
|
||||
# api.freedv_set_tuning_range.argype = [ctypes.c_void_p, ctypes.c_float, ctypes.c_float]
|
||||
|
||||
api.freedv_open.argype = [ctypes.c_int]
|
||||
api.freedv_open.argype = [ctypes.c_int] # type: ignore
|
||||
api.freedv_open.restype = ctypes.c_void_p
|
||||
|
||||
api.freedv_open_advanced.argtype = [ctypes.c_int, ctypes.c_void_p]
|
||||
api.freedv_open_advanced.argtype = [ctypes.c_int, ctypes.c_void_p] # type: ignore
|
||||
api.freedv_open_advanced.restype = ctypes.c_void_p
|
||||
|
||||
api.freedv_get_bits_per_modem_frame.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_bits_per_modem_frame.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_bits_per_modem_frame.restype = ctypes.c_int
|
||||
|
||||
api.freedv_nin.argtype = [ctypes.c_void_p]
|
||||
api.freedv_nin.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_nin.restype = ctypes.c_int
|
||||
|
||||
api.freedv_rawdatarx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
api.freedv_rawdatarx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] # type: ignore
|
||||
api.freedv_rawdatarx.restype = ctypes.c_int
|
||||
|
||||
api.freedv_rawdatatx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
api.freedv_rawdatatx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] # type: ignore
|
||||
api.freedv_rawdatatx.restype = ctypes.c_int
|
||||
|
||||
api.freedv_rawdatapostambletx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
api.freedv_rawdatapostambletx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] # type: ignore
|
||||
api.freedv_rawdatapostambletx.restype = ctypes.c_int
|
||||
|
||||
api.freedv_rawdatapreambletx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
api.freedv_rawdatapreambletx.argtype = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] # type: ignore
|
||||
api.freedv_rawdatapreambletx.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
|
||||
|
||||
api.freedv_set_frames_per_burst.argtype = [ctypes.c_void_p, ctypes.c_int]
|
||||
api.freedv_set_frames_per_burst.argtype = [ctypes.c_void_p, ctypes.c_int] # type: ignore
|
||||
api.freedv_set_frames_per_burst.restype = ctypes.c_void_p
|
||||
|
||||
api.freedv_get_rx_status.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_rx_status.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_rx_status.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_modem_stats.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
|
||||
api.freedv_get_modem_stats.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_modem_stats.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_n_tx_postamble_modem_samples.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_n_tx_postamble_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_n_tx_postamble_modem_samples.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_n_tx_preamble_modem_samples.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_n_tx_preamble_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_n_tx_preamble_modem_samples.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_n_tx_modem_samples.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_n_tx_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_n_tx_modem_samples.restype = ctypes.c_int
|
||||
|
||||
api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p]
|
||||
api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||
api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
|
||||
|
||||
api.FREEDV_FS_8000 = 8000
|
||||
api.FREEDV_MODE_DATAC1 = 10
|
||||
api.FREEDV_MODE_DATAC3 = 12
|
||||
api.FREEDV_MODE_DATAC0 = 14
|
||||
api.FREEDV_MODE_FSK_LDPC = 9
|
||||
api.FREEDV_FS_8000 = 8000 # type: ignore
|
||||
api.FREEDV_MODE_DATAC1 = 10 # type: ignore
|
||||
api.FREEDV_MODE_DATAC3 = 12 # type: ignore
|
||||
api.FREEDV_MODE_DATAC0 = 14 # type: ignore
|
||||
api.FREEDV_MODE_FSK_LDPC = 9 # type: ignore
|
||||
|
||||
|
||||
# -------------------------------- FSK LDPC MODE SETTINGS
|
||||
|
||||
# Advanced structure for fsk modes
|
||||
|
||||
class ADVANCED(ctypes.Structure):
|
||||
""" """
|
||||
"""Advanced structure for fsk modes"""
|
||||
|
||||
_fields_ = [
|
||||
("interleave_frames", ctypes.c_int),
|
||||
("M", ctypes.c_int),
|
||||
|
@ -163,6 +168,7 @@ class ADVANCED(ctypes.Structure):
|
|||
]
|
||||
|
||||
|
||||
# pylint: disable=pointless-string-statement
|
||||
"""
|
||||
adv.interleave_frames = 0 # max amplitude
|
||||
adv.M = 2 # number of fsk tones 2/4
|
||||
|
@ -185,7 +191,7 @@ H_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
|
|||
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
|
||||
"""
|
||||
# --------------- 2 FSK H_128_256_5, 16 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED()
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED() # type: ignore
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.M = 4
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 100
|
||||
|
@ -195,7 +201,7 @@ api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 # 200
|
|||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = "H_128_256_5".encode("utf-8") # code word
|
||||
|
||||
# --------------- 4 H_256_512_4, 7 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED()
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED() # type: ignore
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.interleave_frames = 0
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.M = 4
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.Rs = 100
|
||||
|
@ -214,9 +220,9 @@ MODEM_STATS_MAX_F_HZ = 4000
|
|||
MODEM_STATS_MAX_F_EST = 4
|
||||
|
||||
|
||||
# Modem stats structure
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
""" """
|
||||
"""Modem statistics structure"""
|
||||
|
||||
_fields_ = [
|
||||
("Nc", ctypes.c_int),
|
||||
("snr_est", ctypes.c_float),
|
||||
|
@ -232,18 +238,18 @@ class MODEMSTATS(ctypes.Structure):
|
|||
("uw_fails", ctypes.c_int),
|
||||
("neyetr", ctypes.c_int), # How many eye traces are plotted
|
||||
("neyesamp", ctypes.c_int), # How many samples in the eye diagram
|
||||
("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), # How many samples in the eye diagram
|
||||
("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)),
|
||||
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
|
||||
]
|
||||
|
||||
|
||||
# Return code flags for freedv_get_rx_status() function
|
||||
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
|
||||
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
|
||||
api.FREEDV_RX_BITS = 0x4 # data bits have been returned
|
||||
api.FREEDV_RX_BIT_ERRORS = 0x8 # FEC may not have corrected all bit errors (not all parity checks OK)
|
||||
api.FREEDV_RX_TRIAL_SYNC = 0x1 # type: ignore # demodulator has trial sync
|
||||
api.FREEDV_RX_SYNC = 0x2 # type: ignore # demodulator has sync
|
||||
api.FREEDV_RX_BITS = 0x4 # type: ignore # data bits have been returned
|
||||
api.FREEDV_RX_BIT_ERRORS = 0x8 # type: ignore # FEC may not have corrected all bit errors (not all parity checks OK)
|
||||
|
||||
api.rx_sync_flags_to_text = [
|
||||
api.rx_sync_flags_to_text = [ # type: ignore
|
||||
"----",
|
||||
"---T",
|
||||
"--S-",
|
||||
|
@ -259,13 +265,14 @@ api.rx_sync_flags_to_text = [
|
|||
"EB--",
|
||||
"EB-T",
|
||||
"EBS-",
|
||||
"EBST"]
|
||||
"EBST",
|
||||
]
|
||||
|
||||
|
||||
# Audio buffer ---------------------------------------------------------
|
||||
class audio_buffer:
|
||||
"""
|
||||
Thread safe audio buffer, which fits to need of codec2
|
||||
Thread-safe audio buffer, which fits the needs of codec2
|
||||
|
||||
made by David Rowe, VK5DGR
|
||||
"""
|
||||
|
@ -273,7 +280,7 @@ class audio_buffer:
|
|||
# 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
|
||||
def __init__(self, size):
|
||||
structlog.get_logger("structlog").debug("[C2 ] Creating audio buffer", size=size)
|
||||
log.debug("[C2 ] Creating audio buffer", size=size)
|
||||
self.size = size
|
||||
self.buffer = np.zeros(size, dtype=np.int16)
|
||||
self.nbuffer = 0
|
||||
|
@ -292,7 +299,7 @@ class audio_buffer:
|
|||
self.mutex.acquire()
|
||||
# Add samples at the end of the buffer
|
||||
assert self.nbuffer + len(samples) <= self.size
|
||||
self.buffer[self.nbuffer:self.nbuffer + len(samples)] = samples
|
||||
self.buffer[self.nbuffer : self.nbuffer + len(samples)] = samples
|
||||
self.nbuffer += len(samples)
|
||||
self.mutex.release()
|
||||
|
||||
|
@ -308,30 +315,34 @@ class audio_buffer:
|
|||
self.mutex.acquire()
|
||||
# Remove samples from the start of the buffer
|
||||
self.nbuffer -= size
|
||||
self.buffer[:self.nbuffer] = self.buffer[size:size + self.nbuffer]
|
||||
self.buffer[: self.nbuffer] = self.buffer[size : size + self.nbuffer]
|
||||
assert self.nbuffer >= 0
|
||||
self.mutex.release()
|
||||
|
||||
|
||||
# Resampler ---------------------------------------------------------
|
||||
|
||||
api.FDMDV_OS_48 = 6 # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = 48 # number of OS filter taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = api.FDMDV_OS_TAPS_48K // api.FDMDV_OS_48 # number of OS filter taps at 8kHz
|
||||
api.fdmdv_8_to_48_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
|
||||
api.fdmdv_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
|
||||
# Oversampling rate
|
||||
api.FDMDV_OS_48 = 6 # type: ignore
|
||||
# Number of oversampling taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48K = 48 # type: ignore
|
||||
# Number of oversampling filter taps at 8kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = api.FDMDV_OS_TAPS_48K // api.FDMDV_OS_48 # type: ignore
|
||||
api.fdmdv_8_to_48_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] # type: ignore
|
||||
api.fdmdv_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] # type: ignore
|
||||
|
||||
|
||||
class resampler:
|
||||
"""
|
||||
Re-sampler class
|
||||
"""
|
||||
|
||||
# Re-sample an array of variable length, we just store the filter memories here
|
||||
MEM8 = api.FDMDV_OS_TAPS_48_8K
|
||||
MEM48 = api.FDMDV_OS_TAPS_48K
|
||||
|
||||
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_mem48 = np.zeros(self.MEM48)
|
||||
|
||||
|
@ -347,21 +358,21 @@ class resampler:
|
|||
"""
|
||||
assert in48.dtype == np.int16
|
||||
# Length of input vector must be an integer multiple of api.FDMDV_OS_48
|
||||
assert len(in48) % api.FDMDV_OS_48 == 0
|
||||
assert len(in48) % api.FDMDV_OS_48 == 0 # type: ignore
|
||||
|
||||
# Concatenate filter memory and input samples
|
||||
in48_mem = np.zeros(self.MEM48 + len(in48), dtype=np.int16)
|
||||
in48_mem[:self.MEM48] = self.filter_mem48
|
||||
in48_mem[self.MEM48:] = in48
|
||||
in48_mem[: self.MEM48] = self.filter_mem48
|
||||
in48_mem[self.MEM48 :] = in48
|
||||
|
||||
# In C: pin48=&in48_mem[MEM48]
|
||||
pin48 = ctypes.byref(np.ctypeslib.as_ctypes(in48_mem), 2 * self.MEM48)
|
||||
n8 = int(len(in48) / api.FDMDV_OS_48)
|
||||
n8 = int(len(in48) / api.FDMDV_OS_48) # type: ignore
|
||||
out8 = np.zeros(n8, dtype=np.int16)
|
||||
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8)
|
||||
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8) # type: ignore
|
||||
|
||||
# Store memory for next time
|
||||
self.filter_mem48 = in48_mem[:self.MEM48]
|
||||
self.filter_mem48 = in48_mem[: self.MEM48]
|
||||
|
||||
return out8
|
||||
|
||||
|
@ -379,15 +390,15 @@ class resampler:
|
|||
|
||||
# Concatenate filter memory and input samples
|
||||
in8_mem = np.zeros(self.MEM8 + len(in8), dtype=np.int16)
|
||||
in8_mem[:self.MEM8] = self.filter_mem8
|
||||
in8_mem[self.MEM8:] = in8
|
||||
in8_mem[: self.MEM8] = self.filter_mem8
|
||||
in8_mem[self.MEM8 :] = in8
|
||||
|
||||
# In C: pin8=&in8_mem[MEM8]
|
||||
pin8 = ctypes.byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8)
|
||||
out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16)
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8))
|
||||
out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16) # type: ignore
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8)) # type: ignore
|
||||
|
||||
# Store memory for next time
|
||||
self.filter_mem8 = in8_mem[:self.MEM8]
|
||||
self.filter_mem8 = in8_mem[: self.MEM8]
|
||||
|
||||
return out48
|
||||
|
|
|
@ -55,6 +55,7 @@ class DAEMON:
|
|||
Daemon class
|
||||
|
||||
"""
|
||||
|
||||
log = structlog.get_logger("DAEMON")
|
||||
|
||||
def __init__(self):
|
||||
|
@ -62,10 +63,14 @@ class DAEMON:
|
|||
self.crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library
|
||||
|
||||
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_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()
|
||||
|
||||
worker = threading.Thread(target=self.worker, name="WORKER", daemon=True)
|
||||
|
@ -78,10 +83,15 @@ class DAEMON:
|
|||
while True:
|
||||
try:
|
||||
if not static.TNCSTARTED:
|
||||
static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices()
|
||||
(
|
||||
static.AUDIO_INPUT_DEVICES,
|
||||
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)
|
||||
self.log.error(
|
||||
"[DMN] update_audio_devices: Exception gathering audio devices:",
|
||||
e=err1,
|
||||
)
|
||||
time.sleep(1)
|
||||
|
||||
def update_serial_devices(self):
|
||||
|
@ -98,13 +108,17 @@ class DAEMON:
|
|||
crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
|
||||
crc_hwid = crc_hwid.hex()
|
||||
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
|
||||
time.sleep(1)
|
||||
except Exception as err1:
|
||||
self.log.error("[DMN] update_serial_devices: Exception gathering serial devices:", e=err1)
|
||||
# print(e)
|
||||
self.log.error(
|
||||
"[DMN] update_serial_devices: Exception gathering serial devices:",
|
||||
e=err1,
|
||||
)
|
||||
|
||||
def worker(self):
|
||||
"""
|
||||
|
@ -239,7 +253,7 @@ class DAEMON:
|
|||
|
||||
self.log.info("[DMN] TNC started", path="binary")
|
||||
except FileNotFoundError as err1:
|
||||
self.log.error("[DMN] worker: Exception:", e=err1)
|
||||
self.log.info("[DMN] worker: ", e=err1)
|
||||
command = []
|
||||
if sys.platform in ["linux", "darwin"]:
|
||||
command.append("python3")
|
||||
|
@ -298,9 +312,18 @@ class DAEMON:
|
|||
import rigdummy as rig
|
||||
|
||||
hamlib = rig.radio()
|
||||
hamlib.open_rig(devicename=devicename, 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.open_rig(
|
||||
devicename=devicename,
|
||||
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
|
||||
|
||||
|
@ -310,12 +333,9 @@ class DAEMON:
|
|||
if pttstate:
|
||||
self.log.info("[DMN] Hamlib PTT", status="SUCCESS")
|
||||
response = {"command": "test_hamlib", "result": "SUCCESS"}
|
||||
elif not pttstate:
|
||||
else:
|
||||
self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS")
|
||||
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
|
||||
else:
|
||||
self.log.error("[DMN] Hamlib PTT", status="FAILED")
|
||||
response = {"command": "test_hamlib", "result": "FAILED"}
|
||||
|
||||
hamlib.set_ptt(False)
|
||||
hamlib.close_rig()
|
||||
|
@ -334,7 +354,13 @@ if __name__ == "__main__":
|
|||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
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-65535",
|
||||
type=int,
|
||||
)
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
static.DAEMONPORT = ARGS.socket_port
|
||||
|
@ -344,7 +370,13 @@ if __name__ == "__main__":
|
|||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
|
||||
|
||||
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"]:
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
|
||||
|
@ -359,16 +391,25 @@ if __name__ == "__main__":
|
|||
mainlog.info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
|
||||
# https://stackoverflow.com/a/16641793
|
||||
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.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as err:
|
||||
mainlog.error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err)
|
||||
mainlog.error(
|
||||
"[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err
|
||||
)
|
||||
sys.exit(1)
|
||||
daemon = DAEMON()
|
||||
|
||||
mainlog.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:
|
||||
time.sleep(1)
|
||||
|
|
1550
tnc/data_handler.py
1550
tnc/data_handler.py
File diff suppressed because it is too large
Load diff
104
tnc/helpers.py
104
tnc/helpers.py
|
@ -10,6 +10,8 @@ import crcengine
|
|||
import static
|
||||
import structlog
|
||||
|
||||
log = structlog.get_logger("helpers")
|
||||
|
||||
|
||||
def wait(seconds: float) -> bool:
|
||||
"""
|
||||
|
@ -78,13 +80,15 @@ def get_crc_24(data) -> bytes:
|
|||
Returns:
|
||||
CRC-24 (OpenPGP) of the provided data as bytes
|
||||
"""
|
||||
crc_algorithm = crcengine.create(0x864cfb,
|
||||
24,
|
||||
0xb704ce,
|
||||
ref_in=False,
|
||||
ref_out=False,
|
||||
xor_out=0,
|
||||
name="crc-24-openpgp")
|
||||
crc_algorithm = crcengine.create(
|
||||
0x864CFB,
|
||||
24,
|
||||
0xB704CE,
|
||||
ref_in=False,
|
||||
ref_out=False,
|
||||
xor_out=0,
|
||||
name="crc-24-openpgp",
|
||||
)
|
||||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(3, byteorder="big")
|
||||
return crc_data
|
||||
|
@ -125,17 +129,37 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
|||
"""
|
||||
# check if buffer empty
|
||||
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
|
||||
else:
|
||||
for i in range(len(static.HEARD_STATIONS)):
|
||||
# Update callsign with new timestamp
|
||||
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
||||
static.HEARD_STATIONS[i] = [dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
|
||||
static.HEARD_STATIONS[i] = [
|
||||
dxcallsign,
|
||||
dxgrid,
|
||||
int(time.time()),
|
||||
datatype,
|
||||
snr,
|
||||
offset,
|
||||
frequency,
|
||||
]
|
||||
break
|
||||
# Insert if nothing found
|
||||
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
|
||||
|
||||
|
||||
|
@ -175,16 +199,25 @@ def callsign_to_bytes(callsign) -> bytes:
|
|||
# Try converting to bytestring if possible type string
|
||||
try:
|
||||
callsign = bytes(callsign, "utf-8")
|
||||
except TypeError as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=err)
|
||||
except TypeError:
|
||||
# This is expected depending on the type of the `callsign` argument.
|
||||
# log.debug("[HLP] callsign_to_bytes: Error converting callsign to bytes:", e=err)
|
||||
pass
|
||||
except Exception as err:
|
||||
log.debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||
|
||||
# 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
|
||||
# (stripping "-" out of the callsign)
|
||||
callsign = callsign.split(b"-")
|
||||
ssid = 0
|
||||
try:
|
||||
ssid = int(callsign[1])
|
||||
except IndexError as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||
except IndexError:
|
||||
# This is expected when callsign doesn't have a dash.
|
||||
# log.debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||
pass
|
||||
except Exception as err:
|
||||
log.debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||
|
||||
# callsign = callsign[0]
|
||||
# bytestring = bytearray(8)
|
||||
|
@ -247,7 +280,8 @@ def bytes_to_callsign(bytestring: bytes) -> 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:
|
||||
callsign: Callsign which we want to check
|
||||
|
@ -258,13 +292,17 @@ def check_callsign(callsign: bytes, crc_to_check: bytes):
|
|||
False
|
||||
"""
|
||||
|
||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Checking:", callsign=callsign)
|
||||
# print(callsign)
|
||||
log.debug("[HLP] check_callsign: Checking:", callsign=callsign)
|
||||
try:
|
||||
# We want the callsign without SSID
|
||||
callsign = callsign.split(b"-")[0]
|
||||
|
||||
except IndexError:
|
||||
# This is expected when `callsign` doesn't have a dash.
|
||||
pass
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=err)
|
||||
log.debug("[HLP] check_callsign: Error callsign SSID to integer:", e=err)
|
||||
|
||||
for ssid in static.SSID_LIST:
|
||||
call_with_ssid = bytearray(callsign)
|
||||
|
@ -292,24 +330,24 @@ def encode_grid(grid):
|
|||
|
||||
grid = grid.upper() # upper case to be save
|
||||
|
||||
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_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_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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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 <<= 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
|
||||
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
|
||||
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
|
||||
|
||||
return out_code_word.to_bytes(length=4, byteorder="big")
|
||||
|
||||
|
@ -351,20 +389,22 @@ def encode_call(call):
|
|||
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
|
||||
|
||||
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
|
||||
|
||||
call = call.upper() # upper case to be save
|
||||
|
||||
for x in call:
|
||||
int_val = ord(x) - 48 # -48 reduce bits, begin with first number utf8 table
|
||||
for char in call:
|
||||
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 |= (int_val & 0b111111) # bit OR adds the new char, masked with AND 0b111111
|
||||
|
||||
out_code_word |= (
|
||||
int_val & 0b111111
|
||||
) # bit OR adds the new char, masked with AND 0b111111
|
||||
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
|
||||
out_code_word |= ord(call[-1]) & 0b111111 # add the SSID uncoded only 0 - 63
|
||||
|
||||
return out_code_word.to_bytes(length=6, byteorder="big")
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ import structlog
|
|||
|
||||
|
||||
# https://www.structlog.org/en/stable/standard-library.html
|
||||
def setup_logging(filename):
|
||||
def setup_logging(filename: str = "", level: str = "DEBUG"):
|
||||
"""
|
||||
|
||||
Args:
|
||||
filename:
|
||||
|
||||
Returns:
|
||||
level:str: Log level to output, possible values are:
|
||||
"CRITICAL", "FATAL", "ERROR", "WARNING", "WARN", "INFO", "DEBUG"
|
||||
|
||||
"""
|
||||
|
||||
|
@ -40,12 +40,12 @@ def setup_logging(filename):
|
|||
},
|
||||
"handlers": {
|
||||
"default": {
|
||||
"level": "DEBUG",
|
||||
"level": level,
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "colored",
|
||||
},
|
||||
"file": {
|
||||
"level": "DEBUG",
|
||||
"level": level,
|
||||
"class": "logging.handlers.WatchedFileHandler",
|
||||
"filename": f"{filename}.log",
|
||||
"formatter": "plain",
|
||||
|
@ -53,8 +53,8 @@ def setup_logging(filename):
|
|||
},
|
||||
"loggers": {
|
||||
"": {
|
||||
"handlers": ["default", "file"],
|
||||
"level": "DEBUG",
|
||||
"handlers": ["default", "file"] if filename else ["default"],
|
||||
"level": level,
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
|
|
227
tnc/main.py
227
tnc/main.py
|
@ -23,6 +23,8 @@ import modem
|
|||
import static
|
||||
import structlog
|
||||
|
||||
log = structlog.get_logger("main")
|
||||
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
"""
|
||||
|
@ -42,35 +44,186 @@ def signal_handler(sig, frame):
|
|||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# we need to run this on Windows for multiprocessing support
|
||||
# This is for Windows multiprocessing support
|
||||
multiprocessing.freeze_support()
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
|
||||
PARSER.add_argument("--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str)
|
||||
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)
|
||||
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("--tx", dest="audio_output_device", 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_bandwidth_mode", action="store_true", help="Enable low bandwidth 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)
|
||||
PARSER.add_argument(
|
||||
"--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str
|
||||
)
|
||||
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,
|
||||
)
|
||||
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(
|
||||
"--tx",
|
||||
dest="audio_output_device",
|
||||
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_bandwidth_mode",
|
||||
action="store_true",
|
||||
help="Enable low bandwidth 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()
|
||||
|
||||
|
@ -117,7 +270,13 @@ if __name__ == "__main__":
|
|||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
|
||||
|
||||
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"]:
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
|
||||
|
@ -126,9 +285,11 @@ if __name__ == "__main__":
|
|||
os.makedirs(logging_path)
|
||||
log_handler.setup_logging(logging_path)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").error("[DMN] logger init error", exception=err)
|
||||
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
|
||||
data_handler.DATA()
|
||||
|
@ -138,17 +299,19 @@ if __name__ == "__main__":
|
|||
|
||||
# --------------------------------------------START CMD SERVER
|
||||
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
|
||||
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.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
|
||||
log.error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
|
||||
sys.exit(1)
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
|
742
tnc/modem.py
742
tnc/modem.py
File diff suppressed because it is too large
Load diff
85
tnc/rig.py
85
tnc/rig.py
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import re
|
||||
|
@ -8,6 +6,8 @@ import sys
|
|||
|
||||
import structlog
|
||||
|
||||
mainlog = structlog.get_logger("rig")
|
||||
|
||||
# set global hamlib version
|
||||
hamlib_version = 0
|
||||
|
||||
|
@ -24,7 +24,7 @@ try:
|
|||
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
||||
|
||||
# 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 +
|
||||
sys.path.append("/usr/local/lib/")
|
||||
|
@ -49,32 +49,43 @@ try:
|
|||
|
||||
min_hamlib_version = 4.1
|
||||
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:
|
||||
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
||||
mainlog.warning(
|
||||
"[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version
|
||||
)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=err)
|
||||
|
||||
mainlog.warning("[RIG] Python Hamlib binding not found", error=err)
|
||||
try:
|
||||
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl")
|
||||
rigctl = subprocess.Popen("rigctl -V", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
||||
|
||||
mainlog.warning("[RIG] Trying to open rigctl")
|
||||
rigctl = subprocess.Popen(
|
||||
"rigctl -V",
|
||||
shell=True,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
hamlib_version = rigctl.stdout.readline()
|
||||
hamlib_version = hamlib_version.split(" ")
|
||||
if hamlib_version[1] != "Hamlib":
|
||||
raise Exception from err
|
||||
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
|
||||
|
||||
sys.exit()
|
||||
if hamlib_version[1] == "Hamlib":
|
||||
mainlog.warning(
|
||||
"[RIG] Rigctl found! Please try using this", version=hamlib_version[2]
|
||||
)
|
||||
sys.exit()
|
||||
else:
|
||||
raise Exception
|
||||
except Exception as err1:
|
||||
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=err1)
|
||||
|
||||
mainlog.critical("[RIG] HAMLIB NOT INSTALLED", error=err1)
|
||||
hamlib_version = 0
|
||||
sys.exit()
|
||||
|
||||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
log = structlog.get_logger(__name__)
|
||||
|
||||
def __init__(self):
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
|
@ -87,7 +98,19 @@ class radio:
|
|||
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):
|
||||
def open_rig(
|
||||
self,
|
||||
devicename,
|
||||
deviceport,
|
||||
hamlib_ptt_type,
|
||||
serialspeed,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
rigctld_port,
|
||||
rigctld_ip,
|
||||
):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
@ -102,12 +125,11 @@ class radio:
|
|||
rigctld_port:
|
||||
rigctld_ip:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self.devicename = devicename
|
||||
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.pttport = str(pttport)
|
||||
self.data_bits = str(data_bits)
|
||||
|
@ -122,7 +144,7 @@ class radio:
|
|||
try:
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except Exception:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
|
||||
self.log.error("[RIG] Hamlib: rig not supported...")
|
||||
self.devicenumber = 0
|
||||
|
||||
self.my_rig = Hamlib.Rig(self.devicenumber)
|
||||
|
@ -172,7 +194,16 @@ class radio:
|
|||
else: # self.hamlib_ptt_type == "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()
|
||||
atexit.register(self.my_rig.close)
|
||||
|
@ -184,11 +215,11 @@ class radio:
|
|||
error = error[1]
|
||||
|
||||
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"
|
||||
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url)
|
||||
self.log.error("[RIG] HELP:", check=help_url)
|
||||
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
|
||||
self.set_ptt(False)
|
||||
|
@ -200,7 +231,9 @@ class radio:
|
|||
return True
|
||||
|
||||
except Exception as err2:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0])
|
||||
self.log.error(
|
||||
"[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0]
|
||||
)
|
||||
return False
|
||||
|
||||
def get_frequency(self):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
# Intially created by Franco Spinelli, IW2DHW, 01/2022
|
||||
# Updated by DJ2LS
|
||||
#
|
||||
|
@ -22,6 +21,9 @@ hamlib_version = 0
|
|||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
log = structlog.get_logger("radio (rigctl)")
|
||||
|
||||
def __init__(self):
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
|
@ -35,7 +37,19 @@ class radio:
|
|||
self.handshake = ""
|
||||
self.cmd = ""
|
||||
|
||||
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:
|
||||
|
@ -55,7 +69,8 @@ class radio:
|
|||
"""
|
||||
self.devicename = devicename
|
||||
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.pttport = pttport
|
||||
self.data_bits = data_bits
|
||||
|
@ -71,13 +86,14 @@ class radio:
|
|||
# get devicenumber by looking for deviceobject in Hamlib module
|
||||
try:
|
||||
import Hamlib
|
||||
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except Exception as err:
|
||||
if int(self.devicename):
|
||||
self.devicenumber = int(self.devicename)
|
||||
else:
|
||||
self.devicenumber = 6 # dummy
|
||||
structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=err)
|
||||
self.log.warning("[RIGCTL] Radio not found. Using DUMMY!", error=err)
|
||||
|
||||
# set deviceport to dummy port, if we selected dummy model
|
||||
if self.devicenumber in {1, 6}:
|
||||
|
@ -88,10 +104,23 @@ class radio:
|
|||
# select precompiled executable for win32/win64 rigctl
|
||||
# this is really a hack...somewhen we need a native hamlib integration for windows
|
||||
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:
|
||||
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
|
||||
# il set e t per il get
|
||||
|
@ -103,7 +132,9 @@ class radio:
|
|||
def get_frequency(self):
|
||||
""" """
|
||||
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)
|
||||
freq = sw_proc.communicate()[0]
|
||||
# print("get_frequency", freq, sw_proc.communicate())
|
||||
|
@ -146,7 +177,9 @@ class radio:
|
|||
def get_ptt(self):
|
||||
""" """
|
||||
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)
|
||||
status = sw_proc.communicate()[0]
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#
|
||||
# modified and adjusted to FreeDATA needs by DJ2LS
|
||||
|
||||
import logging
|
||||
import socket
|
||||
import time
|
||||
|
||||
|
@ -14,12 +13,15 @@ import structlog
|
|||
hamlib_version = 0
|
||||
|
||||
|
||||
class radio():
|
||||
class radio:
|
||||
"""rigctld (hamlib) communication class"""
|
||||
|
||||
# Note: This is a massive hack.
|
||||
|
||||
log = structlog.get_logger("radio (rigctld)")
|
||||
|
||||
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
||||
""" Open a connection to rigctld, and test it for validity """
|
||||
"""Open a connection to rigctld, and test it for validity"""
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# self.sock.settimeout(timeout)
|
||||
|
||||
|
@ -28,7 +30,19 @@ class radio():
|
|||
self.port = port
|
||||
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:
|
||||
|
@ -50,10 +64,12 @@ class radio():
|
|||
self.port = int(rigctld_port)
|
||||
|
||||
if self.connect():
|
||||
logging.debug("Rigctl intialized")
|
||||
self.log.debug("Rigctl initialized")
|
||||
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
|
||||
|
||||
def connect(self):
|
||||
|
@ -62,12 +78,19 @@ class radio():
|
|||
try:
|
||||
self.connection = socket.create_connection((self.hostname, self.port))
|
||||
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
|
||||
except Exception as err:
|
||||
# ConnectionRefusedError: [Errno 111] Connection refused
|
||||
self.close_rig()
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=err)
|
||||
self.log.warning(
|
||||
"[RIGCTLD] Connection to rigctld refused! Reconnect...",
|
||||
ip=self.hostname,
|
||||
port=self.port,
|
||||
e=err,
|
||||
)
|
||||
return False
|
||||
|
||||
def close_rig(self):
|
||||
|
@ -82,20 +105,28 @@ class radio():
|
|||
Args:
|
||||
command:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
if self.connected:
|
||||
try:
|
||||
self.connection.sendall(command + b"\n")
|
||||
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
|
||||
|
||||
try:
|
||||
return self.connection.recv(1024)
|
||||
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
|
||||
else:
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
hamlib_version = 0
|
||||
|
||||
|
||||
|
|
285
tnc/sock.py
285
tnc/sock.py
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 25 21:25:14 2020
|
||||
|
@ -38,19 +37,20 @@ DAEMON_QUEUE = queue.Queue()
|
|||
CONNECTED_CLIENTS = set()
|
||||
CLOSE_SIGNAL = False
|
||||
|
||||
log = structlog.get_logger("sock")
|
||||
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
"""
|
||||
the socket handler base class
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||
""" """
|
||||
|
||||
connection_alive = False
|
||||
log = structlog.get_logger("ThreadedTCPRequestHandler")
|
||||
|
||||
def send_to_client(self):
|
||||
"""
|
||||
|
@ -84,7 +84,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
try:
|
||||
client.send(sock_data)
|
||||
except Exception as err:
|
||||
log.info("[SCK] Connection lost", e=err)
|
||||
self.log.info("[SCK] Connection lost", e=err)
|
||||
self.connection_alive = False
|
||||
|
||||
# we want to transmit scatter data only once to reduce network traffic
|
||||
|
@ -132,8 +132,12 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
# finally delete our rx buffer to be ready for new commands
|
||||
data = bytes()
|
||||
except Exception as err:
|
||||
log.info("[SCK] Connection closed", ip=self.client_address[0],
|
||||
port=self.client_address[1], e=err)
|
||||
self.log.info(
|
||||
"[SCK] Connection closed",
|
||||
ip=self.client_address[0],
|
||||
port=self.client_address[1],
|
||||
e=err,
|
||||
)
|
||||
self.connection_alive = False
|
||||
|
||||
def handle(self):
|
||||
|
@ -142,14 +146,21 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
"""
|
||||
CONNECTED_CLIENTS.add(self.request)
|
||||
|
||||
log.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.send_thread = threading.Thread(target=self.send_to_client, args=[], daemon=True)
|
||||
self.send_thread.start()
|
||||
self.receive_thread = threading.Thread(target=self.receive_from_client, args=[], daemon=True)
|
||||
self.receive_thread.start()
|
||||
self.sendThread = threading.Thread(
|
||||
target=self.send_to_client, args=[], daemon=True
|
||||
)
|
||||
self.sendThread.start()
|
||||
self.receiveThread = threading.Thread(
|
||||
target=self.receive_from_client, args=[], daemon=True
|
||||
)
|
||||
self.receiveThread.start()
|
||||
|
||||
# keep connection alive until we close it
|
||||
while self.connection_alive and not CLOSE_SIGNAL:
|
||||
|
@ -157,13 +168,18 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
def finish(self):
|
||||
""" """
|
||||
log.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:
|
||||
CONNECTED_CLIENTS.remove(self.request)
|
||||
except Exception as err:
|
||||
log.warning("[SCK] client connection already removed from client list",
|
||||
client=self.request, e=err)
|
||||
except Exception:
|
||||
self.log.warning(
|
||||
"[SCK] client connection already removed from client list",
|
||||
client=self.request,
|
||||
)
|
||||
|
||||
|
||||
def process_tnc_commands(data):
|
||||
|
@ -176,29 +192,41 @@ def process_tnc_commands(data):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
log = structlog.get_logger("process_tnc_commands")
|
||||
|
||||
# we need to do some error handling in case of socket timeout or decoding issue
|
||||
try:
|
||||
# convert data to json object
|
||||
received_json = json.loads(data)
|
||||
log.debug("[SCK] CMD", command=received_json)
|
||||
# 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:
|
||||
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
||||
command_response("tx_audio_level", True)
|
||||
|
||||
except Exception as err:
|
||||
command_response("tx_audio_level", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# TRANSMIT SINE WAVE -----------------------------------------------------
|
||||
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
|
||||
# TRANSMIT TEST FRAME ----------------------------------------------------
|
||||
if (
|
||||
received_json["type"] == "set"
|
||||
and received_json["command"] == "send_test_frame"
|
||||
):
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
||||
command_response("send_test_frame", True)
|
||||
except Exception as err:
|
||||
command_response("send_test_frame", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# CQ CQ CQ -----------------------------------------------------
|
||||
if received_json["command"] == "cqcqcq":
|
||||
|
@ -208,7 +236,9 @@ def process_tnc_commands(data):
|
|||
|
||||
except Exception as err:
|
||||
command_response("cqcqcq", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# START_BEACON -----------------------------------------------------
|
||||
if received_json["command"] == "start_beacon":
|
||||
|
@ -219,7 +249,9 @@ def process_tnc_commands(data):
|
|||
command_response("start_beacon", True)
|
||||
except Exception as err:
|
||||
command_response("start_beacon", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# STOP_BEACON -----------------------------------------------------
|
||||
if received_json["command"] == "stop_beacon":
|
||||
|
@ -230,7 +262,9 @@ def process_tnc_commands(data):
|
|||
command_response("stop_beacon", True)
|
||||
except Exception as err:
|
||||
command_response("stop_beacon", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# PING ----------------------------------------------------------
|
||||
if received_json["type"] == "ping" and received_json["command"] == "ping":
|
||||
|
@ -248,7 +282,9 @@ def process_tnc_commands(data):
|
|||
command_response("ping", True)
|
||||
except Exception as err:
|
||||
command_response("ping", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# CONNECT ----------------------------------------------------------
|
||||
if received_json["type"] == "arq" and received_json["command"] == "connect":
|
||||
|
@ -270,7 +306,9 @@ def process_tnc_commands(data):
|
|||
command_response("connect", True)
|
||||
except Exception as err:
|
||||
command_response("connect", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# DISCONNECT ----------------------------------------------------------
|
||||
if received_json["type"] == "arq" and received_json["command"] == "disconnect":
|
||||
|
@ -280,7 +318,9 @@ def process_tnc_commands(data):
|
|||
command_response("disconnect", True)
|
||||
except Exception as err:
|
||||
command_response("disconnect", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# TRANSMIT RAW DATA -------------------------------------------
|
||||
if received_json["type"] == "arq" and received_json["command"] == "send_raw":
|
||||
|
@ -319,15 +359,22 @@ def process_tnc_commands(data):
|
|||
if not len(base64data) % 4:
|
||||
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:
|
||||
raise TypeError
|
||||
except Exception as err:
|
||||
command_response("send_raw", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# 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:
|
||||
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
|
||||
|
@ -337,7 +384,9 @@ def process_tnc_commands(data):
|
|||
command_response("stop_transmission", True)
|
||||
except Exception as err:
|
||||
command_response("stop_transmission", False)
|
||||
log.warning("[SCK] command execution error", e=err, 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":
|
||||
try:
|
||||
|
@ -350,9 +399,15 @@ def process_tnc_commands(data):
|
|||
# print(static.RX_BUFFER[i][4])
|
||||
# rawdata = json.loads(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)
|
||||
# self.request.sendall(bytes(jsondata, encoding))
|
||||
|
@ -361,17 +416,24 @@ def process_tnc_commands(data):
|
|||
|
||||
except Exception as err:
|
||||
command_response("rx_buffer", False)
|
||||
log.warning("[SCK] command execution error", e=err, 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:
|
||||
static.RX_BUFFER = []
|
||||
command_response("del_rx_buffer", True)
|
||||
except Exception as err:
|
||||
command_response("del_rx_buffer", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
log.warning(
|
||||
"[SCK] command execution error", e=err, command=received_json
|
||||
)
|
||||
|
||||
# exception, if JSON can't be decoded
|
||||
# exception, if JSON cant be decoded
|
||||
except Exception as err:
|
||||
log.error("[TNC] JSON decoding error", e=err)
|
||||
|
||||
|
@ -415,20 +477,24 @@ def send_tnc_state():
|
|||
|
||||
# add heard stations to heard stations object
|
||||
for heard in static.HEARD_STATIONS:
|
||||
output["stations"].append({
|
||||
"dxcallsign": str(heard[0], "utf-8"),
|
||||
"dxgrid": str(heard[1], "utf-8"),
|
||||
"timestamp": heard[2],
|
||||
"datatype": heard[3],
|
||||
"snr": heard[4],
|
||||
"offset": heard[5],
|
||||
"frequency": heard[6]})
|
||||
output["stations"].append(
|
||||
{
|
||||
"dxcallsign": str(heard[0], "utf-8"),
|
||||
"dxgrid": str(heard[1], "utf-8"),
|
||||
"timestamp": heard[2],
|
||||
"datatype": heard[3],
|
||||
"snr": heard[4],
|
||||
"offset": heard[5],
|
||||
"frequency": heard[6],
|
||||
}
|
||||
)
|
||||
|
||||
return json.dumps(output)
|
||||
|
||||
|
||||
# This has apparently been taken out of a class, but is never called because
|
||||
# the `self.request.sendall` call is a syntax error as `self` is undefined.
|
||||
# This appears to have been taken out of a class, but is never called because
|
||||
# the `self.request.sendall` call is a syntax error as `self` is undefined and
|
||||
# we don't see errors in use.
|
||||
def process_daemon_commands(data):
|
||||
"""
|
||||
process daemon commands
|
||||
|
@ -439,6 +505,8 @@ def process_daemon_commands(data):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
log = structlog.get_logger("process_daemon_commands")
|
||||
|
||||
# convert data to json object
|
||||
received_json = json.loads(data)
|
||||
log.debug("[SCK] CMD", command=received_json)
|
||||
|
@ -448,15 +516,21 @@ def process_daemon_commands(data):
|
|||
|
||||
if bytes(callsign, "utf-8") == b"":
|
||||
self.request.sendall(b"INVALID CALLSIGN")
|
||||
log.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:
|
||||
static.MYCALLSIGN = bytes(callsign, "utf-8")
|
||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
||||
|
||||
command_response("mycallsign", True)
|
||||
log.info("[DMN] SET MYCALL", call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC)
|
||||
log.info(
|
||||
"[DMN] SET MYCALL",
|
||||
call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC,
|
||||
)
|
||||
except Exception as err:
|
||||
command_response("mycallsign", False)
|
||||
log.warning("[SCK] command execution error", e=err, command=received_json)
|
||||
|
@ -475,7 +549,11 @@ def process_daemon_commands(data):
|
|||
command_response("mygrid", False)
|
||||
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:
|
||||
mycall = str(received_json["parameter"][0]["mycall"])
|
||||
mygrid = str(received_json["parameter"][0]["mygrid"])
|
||||
|
@ -495,7 +573,9 @@ def process_daemon_commands(data):
|
|||
enable_scatter = str(received_json["parameter"][0]["enable_scatter"])
|
||||
enable_fft = str(received_json["parameter"][0]["enable_fft"])
|
||||
enable_fsk = str(received_json["parameter"][0]["enable_fsk"])
|
||||
low_bandwidth_mode = str(received_json["parameter"][0]["low_bandwidth_mode"])
|
||||
low_bandwidth_mode = str(
|
||||
received_json["parameter"][0]["low_bandwidth_mode"]
|
||||
)
|
||||
tuning_range_fmin = str(received_json["parameter"][0]["tuning_range_fmin"])
|
||||
tuning_range_fmax = str(received_json["parameter"][0]["tuning_range_fmax"])
|
||||
tx_audio_level = str(received_json["parameter"][0]["tx_audio_level"])
|
||||
|
@ -503,33 +583,39 @@ def process_daemon_commands(data):
|
|||
|
||||
# print some debugging parameters
|
||||
for item in received_json["parameter"][0]:
|
||||
log.debug(f"[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",
|
||||
mycall,
|
||||
mygrid,
|
||||
rx_audio,
|
||||
tx_audio,
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
enable_scatter,
|
||||
enable_fft,
|
||||
low_bandwidth_mode,
|
||||
tuning_range_fmin,
|
||||
tuning_range_fmax,
|
||||
enable_fsk,
|
||||
tx_audio_level,
|
||||
respond_to_cq,
|
||||
])
|
||||
DAEMON_QUEUE.put(
|
||||
[
|
||||
"STARTTNC",
|
||||
mycall,
|
||||
mygrid,
|
||||
rx_audio,
|
||||
tx_audio,
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
enable_scatter,
|
||||
enable_fft,
|
||||
low_bandwidth_mode,
|
||||
tuning_range_fmin,
|
||||
tuning_range_fmax,
|
||||
enable_fsk,
|
||||
tx_audio_level,
|
||||
respond_to_cq,
|
||||
]
|
||||
)
|
||||
command_response("start_tnc", True)
|
||||
|
||||
except Exception as err:
|
||||
|
@ -550,19 +636,22 @@ def process_daemon_commands(data):
|
|||
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
||||
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||
|
||||
DAEMON_QUEUE.put(["TEST_HAMLIB",
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
])
|
||||
DAEMON_QUEUE.put(
|
||||
[
|
||||
"TEST_HAMLIB",
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
]
|
||||
)
|
||||
command_response("test_hamlib", True)
|
||||
except Exception as err:
|
||||
command_response("test_hamlib", False)
|
||||
|
@ -586,6 +675,8 @@ def send_daemon_state():
|
|||
"""
|
||||
send the daemon state to network
|
||||
"""
|
||||
log = structlog.get_logger("send_daemon_state")
|
||||
|
||||
try:
|
||||
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
||||
|
||||
|
@ -597,9 +688,9 @@ def send_daemon_state():
|
|||
"input_devices": static.AUDIO_INPUT_DEVICES,
|
||||
"output_devices": static.AUDIO_OUTPUT_DEVICES,
|
||||
"serial_devices": static.SERIAL_DEVICES,
|
||||
# "cpu": str(psutil.cpu_percent()),
|
||||
# "ram": str(psutil.virtual_memory().percent),
|
||||
"version": "0.1"
|
||||
#'cpu': str(psutil.cpu_percent()),
|
||||
#'ram': str(psutil.virtual_memory().percent),
|
||||
"version": "0.1",
|
||||
}
|
||||
|
||||
if static.TNCSTARTED:
|
||||
|
|
Loading…
Reference in a new issue