black code formatting

This commit is contained in:
dj2ls 2022-04-11 11:03:54 +02:00
parent 952c9b3839
commit 92cfa367f3
15 changed files with 4393 additions and 2248 deletions

View file

@ -1,4 +1,3 @@
import json
import sys
import multiprocessing
@ -7,39 +6,41 @@ import atexit
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
also uses a process data manager
"""
# we need to run this on windows for multiprocessing support
# multiprocessing.freeze_support()
#multiprocessing.get_context('spawn')
# multiprocessing.get_context('spawn')
# 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
sd._terminate()
sd._initialize()
with multiprocessing.Manager() as manager:
proxy_input_devices = manager.list()
proxy_output_devices = manager.list()
#print(multiprocessing.get_start_method())
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
# print(multiprocessing.get_start_method())
p = multiprocessing.Process(
target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)
)
p.start()
p.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):
"""
get audio devices from portaudio
Args:
input_devices: proxy variable for input devices
output_devices: proxy variable for outout devices
@ -47,15 +48,15 @@ def fetch_audio_devices(input_devices, output_devices):
Returns:
"""
devices = sd.query_devices(device=None, kind=None)
index = 0
for device in devices:
#for i in range(0, p.get_device_count()):
# for i in range(0, p.get_device_count()):
# we need to do a try exception, beacuse for windows theres no audio device range
try:
name = device["name"]
maxOutputChannels = device["max_output_channels"]
maxInputChannels = device["max_input_channels"]
@ -63,11 +64,10 @@ def fetch_audio_devices(input_devices, output_devices):
print(e)
maxInputChannels = 0
maxOutputChannels = 0
name = ''
name = ""
if maxInputChannels > 0:
input_devices.append({"id": index, "name": str(name)})
if maxOutputChannels > 0:
output_devices.append({"id": index, "name": str(name)})
index += 1

View file

@ -17,6 +17,7 @@ class FREEDV_MODE(Enum):
"""
enum for codec2 modes and names
"""
fsk_ldpc_0 = 200
fsk_ldpc_1 = 201
fsk_ldpc = 9
@ -25,31 +26,33 @@ class FREEDV_MODE(Enum):
datac3 = 12
allmodes = 255
# function for returning the mode value
def freedv_get_mode_value_by_name(mode):
"""
get the codec2 mode by entering its string
Args:
mode:
mode:
Returns: int
"""
return FREEDV_MODE[mode].value
# function for returning the mode name
def freedv_get_mode_name_by_value(mode):
"""
get the codec2 mode name as string
Args:
mode:
mode:
Returns: string
"""
return FREEDV_MODE(mode).name
# check if we are running in a pyinstaller environment
try:
app_path = sys._MEIPASS
@ -58,17 +61,17 @@ except:
sys.path.append(app_path)
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
if sys.platform == 'linux':
files = glob.glob('**/*libcodec2*',recursive=True)
files.append('libcodec2.so')
elif sys.platform == 'darwin':
files = glob.glob('**/*libcodec2*.dylib',recursive=True)
elif sys.platform == 'win32' or sys.platform == 'win64':
files = glob.glob('**\*libcodec2*.dll',recursive=True)
if sys.platform == "linux":
files = glob.glob("**/*libcodec2*", recursive=True)
files.append("libcodec2.so")
elif sys.platform == "darwin":
files = glob.glob("**/*libcodec2*.dylib", recursive=True)
elif sys.platform == "win32" or sys.platform == "win64":
files = glob.glob("**\*libcodec2*.dll", recursive=True)
else:
files = []
for file in files:
try:
@ -76,21 +79,21 @@ for file in files:
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
break
except Exception as e:
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=e)
structlog.get_logger("structlog").warning(
"[C2 ] Libcodec2 found but not loaded", path=file, e=e
)
# quit module if codec2 cant be loaded
if not 'api' in locals():
# quit module if codec2 cant be loaded
if not "api" in locals():
structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded", path=file)
os._exit(1)
# ctypes function init
# ctypes function init
#api.freedv_set_tuning_range.restype = c_int
#api.freedv_set_tuning_range.argype = [c_void_p, c_float, c_float]
# api.freedv_set_tuning_range.restype = c_int
# api.freedv_set_tuning_range.argype = [c_void_p, c_float, c_float]
api.freedv_open.argype = [c_int]
api.freedv_open.restype = c_void_p
@ -121,24 +124,24 @@ api.freedv_get_n_max_modem_samples.restype = c_int
api.freedv_set_frames_per_burst.argtype = [c_void_p, c_int]
api.freedv_set_frames_per_burst.restype = c_void_p
api.freedv_get_rx_status.argtype = [c_void_p]
api.freedv_get_rx_status.restype = c_int
api.freedv_get_rx_status.restype = c_int
api.freedv_get_modem_stats.argtype = [c_void_p, c_void_p, c_void_p]
api.freedv_get_modem_stats.restype = c_int
api.freedv_get_n_tx_postamble_modem_samples.argtype = [c_void_p]
api.freedv_get_n_tx_postamble_modem_samples.restype = c_int
api.freedv_get_n_tx_postamble_modem_samples.restype = c_int
api.freedv_get_n_tx_preamble_modem_samples.argtype = [c_void_p]
api.freedv_get_n_tx_preamble_modem_samples.restype = c_int
api.freedv_get_n_tx_preamble_modem_samples.restype = c_int
api.freedv_get_n_tx_modem_samples.argtype = [c_void_p]
api.freedv_get_n_tx_modem_samples.restype = c_int
api.freedv_get_n_tx_modem_samples.restype = c_int
api.freedv_get_n_max_modem_samples.argtype = [c_void_p]
api.freedv_get_n_max_modem_samples.restype = c_int
api.freedv_get_n_max_modem_samples.restype = c_int
api.FREEDV_FS_8000 = 8000
api.FREEDV_MODE_DATAC1 = 10
@ -151,17 +154,19 @@ api.FREEDV_MODE_FSK_LDPC = 9
# advanced structure for fsk modes
class ADVANCED(ctypes.Structure):
""" """
_fields_ = [
("interleave_frames", ctypes.c_int),
("interleave_frames", ctypes.c_int),
("M", ctypes.c_int),
("Rs", ctypes.c_int),
("Fs", ctypes.c_int),
("first_tone", ctypes.c_int),
("tone_spacing", ctypes.c_int),
("codename", ctypes.c_char_p),
("first_tone", ctypes.c_int),
("tone_spacing", ctypes.c_int),
("codename", ctypes.c_char_p),
]
'''
"""
adv.interleave_frames = 0 # max amplitude
adv.M = 2 # number of fsk tones 2/4
adv.Rs = 100 # symbol rate
@ -181,16 +186,16 @@ H_128_256_5 rate 0.50 (256,128) BPF: 16 working
H_4096_8192_3d rate 0.50 (8192,4096) BPF: 512 not working
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.interleave_frames = 0
api.FREEDV_MODE_FSK_LDPC_0_ADV.M = 4
api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 100
api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk
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
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk
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()
@ -198,26 +203,27 @@ 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
api.FREEDV_MODE_FSK_LDPC_1_ADV.Fs = 8000
api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1250 # 1250 4fsk, 1500 2fsk
api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1250 # 1250 4fsk, 1500 2fsk
api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = 'H_256_512_4'.encode('utf-8') # code word
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_256_512_4".encode("utf-8") # code word
# ------- MODEM STATS STRUCTURES
MODEM_STATS_NC_MAX = 50+1
MODEM_STATS_NR_MAX = 160
MODEM_STATS_ET_MAX = 8
MODEM_STATS_EYE_IND_MAX = 160
MODEM_STATS_NSPEC = 512
MODEM_STATS_MAX_F_HZ = 4000
MODEM_STATS_MAX_F_EST = 4
MODEM_STATS_NC_MAX = 50 + 1
MODEM_STATS_NR_MAX = 160
MODEM_STATS_ET_MAX = 8
MODEM_STATS_EYE_IND_MAX = 160
MODEM_STATS_NSPEC = 512
MODEM_STATS_MAX_F_HZ = 4000
MODEM_STATS_MAX_F_EST = 4
# modem stats structure
class MODEMSTATS(ctypes.Structure):
""" """
_fields_ = [
("Nc", ctypes.c_int),
("snr_est", ctypes.c_float),
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX),
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX) * MODEM_STATS_NC_MAX),
("nr", ctypes.c_int),
("sync", ctypes.c_int),
("foff", ctypes.c_float),
@ -227,19 +233,23 @@ class MODEMSTATS(ctypes.Structure):
("pre", ctypes.c_int),
("post", ctypes.c_int),
("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
("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
("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 # 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.rx_sync_flags_to_text = [
"----",
@ -257,68 +267,80 @@ api.rx_sync_flags_to_text = [
"EB--",
"EB-T",
"EBS-",
"EBST"]
"EBST",
]
# audio buffer ---------------------------------------------------------
class audio_buffer:
"""
thread safe audio buffer, which fits to needs of codec2
made by David Rowe, VK5DGR
"""
# 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)
structlog.get_logger("structlog").debug(
"[C2 ] creating audio buffer", size=size
)
self.size = size
self.buffer = np.zeros(size, dtype=np.int16)
self.nbuffer = 0
self.mutex = Lock()
def push(self,samples):
def push(self, samples):
"""
Push new data to buffer
Args:
samples:
samples:
Returns:
"""
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
assert self.nbuffer + len(samples) <= self.size
self.buffer[self.nbuffer : self.nbuffer + len(samples)] = samples
self.nbuffer += len(samples)
self.mutex.release()
def pop(self,size):
def pop(self, size):
"""
get data from buffer in size of NIN
Args:
size:
size:
Returns:
"""
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.nbuffer -= size
self.buffer[: self.nbuffer] = self.buffer[size : size + self.nbuffer]
assert self.nbuffer >= 0
self.mutex.release()
# resampler ---------------------------------------------------------
api.FDMDV_OS_48 = int(6) # oversampling rate
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz
api.FDMDV_OS_TAPS_48_8K = int(api.FDMDV_OS_TAPS_48K/api.FDMDV_OS_48) # number of OS filter taps at 8kHz
api.FDMDV_OS_48 = int(6) # oversampling rate
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz
api.FDMDV_OS_TAPS_48_8K = int(
api.FDMDV_OS_TAPS_48K / api.FDMDV_OS_48
) # number of OS filter taps at 8kHz
api.fdmdv_8_to_48_short.argtype = [c_void_p, c_void_p, c_int]
api.fdmdv_48_to_8_short.argtype = [c_void_p, c_void_p, c_int]
class resampler:
"""
resampler class
"""
# resample 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
@ -327,9 +349,8 @@ class resampler:
structlog.get_logger("structlog").debug("[C2 ] create 48<->8 kHz resampler")
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
self.filter_mem48 = np.zeros(self.MEM48)
def resample48_to_8(self,in48):
def resample48_to_8(self, in48):
"""
audio resampler integration from codec2
downsample audio from 48000Hz to 8000Hz
@ -341,25 +362,25 @@ 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
# concat 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 = np.zeros(self.MEM48 + len(in48), dtype=np.int16)
in48_mem[: self.MEM48] = self.filter_mem48
in48_mem[self.MEM48 :] = in48
# In C: pin48=&in48_mem[MEM48]
pin48 = byref(np.ctypeslib.as_ctypes(in48_mem), 2*self.MEM48)
pin48 = byref(np.ctypeslib.as_ctypes(in48_mem), 2 * self.MEM48)
n8 = int(len(in48) / api.FDMDV_OS_48)
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)
# store memory for next time
self.filter_mem48 = in48_mem[:self.MEM48]
self.filter_mem48 = in48_mem[: self.MEM48]
return out8
def resample8_to_48(self,in8):
def resample8_to_48(self, in8):
"""
audio resampler integration from codec2
resample audio from 8000Hz to 48000Hz
@ -372,16 +393,16 @@ class resampler:
assert in8.dtype == np.int16
# concat 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 = np.zeros(self.MEM8 + len(in8), dtype=np.int16)
in8_mem[: self.MEM8] = self.filter_mem8
in8_mem[self.MEM8 :] = in8
# In C: pin8=&in8_mem[MEM8]
pin8 = 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));
pin8 = 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))
# store memory for next time
self.filter_mem8 = in8_mem[:self.MEM8]
self.filter_mem8 = in8_mem[: self.MEM8]
return out48

View file

@ -37,85 +37,93 @@ def signal_handler(sig, frame):
"""
signal handler for closing the network socket on app exit
Args:
sig:
frame:
sig:
frame:
Returns: system exit
"""
print('Closing daemon...')
print("Closing daemon...")
sock.CLOSE_SIGNAL = True
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
class DAEMON():
"""
daemon class
class DAEMON:
"""
daemon class
"""
def __init__(self):
# load crc engine
self.crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc8 library
# load crc engine
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)
worker.start()
def update_audio_devices(self):
"""
"""
update audio devices and set to static
"""
while 1:
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 e:
print(e)
time.sleep(1)
def update_serial_devices(self):
"""
update serial devices and set to static
"""
while 1:
try:
#print("update serial")
# print("update serial")
serial_devices = []
ports = serial.tools.list_ports.comports()
for port, desc, hwid in ports:
# calculate hex of hwid if we have unique names
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8'))
crc_hwid = crc_hwid.to_bytes(2, byteorder='big')
crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
crc_hwid = crc_hwid.hex()
description = desc + ' [' + crc_hwid + ']'
serial_devices.append({"port": str(port), "description": str(description) })
description = desc + " [" + crc_hwid + "]"
serial_devices.append(
{"port": str(port), "description": str(description)}
)
static.SERIAL_DEVICES = serial_devices
time.sleep(1)
except Exception as e:
print(e)
def worker(self):
"""
a worker for the received commands
"""
while 1:
try:
data = self.daemon_queue.get()
# data[1] mycall
@ -138,132 +146,135 @@ class DAEMON():
# data[18] low_bandwith_mode
# data[19] tuning_range_fmin
# data[20] tuning_range_fmax
if data[0] == 'STARTTNC':
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6])
if data[0] == "STARTTNC":
structlog.get_logger("structlog").warning(
"[DMN] Starting TNC", rig=data[5], port=data[6]
)
# list of parameters, necessary for running subprocess command as a list
options = []
options.append('--port')
options.append("--port")
options.append(str(static.DAEMONPORT - 1))
options.append('--mycall')
options.append("--mycall")
options.append(data[1])
options.append('--mygrid')
options.append("--mygrid")
options.append(data[2])
options.append('--rx')
options.append("--rx")
options.append(data[3])
options.append('--tx')
options.append("--tx")
options.append(data[4])
# 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
if data[13] != 'disabled':
options.append('--devicename')
if data[13] != "disabled":
options.append("--devicename")
options.append(data[5])
options.append('--deviceport')
options.append("--deviceport")
options.append(data[6])
options.append('--serialspeed')
options.append("--serialspeed")
options.append(data[7])
options.append('--pttprotocol')
options.append("--pttprotocol")
options.append(data[8])
options.append('--pttport')
options.append("--pttport")
options.append(data[9])
options.append('--data_bits')
options.append("--data_bits")
options.append(data[10])
options.append('--stop_bits')
options.append("--stop_bits")
options.append(data[11])
options.append('--handshake')
options.append("--handshake")
options.append(data[12])
options.append('--radiocontrol')
options.append("--radiocontrol")
options.append(data[13])
if data[13] != 'rigctld':
options.append('--rigctld_ip')
if data[13] != "rigctld":
options.append("--rigctld_ip")
options.append(data[14])
options.append('--rigctld_port')
options.append("--rigctld_port")
options.append(data[15])
if data[16] == 'True':
options.append('--scatter')
if data[17] == 'True':
options.append('--fft')
if data[18] == 'True':
options.append('--500hz')
if data[16] == "True":
options.append("--scatter")
options.append('--tuning_range_fmin')
if data[17] == "True":
options.append("--fft")
if data[18] == "True":
options.append("--500hz")
options.append("--tuning_range_fmin")
options.append(data[19])
options.append('--tuning_range_fmax')
options.append("--tuning_range_fmax")
options.append(data[20])
# overriding FSK mode
#if data[21] == 'True':
# if data[21] == 'True':
# options.append('--fsk')
options.append('--tx-audio-level')
options.append(data[22])
options.append("--tx-audio-level")
options.append(data[22])
# try running tnc from binary, else run from source
# this helps running the tnc in a developer environment
try:
command = []
if sys.platform == 'linux' or sys.platform == 'darwin':
command.append('./freedata-tnc')
elif sys.platform == 'win32' or sys.platform == 'win64':
command.append('freedata-tnc.exe')
if sys.platform == "linux" or sys.platform == "darwin":
command.append("./freedata-tnc")
elif sys.platform == "win32" or sys.platform == "win64":
command.append("freedata-tnc.exe")
command += options
p = subprocess.Popen(command)
atexit.register(p.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary")
structlog.get_logger("structlog").info(
"[DMN] TNC started", path="binary"
)
except:
command = []
if sys.platform == 'linux' or sys.platform == 'darwin':
command.append('python3')
elif sys.platform == 'win32' or sys.platform == 'win64':
command.append('python')
command.append('main.py')
if sys.platform == "linux" or sys.platform == "darwin":
command.append("python3")
elif sys.platform == "win32" or sys.platform == "win64":
command.append("python")
command.append("main.py")
command += options
p = subprocess.Popen(command)
atexit.register(p.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="source")
structlog.get_logger("structlog").info(
"[DMN] TNC started", path="source"
)
static.TNCPROCESS = p # .pid
static.TNCSTARTED = True
'''
"""
# WE HAVE THIS PART in SOCKET
if data[0] == 'STOPTNC':
static.TNCPROCESS.kill()
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
#os.kill(static.TNCPROCESS, signal.SIGKILL)
static.TNCSTARTED = False
'''
"""
# data[1] devicename
# data[2] deviceport
# data[3] serialspeed
@ -275,7 +286,7 @@ class DAEMON():
# data[9] radiocontrol
# data[10] rigctld_ip
# data[11] rigctld_port
if data[0] == 'TEST_HAMLIB':
if data[0] == "TEST_HAMLIB":
devicename = data[1]
deviceport = data[2]
@ -289,91 +300,125 @@ class DAEMON():
rigctld_ip = data[10]
rigctld_port = data[11]
# check how we want to control the radio
if radiocontrol == 'direct':
if radiocontrol == "direct":
import rig
elif radiocontrol == 'rigctl':
elif radiocontrol == "rigctl":
import rigctl as rig
elif radiocontrol == 'rigctld':
elif radiocontrol == "rigctld":
import rigctld as rig
else:
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
hamlib.set_ptt(True)
hamlib.set_ptt(True)
pttstate = hamlib.get_ptt()
if pttstate:
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS')
response = {'command': 'test_hamlib', 'result': 'SUCCESS'}
structlog.get_logger("structlog").info(
"[DMN] Hamlib PTT", status="SUCCESS"
)
response = {"command": "test_hamlib", "result": "SUCCESS"}
elif not pttstate:
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS')
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'}
structlog.get_logger("structlog").warning(
"[DMN] Hamlib PTT", status="NO SUCCESS"
)
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
else:
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED')
response = {'command': 'test_hamlib', 'result': 'FAILED'}
hamlib.set_ptt(False)
structlog.get_logger("structlog").error(
"[DMN] Hamlib PTT", status="FAILED"
)
response = {"command": "test_hamlib", "result": "FAILED"}
hamlib.set_ptt(False)
hamlib.close_rig()
jsondata = json.dumps(response)
sock.SOCKET_QUEUE.put(jsondata)
except Exception as e:
print(e)
if __name__ == '__main__':
if __name__ == "__main__":
# we need to run this on windows for multiprocessing support
multiprocessing.freeze_support()
# --------------------------------------------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 = 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,
)
ARGS = PARSER.parse_args()
static.DAEMONPORT = ARGS.socket_port
try:
if sys.platform == 'linux':
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon'
if sys.platform == 'darwin':
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon'
if sys.platform == 'win32' or sys.platform == 'win64':
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon'
if sys.platform == "linux":
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
if sys.platform == "darwin":
logging_path = (
os.getenv("HOME")
+ "/Library/"
+ "Application Support/"
+ "FreeDATA/"
+ "daemon"
)
if sys.platform == "win32" or sys.platform == "win64":
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
if not os.path.exists(logging_path):
os.makedirs(logging_path)
log_handler.setup_logging(logging_path)
except:
structlog.get_logger("structlog").error("[DMN] logger init error")
structlog.get_logger("structlog").error("[DMN] logger init error")
try:
structlog.get_logger("structlog").info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
structlog.get_logger("structlog").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 e:
structlog.get_logger("structlog").error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e)
structlog.get_logger("structlog").error(
"[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e
)
os._exit(1)
daemon = DAEMON()
structlog.get_logger("structlog").info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION)
structlog.get_logger("structlog").info(
"[DMN] Starting FreeDATA Daemon",
author="DJ2LS",
year="2022",
version=static.VERSION,
)
while True:
time.sleep(1)

File diff suppressed because it is too large Load diff

View file

@ -11,12 +11,11 @@ import crcengine
import static
def wait(seconds):
"""
Args:
seconds:
seconds:
Returns:
@ -26,62 +25,62 @@ def wait(seconds):
while time.time() < timeout:
time.sleep(0.01)
return True
def get_crc_8(data):
"""Author: DJ2LS
Get the CRC8 of a byte string
param: data = bytes()
Args:
data:
data:
Returns:
"""
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_data.to_bytes(1, byteorder='big')
crc_data = crc_data.to_bytes(1, byteorder="big")
return crc_data
def get_crc_16(data):
"""Author: DJ2LS
Get the CRC16 of a byte string
param: data = bytes()
Args:
data:
data:
Returns:
"""
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_data.to_bytes(2, byteorder='big')
crc_data = crc_data.to_bytes(2, byteorder="big")
return crc_data
def get_crc_32(data):
"""Author: DJ2LS
Get the CRC32 of a byte string
param: data = bytes()
Args:
data:
data:
Returns:
"""
crc_algorithm = crcengine.new('crc32') # load crc16 library
crc_algorithm = crcengine.new("crc32") # load crc16 library
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
@ -89,12 +88,12 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
"""
Args:
dxcallsign:
dxgrid:
datatype:
snr:
offset:
frequency:
dxcallsign:
dxgrid:
datatype:
snr:
offset:
frequency:
Returns:
@ -102,17 +101,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(0, len(static.HEARD_STATIONS)):
# update callsign with new timestamp
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
static.HEARD_STATIONS[i] = [dxcallsign, dxgrid, int(time.time()), datatype, snr, 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
@ -122,134 +141,132 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
# static.HEARD_STATIONS[idx] = item
def callsign_to_bytes(callsign):
"""
Args:
callsign:
callsign:
Returns:
"""
# http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations
#-14 Truckers or generally full time drivers
#-15 generic additional station, digi, mobile, wx, etc
# -0 Your primary station usually fixed and message capable
# -1 generic additional station, digi, mobile, wx, etc
# -2 generic additional station, digi, mobile, wx, etc
# -3 generic additional station, digi, mobile, wx, etc
# -4 generic additional station, digi, mobile, wx, etc
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
# -6 Special activity, Satellite ops, camping or 6 meters, etc
# -7 walkie talkies, HT's or other human portable
# -8 boats, sailboats, RV's or second main mobile
# -9 Primary Mobile (usually message capable)
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
# -11 balloons, aircraft, spacecraft, etc
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
# -13 Weather stations
# -14 Truckers or generally full time drivers
# -15 generic additional station, digi, mobile, wx, etc
# try converting to bytestring if possible type string
try:
callsign = bytes(callsign, 'utf-8')
try:
callsign = bytes(callsign, "utf-8")
except:
pass
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
callsign = callsign.split(b'-')
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
callsign = callsign.split(b"-")
try:
ssid = int(callsign[1])
except:
ssid = 0
callsign = callsign[0]
bytestring = bytearray(8)
bytestring[:len(callsign)] = callsign
bytestring[: len(callsign)] = callsign
bytestring[7:8] = bytes([ssid])
return bytes(bytestring)
return bytes(bytestring)
def bytes_to_callsign(bytestring):
"""
Args:
bytestring:
bytestring:
Returns:
"""
# http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations
#-14 Truckers or generally full time drivers
#-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 )
# -0 Your primary station usually fixed and message capable
# -1 generic additional station, digi, mobile, wx, etc
# -2 generic additional station, digi, mobile, wx, etc
# -3 generic additional station, digi, mobile, wx, etc
# -4 generic additional station, digi, mobile, wx, etc
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
# -6 Special activity, Satellite ops, camping or 6 meters, etc
# -7 walkie talkies, HT's or other human portable
# -8 boats, sailboats, RV's or second main mobile
# -9 Primary Mobile (usually message capable)
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
# -11 balloons, aircraft, spacecraft, etc
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
# -13 Weather stations
# -14 Truckers or generally full time drivers
# -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 )
callsign = bytes(bytestring[:7])
callsign = callsign.rstrip(b'\x00')
callsign = callsign.rstrip(b"\x00")
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
callsign = callsign + b'-'
callsign = callsign.decode('utf-8')
callsign = callsign + b"-"
callsign = callsign.decode("utf-8")
callsign = callsign + str(ssid)
callsign = callsign.encode('utf-8')
return bytes(callsign)
callsign = callsign.encode("utf-8")
return bytes(callsign)
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
Args:
callsign: Callsign which we want to check
crc_to_check: The CRC which we want the callsign to check against
crc_to_check: The CRC which we want the callsign to check against
Returns:
[True, Callsign + SSID]
False
"""
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library
crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
try:
callsign = callsign.split(b'-')
callsign = callsign[0] # we want the callsign without SSID
callsign = callsign.split(b"-")
callsign = callsign[0] # we want the callsign without SSID
except:
callsign = callsign
print(static.SSID_LIST)
for ssid in static.SSID_LIST:
print(ssid)
print(ssid)
for ssid in static.SSID_LIST:
#for ssid in range(0,254):
call_with_ssid = bytearray(callsign)
call_with_ssid.extend('-'.encode('utf-8'))
call_with_ssid.extend(str(ssid).encode('utf-8'))
# for ssid in range(0,254):
call_with_ssid = bytearray(callsign)
call_with_ssid.extend("-".encode("utf-8"))
call_with_ssid.extend(str(ssid).encode("utf-8"))
callsign_crc = get_crc_16(call_with_ssid)
if callsign_crc == crc_to_check:
print(call_with_ssid)
return [True, bytes(call_with_ssid)]
return [False, ""]

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ def setup_logging(filename):
"""
Args:
filename:
filename:
Returns:
@ -20,7 +20,8 @@ def setup_logging(filename):
timestamper,
]
logging.config.dictConfig({
logging.config.dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
"formatters": {
@ -44,7 +45,7 @@ def setup_logging(filename):
"file": {
"level": "DEBUG",
"class": "logging.handlers.WatchedFileHandler",
"filename": filename + '.log',
"filename": filename + ".log",
"formatter": "plain",
},
},
@ -54,8 +55,9 @@ def setup_logging(filename):
"level": "DEBUG",
"propagate": True,
},
}
})
},
}
)
structlog.configure(
processors=[
structlog.stdlib.add_log_level,

View file

@ -13,18 +13,19 @@ main module for running the tnc
import argparse
import threading
import static
import socketserver
import helpers
import data_handler
import structlog
import log_handler
import modem
import sys
import os
import signal
import time
import multiprocessing
import structlog
import modem
import static
import log_handler
import helpers
import data_handler
# signal handler for closing aplication
@ -33,61 +34,207 @@ def signal_handler(sig, frame):
a signal handler, which closes the network/socket when closing the application
Args:
sig: signal
frame:
frame:
Returns: system exit
"""
print('Closing TNC...')
print("Closing TNC...")
sock.CLOSE_SIGNAL = True
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
if __name__ == '__main__':
if __name__ == "__main__":
# we need to run this on windows for 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_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('--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 = 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_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(
"--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()
# additional step for beeing sure our callsign is correctly
# in case we are not getting a station ssid
# 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)
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
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_OUTPUT_DEVICE = ARGS.audio_output_device
static.PORT = ARGS.socket_port
@ -104,58 +251,68 @@ if __name__ == '__main__':
static.HAMLIB_RGICTLD_PORT = str(ARGS.rigctld_port)
static.ENABLE_SCATTER = ARGS.send_scatter
static.ENABLE_FFT = ARGS.send_fft
static.ENABLE_FSK = ARGS.enable_fsk
static.LOW_BANDWITH_MODE = ARGS.low_bandwith_mode
static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
static.ENABLE_FSK = ARGS.enable_fsk
static.LOW_BANDWITH_MODE = ARGS.low_bandwith_mode
static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
# we need to wait until we got all parameters from argparse first before we can load the other modules
import sock
# config logging
try:
if sys.platform == 'linux':
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc'
if sys.platform == 'darwin':
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc'
if sys.platform == 'win32' or sys.platform == 'win64':
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc'
import sock
# config logging
try:
if sys.platform == "linux":
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
if sys.platform == "darwin":
logging_path = (
os.getenv("HOME")
+ "/Library/"
+ "Application Support/"
+ "FreeDATA/"
+ "tnc"
)
if sys.platform in ["win32", "win64"]:
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
if not os.path.exists(logging_path):
os.makedirs(logging_path)
log_handler.setup_logging(logging_path)
except:
structlog.get_logger("structlog").error("[DMN] logger init error")
structlog.get_logger("structlog").error("[DMN] logger init error")
structlog.get_logger("structlog").info(
"[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION
)
structlog.get_logger("structlog").info("[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION)
# start data handler
data_handler.DATA()
# start modem
modem = modem.RF()
# --------------------------------------------START CMD SERVER
try:
structlog.get_logger("structlog").info("[TNC] Starting TCP/IP socket", port=static.PORT)
structlog.get_logger("structlog").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 e:
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e)
structlog.get_logger("structlog").error(
"[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e
)
os._exit(1)
while 1:
time.sleep(1)

File diff suppressed because it is too large Load diff

View file

@ -20,103 +20,133 @@ except:
sys.path.append(app_path)
# try importing hamlib
# try importing hamlib
try:
# get python version
python_version = 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('/usr/local/lib/python'+ python_version +'/site-packages')
# installation path for Ubuntu 20.10 +
sys.path.append('/usr/local/lib/')
sys.path.append("/usr/local/lib/")
# installation path for Suse
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages')
sys.path.append("/usr/local/lib64/python" + python_version + "/site-packages")
# 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
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.8/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('lib/hamlib/linux/python3.8/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.8/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("lib/hamlib/linux/python3.8/site-packages")
import Hamlib
# https://stackoverflow.com/a/4703409
hamlib_version = re.findall(r"[-+]?\d*\.?\d+|\d+", Hamlib.cvar.hamlib_version)
hamlib_version = re.findall(r"[-+]?\d*\.?\d+|\d+", Hamlib.cvar.hamlib_version)
hamlib_version = float(hamlib_version[0])
min_hamlib_version = 4.1
if hamlib_version > min_hamlib_version:
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version)
structlog.get_logger("structlog").info(
"[RIG] Hamlib found", version=hamlib_version
)
else:
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
structlog.get_logger("structlog").warning(
"[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version
)
except Exception as e:
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e)
structlog.get_logger("structlog").warning(
"[RIG] Python Hamlib binding not found", error=e
)
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)
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(' ')
hamlib_version = hamlib_version.split(" ")
if hamlib_version[1] == 'Hamlib':
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
if hamlib_version[1] == "Hamlib":
structlog.get_logger("structlog").warning(
"[RIG] Rigctl found! Please try using this", version=hamlib_version[2]
)
sys.exit()
else:
raise Exception
except Exception as e:
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=e)
structlog.get_logger("structlog").critical(
"[RIG] HAMLIB NOT INSTALLED", error=e
)
hamlib_version = 0
sys.exit()
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):
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:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
rigctld_port:
rigctld_ip:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
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
self.serialspeed = str(
serialspeed
) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = str(hamlib_ptt_type)
self.pttport = str(pttport)
self.data_bits = str(data_bits)
self.stop_bits = str(stop_bits)
self.handshake = str(handshake)
# try to init hamlib
try:
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
@ -125,10 +155,11 @@ class radio:
try:
self.devicenumber = int(getattr(Hamlib, self.devicename))
except:
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
structlog.get_logger("structlog").error(
"[RIG] Hamlib: rig not supported..."
)
self.devicenumber = 0
self.my_rig = Hamlib.Rig(self.devicenumber)
self.my_rig.set_conf("rig_pathname", self.deviceport)
self.my_rig.set_conf("retry", "5")
@ -137,109 +168,120 @@ class radio:
self.my_rig.set_conf("stop_bits", self.stop_bits)
self.my_rig.set_conf("data_bits", self.data_bits)
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.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.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.my_rig.set_conf("dtr_state", "HIGH")
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.my_rig.set_conf("dtr_state", "LOW")
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.my_rig.set_conf("dtr_state", "OFF")
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
elif self.hamlib_ptt_type == 'MICDATA':
elif self.hamlib_ptt_type == "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
elif self.hamlib_ptt_type == 'RIG_PTT_NONE':
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE':
elif 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"))
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.my_rig.open()
atexit.register(self.my_rig.close)
try:
# lets determine the error message when opening rig
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
error = error[1].split('err=')
error = error[1].split("err=")
error = error[1]
if error == 'Permission denied':
structlog.get_logger("structlog").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)
except:
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS')
if error == "Permission denied":
structlog.get_logger("structlog").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
)
except:
structlog.get_logger("structlog").info(
"[RIG] Hamlib device opened", status="SUCCESS"
)
# set ptt to false if ptt is stuck for some reason
self.set_ptt(False)
# set rig mode to USB
# 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)
return True
except Exception as e:
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0])
structlog.get_logger("structlog").error(
"[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0]
)
return False
def get_frequency(self):
""" """
return int(self.my_rig.get_freq())
def get_mode(self):
""" """
(hamlib_mode, bandwith) = self.my_rig.get_mode()
return Hamlib.rig_strrmode(hamlib_mode)
def get_bandwith(self):
""" """
(hamlib_mode, bandwith) = self.my_rig.get_mode()
return bandwith
# not needed yet beacuse of some possible problems
#def set_mode(self, mode):
# def set_mode(self, mode):
# return 0
def get_ptt(self):
""" """
return self.my_rig.get_ptt()
def set_ptt(self, state):
"""
Args:
state:
state:
Returns:
@ -249,7 +291,7 @@ class radio:
else:
self.my_rig.set_ptt(Hamlib.RIG_VFO_CURR, 0)
return state
def close_rig(self):
""" """
self.my_rig.close()

View file

@ -13,123 +13,149 @@ import structlog
import time
import sys
import os
# for rig_model -> rig_number only
# set global hamlib version
hamlib_version = 0
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):
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,
):
"""
Args:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
rigctld_ip:
rigctld_port:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
rigctld_ip:
rigctld_port:
Returns:
"""
self.devicename = devicename
self.deviceport = deviceport
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.serialspeed = str(
serialspeed
) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = hamlib_ptt_type
self.pttport = pttport
self.data_bits = data_bits
self.stop_bits = stop_bits
self.handshake = handshake
# check if we are running in a pyinstaller environment
# check if we are running in a pyinstaller environment
try:
app_path = sys._MEIPASS
except:
app_path = os.path.abspath(".")
sys.path.append(app_path)
sys.path.append(app_path)
# get devicenumber by looking for deviceobject in Hamlib module
try:
import Hamlib
self.devicenumber = int(getattr(Hamlib, self.devicename))
except:
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=e)
self.devicenumber = 6 # dummy
structlog.get_logger("structlog").warning(
"[RIGCTL] RADIO NOT FOUND USING DUMMY!", error=e
)
# set deviceport to dummy port, if we selected dummy model
if self.devicenumber == 1 or self.devicenumber == 6:
self.deviceport = '/dev/ttyUSB0'
self.deviceport = "/dev/ttyUSB0"
print(self.devicenumber, self.deviceport, self.serialspeed)
# select precompiled executable for win32/win64 rigctl
# this is really a hack...somewhen we need a native hamlib integration for windows
if sys.platform == 'win32' or sys.platform == 'win64':
self.cmd = app_path + 'lib\\hamlib\\'+sys.platform+'\\rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
if sys.platform == "win32" or sys.platform == "win64":
self.cmd = (
app_path
+ "lib\\hamlib\\"
+ sys.platform
+ "\\rigctl -m %d -r %s -s %d "
% (int(self.devicenumber), self.deviceport, 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 " % (
int(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
# il set e t per il get
# set ptt to false if ptt is stuck for some reason
self.set_ptt(False)
return True
def get_frequency(self):
""" """
cmd = self.cmd + ' f'
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
cmd = self.cmd + " f"
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())
# print('get_frequency', freq, sw_proc.communicate())
try:
return int(freq)
except:
return False
def get_mode(self):
""" """
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
#return Hamlib.rig_strrmode(hamlib_mode)
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
# return Hamlib.rig_strrmode(hamlib_mode)
try:
return 'PKTUSB'
return "PKTUSB"
except:
return False
def get_bandwith(self):
""" """
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
bandwith = 2700
try:
@ -141,18 +167,20 @@ class radio:
"""
Args:
mode:
mode:
Returns:
"""
# non usata
return 0
def get_ptt(self):
""" """
cmd = self.cmd + ' t'
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
cmd = self.cmd + " t"
sw_proc = subprocess.Popen(
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
)
time.sleep(0.5)
status = sw_proc.communicate()[0]
@ -160,31 +188,31 @@ class radio:
return status
except:
return False
def set_ptt(self, state):
"""
Args:
state:
state:
Returns:
"""
cmd = self.cmd + ' T '
print('set_ptt', state)
cmd = self.cmd + " T "
print("set_ptt", state)
if state:
cmd = cmd + '1'
cmd = cmd + "1"
else:
cmd = cmd + '0'
print('set_ptt', cmd)
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:
return state
except:
return False
def close_rig(self):
""" """
#self.my_rig.close()
# self.my_rig.close()
return

View file

@ -5,6 +5,7 @@ import log_handler
import logging
import time
import static
# class taken from darsidelemm
# rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35
#
@ -13,117 +14,148 @@ import static
# set global hamlib version
hamlib_version = 0
class radio():
class radio:
"""rotctld (hamlib) communication class"""
# Note: This is a massive hack.
# Note: This is a massive hack.
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.settimeout(timeout)
# self.sock.settimeout(timeout)
self.connected = False
self.hostname = hostname
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:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
rigctld_ip:
rigctld_port:
devicename:
deviceport:
hamlib_ptt_type:
serialspeed:
pttport:
data_bits:
stop_bits:
handshake:
rigctld_ip:
rigctld_port:
Returns:
"""
self.hostname = rigctld_ip
self.port = int(rigctld_port)
if self.connect():
logging.debug(f"Rigctl intialized")
return True
else:
structlog.get_logger("structlog").error("[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port)
structlog.get_logger("structlog").error(
"[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port
)
return False
def connect(self):
"""Connect to rigctld instance"""
if not self.connected:
try:
self.connection = socket.create_connection((self.hostname,self.port))
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)
structlog.get_logger("structlog").info(
"[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port
)
return True
except Exception as e:
# 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=e)
structlog.get_logger("structlog").warning(
"[RIGCTLD] Connection to rigctld refused! Reconnect...",
ip=self.hostname,
port=self.port,
e=e,
)
return False
def close_rig(self):
""" """
self.sock.close()
self.connected = False
def send_command(self, command):
"""Send a command to the connected rotctld instance,
and return the return value.
Args:
command:
command:
Returns:
"""
if self.connected:
try:
self.connection.sendall(command+b'\n')
self.connection.sendall(command + b"\n")
except:
structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port)
structlog.get_logger("structlog").warning(
"[RIGCTLD] Command not executed!",
command=command,
ip=self.hostname,
port=self.port,
)
self.connected = False
try:
return self.connection.recv(1024)
except:
structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port)
structlog.get_logger("structlog").warning(
"[RIGCTLD] No command response!",
command=command,
ip=self.hostname,
port=self.port,
)
self.connected = False
else:
# reconnecting....
time.sleep(0.5)
self.connect()
def get_mode(self):
""" """
try:
data = self.send_command(b"m")
data = data.split(b'\n')
data = data.split(b"\n")
mode = data[0]
return mode.decode("utf-8")
return mode.decode("utf-8")
except:
0
def get_bandwith(self):
""" """
try:
data = self.send_command(b"m")
data = data.split(b'\n')
data = data.split(b"\n")
bandwith = data[1]
return bandwith.decode("utf-8")
except:
return 0
def get_frequency(self):
""" """
try:
@ -131,28 +163,28 @@ class radio():
return frequency.decode("utf-8")
except:
return 0
def get_ptt(self):
""" """
try:
return self.send_command(b"t")
except:
return False
def set_ptt(self, state):
"""
Args:
state:
state:
Returns:
"""
try:
if state:
self.send_command(b"T 1")
self.send_command(b"T 1")
else:
self.send_command(b"T 0")
return state
self.send_command(b"T 0")
return state
except:
return False

View file

@ -3,32 +3,33 @@
import structlog
hamlib_version = 0
class radio:
""" """
def __init__(self):
pass
def open_rig(self, **kwargs):
def open_rig(self, **kwargs):
"""
Args:
**kwargs:
**kwargs:
Returns:
"""
return True
def get_frequency(self):
""" """
return None
def get_mode(self):
""" """
return None
def get_bandwith(self):
""" """
return None
@ -37,29 +38,28 @@ class radio:
"""
Args:
mode:
mode:
Returns:
"""
return None
def get_ptt(self):
""" """
return None
def set_ptt(self, state):
def set_ptt(self, state):
"""
Args:
state:
state:
Returns:
"""
return state
def close_rig(self):
""" """
return

View file

@ -42,34 +42,29 @@ CONNECTED_CLIENTS = set()
CLOSE_SIGNAL = False
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
"""
the socket handler base class
"""
pass
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
""" """
def send_to_client(self):
"""
function called by socket handler
send data to a network client if available
"""
tempdata = b''
tempdata = b""
while self.connection_alive and not CLOSE_SIGNAL:
# send tnc state as network stream
# check server port against daemon port and send corresponding data
if self.server.server_address[1] == static.PORT and not static.TNCSTARTED:
data = send_tnc_state()
if data != tempdata:
@ -81,15 +76,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
tempdata = data
SOCKET_QUEUE.put(data)
time.sleep(0.5)
while not SOCKET_QUEUE.empty():
data = SOCKET_QUEUE.get()
sock_data = bytes(data, 'utf-8')
sock_data += b'\n' # append line limiter
sock_data = bytes(data, "utf-8")
sock_data += b"\n" # append line limiter
# send data to all clients
#try:
# try:
for client in CONNECTED_CLIENTS:
try:
client.send(sock_data)
@ -101,8 +95,8 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
# we want to transmit scatter data only once to reduce network traffic
static.SCATTER = []
# we want to display INFO messages only once
static.INFO = []
#self.request.sendall(sock_data)
static.INFO = []
# self.request.sendall(sock_data)
time.sleep(0.15)
def receive_from_client(self):
@ -115,18 +109,17 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
try:
chunk = self.request.recv(1024)
data += chunk
if chunk == b'':
#print("connection broken. Closing...")
self.connection_alive = False
if data.startswith(b'{') and data.endswith(b'}\n'):
if chunk == b"":
# print("connection broken. Closing...")
self.connection_alive = False
if data.startswith(b"{") and data.endswith(b"}\n"):
# 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
data.remove(b'')
data.remove(b"")
# iterate thorugh data list
for commands in data:
if self.server.server_address[1] == static.PORT:
@ -136,19 +129,22 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
# wait some time between processing multiple commands
# this is only a first test to avoid doubled transmission
# we might improve this by only processing one command or
# we might improve this by only processing one command or
# doing some kind of selection to determin which commands need to be dropped
# and which one can be processed during a running transmission
time.sleep(3)
# finally delete our rx buffer to be ready for new commands
data = bytes()
except Exception as e:
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e)
structlog.get_logger("structlog").info(
"[SCK] Connection closed",
ip=self.client_address[0],
port=self.client_address[1],
e=e,
)
self.connection_alive = False
def handle(self):
"""
socket handler
@ -156,25 +152,38 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
CONNECTED_CLIENTS.add(self.request)
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1])
structlog.get_logger("structlog").debug(
"[SCK] Client connected",
ip=self.client_address[0],
port=self.client_address[1],
)
self.connection_alive = True
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start()
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start()
self.sendThread = threading.Thread(
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
while self.connection_alive and not CLOSE_SIGNAL:
time.sleep(1)
def finish(self):
""" """
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1])
structlog.get_logger("structlog").warning(
"[SCK] Closing client socket",
ip=self.client_address[0],
port=self.client_address[1],
)
try:
CONNECTED_CLIENTS.remove(self.request)
except:
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request)
structlog.get_logger("structlog").warning(
"[SCK] client connection already removed from client list",
client=self.request,
)
def process_tnc_commands(data):
@ -182,7 +191,7 @@ def process_tnc_commands(data):
process tnc commands
Args:
data:
data:
Returns:
@ -194,58 +203,73 @@ def process_tnc_commands(data):
received_json = json.loads(data)
structlog.get_logger("structlog").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 e:
command_response("tx_audio_level", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("tx_audio_level", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# 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:
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME'])
data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
command_response("send_test_frame", True)
except Exception as e:
command_response("send_test_frame", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("send_test_frame", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# CQ CQ CQ -----------------------------------------------------
if received_json["command"] == "cqcqcq":
try:
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ'])
data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
command_response("cqcqcq", True)
except Exception as e:
command_response("cqcqcq", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("cqcqcq", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# START_BEACON -----------------------------------------------------
if received_json["command"] == "start_beacon":
try:
static.BEACON_STATE = True
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)
except Exception as e:
command_response("start_beacon", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("start_beacon", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# STOP_BEACON -----------------------------------------------------
if received_json["command"] == "stop_beacon":
try:
try:
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
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)
except Exception as e:
command_response("stop_beacon", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("stop_beacon", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# 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
try:
dxcallsign = received_json["dxcallsign"]
@ -255,16 +279,17 @@ def process_tnc_commands(data):
# then we are forcing a station ssid = 0
dxcallsign = helpers.callsign_to_bytes(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)
except Exception as e:
except Exception as e:
command_response("ping", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# 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
# send ping frame and wait for ACK
try:
@ -275,31 +300,35 @@ def process_tnc_commands(data):
# then we are forcing a station ssid = 0
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
static.DXCALLSIGN = dxcallsign
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
data_handler.DATA_QUEUE_TRANSMIT.put(['CONNECT', dxcallsign])
data_handler.DATA_QUEUE_TRANSMIT.put(["CONNECT", dxcallsign])
command_response("connect", True)
except Exception as e:
command_response("connect", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("connect", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# 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
try:
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT'])
data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
command_response("disconnect", True)
except Exception as e:
except Exception as e:
command_response("disconnect", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# 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
try:
try:
if not static.ARQ_SESSION:
dxcallsign = received_json["parameter"][0]["dxcallsign"]
# additional step for beeing sure our callsign is correctly
@ -314,91 +343,113 @@ def process_tnc_commands(data):
dxcallsign = static.DXCALLSIGN
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
mode = int(received_json["parameter"][0]["mode"])
n_frames = int(received_json["parameter"][0]["n_frames"])
base64data = received_json["parameter"][0]["data"]
# check if specific callsign is set with different SSID than the TNC is initialized
try:
mycallsign = received_json["parameter"][0]["mycallsign"]
except:
mycallsign = static.MYCALLSIGN
# check if transmission uuid provided else set no-uuid
try:
arq_uuid = received_json["uuid"]
except:
arq_uuid = 'no-uuid'
if not len(base64data) % 4:
arq_uuid = "no-uuid"
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 e:
command_response("send_raw", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("send_raw", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# STOP TRANSMISSION ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission":
# 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'])
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
static.TNC_STATE = 'IDLE'
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
structlog.get_logger("structlog").warning(
"[TNC] Stopping transmission!"
)
static.TNC_STATE = "IDLE"
static.ARQ_STATE = False
command_response("stop_transmission", True)
except Exception as e:
command_response("stop_transmission", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("stop_transmission", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, 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:
output = {
"command": "rx_buffer",
"data-array": [],
}
for i in range(0, len(static.RX_BUFFER)):
#print(static.RX_BUFFER[i][4])
#rawdata = json.loads(static.RX_BUFFER[i][4])
# 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))
# self.request.sendall(bytes(jsondata, encoding))
SOCKET_QUEUE.put(jsondata)
command_response("rx_buffer", True)
except Exception as e:
command_response("rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer':
except Exception as e:
command_response("rx_buffer", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
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 e:
command_response("del_rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("del_rx_buffer", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# exception, if JSON cant be decoded
except Exception as e:
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
def send_tnc_state():
"""
send the tnc state to network
"""
encoding = 'utf-8'
encoding = "utf-8"
output = {
"command": "tnc_state",
@ -410,7 +461,7 @@ def send_tnc_state():
"audio_rms": str(static.AUDIO_RMS),
"snr": str(static.SNR),
"frequency": str(static.HAMLIB_FREQUENCY),
"speed_level": str(static.ARQ_SPEED_LEVEL),
"speed_level": str(static.ARQ_SPEED_LEVEL),
"mode": str(static.HAMLIB_MODE),
"bandwith": str(static.HAMLIB_BANDWITH),
"fft": str(static.FFT),
@ -423,8 +474,8 @@ def send_tnc_state():
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
"total_bytes": str(static.TOTAL_BYTES),
"info" : static.INFO,
"beacon_state" : str(static.BEACON_STATE),
"info": static.INFO,
"beacon_state": str(static.BEACON_STATE),
"stations": [],
"mycallsign": str(static.MYCALLSIGN, encoding),
"dxcallsign": str(static.DXCALLSIGN, encoding),
@ -433,8 +484,18 @@ def send_tnc_state():
# add heard stations to heard stations object
for i in range(0, len(static.HEARD_STATIONS)):
output["stations"].append({"dxcallsign": str(static.HEARD_STATIONS[i][0], 'utf-8'), "dxgrid": str(static.HEARD_STATIONS[i][1], 'utf-8'),"timestamp": static.HEARD_STATIONS[i][2], "datatype": static.HEARD_STATIONS[i][3], "snr": static.HEARD_STATIONS[i][4], "offset": static.HEARD_STATIONS[i][5], "frequency": static.HEARD_STATIONS[i][6]})
output["stations"].append(
{
"dxcallsign": str(static.HEARD_STATIONS[i][0], "utf-8"),
"dxgrid": str(static.HEARD_STATIONS[i][1], "utf-8"),
"timestamp": static.HEARD_STATIONS[i][2],
"datatype": static.HEARD_STATIONS[i][3],
"snr": static.HEARD_STATIONS[i][4],
"offset": static.HEARD_STATIONS[i][5],
"frequency": static.HEARD_STATIONS[i][6],
}
)
jsondata = json.dumps(output)
return jsondata
@ -444,7 +505,7 @@ def process_daemon_commands(data):
process daemon commands
Args:
data:
data:
Returns:
@ -452,41 +513,57 @@ def process_daemon_commands(data):
# convert data to json object
received_json = json.loads(data)
structlog.get_logger("structlog").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:
callsign = received_json["parameter"]
if bytes(callsign, 'utf-8') == b'':
self.request.sendall(b'INVALID CALLSIGN')
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
if bytes(callsign, "utf-8") == b"":
self.request.sendall(b"INVALID CALLSIGN")
structlog.get_logger("structlog").warning(
"[DMN] SET MYCALL FAILED",
call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC,
)
else:
static.MYCALLSIGN = bytes(callsign, 'utf-8')
static.MYCALLSIGN = bytes(callsign, "utf-8")
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
command_response("mycallsign", True)
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
except Exception as e:
structlog.get_logger("structlog").info(
"[DMN] SET MYCALL",
call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC,
)
except Exception as e:
command_response("mycallsign", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'mygrid':
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
if received_json["type"] == "set" and received_json["command"] == "mygrid":
try:
mygrid = received_json["parameter"]
if bytes(mygrid, 'utf-8') == b'':
self.request.sendall(b'INVALID GRID')
if bytes(mygrid, "utf-8") == b"":
self.request.sendall(b"INVALID GRID")
else:
static.MYGRID = bytes(mygrid, 'utf-8')
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID)
static.MYGRID = bytes(mygrid, "utf-8")
structlog.get_logger("structlog").info(
"[SCK] SET MYGRID", grid=static.MYGRID
)
command_response("mygrid", True)
except Exception as e:
except Exception as e:
command_response("mygrid", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED:
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
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"])
@ -513,39 +590,47 @@ def process_daemon_commands(data):
# print some debugging parameters
for item in received_json["parameter"][0]:
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item])
structlog.get_logger("structlog").debug(
"[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_bandwith_mode, \
tuning_range_fmin, \
tuning_range_fmax, \
enable_fsk, \
tx_audio_level \
])
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_bandwith_mode,
tuning_range_fmin,
tuning_range_fmax,
enable_fsk,
tx_audio_level,
]
)
command_response("start_tnc", True)
except Exception as e:
command_response("start_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'get' and received_json["command"] == 'test_hamlib':
except Exception as e:
command_response("start_tnc", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
try:
devicename = str(received_json["parameter"][0]["devicename"])
@ -560,37 +645,45 @@ 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 e:
command_response("test_hamlib", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'stop_tnc':
except Exception as e:
command_response("test_hamlib", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
if received_json["type"] == "set" and received_json["command"] == "stop_tnc":
try:
static.TNCPROCESS.kill()
# unregister process from atexit to avoid process zombies
atexit.unregister(static.TNCPROCESS.kill)
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
static.TNCSTARTED = False
command_response("stop_tnc", True)
except Exception as e:
command_response("stop_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
except Exception as e:
command_response("stop_tnc", False)
structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
def send_daemon_state():
"""
send the daemon state to network
@ -599,37 +692,37 @@ def send_daemon_state():
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
output = {
'command': 'daemon_state',
'daemon_state': [],
'python_version': str(python_version),
'hamlib_version': static.HAMLIB_VERSION,
'input_devices': static.AUDIO_INPUT_DEVICES,
'output_devices': static.AUDIO_OUTPUT_DEVICES,
'serial_devices': static.SERIAL_DEVICES,
"command": "daemon_state",
"daemon_state": [],
"python_version": str(python_version),
"hamlib_version": static.HAMLIB_VERSION,
"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'
}
"version": "0.1",
}
if static.TNCSTARTED:
output["daemon_state"].append({"status": "running"})
else:
output["daemon_state"].append({"status": "stopped"})
jsondata = json.dumps(output)
return jsondata
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] error", e=e)
return None
def command_response(command, status):
if status:
status = "OK"
else:
status = "Failed"
jsondata = {"command_response": command, "status" : status}
jsondata = {"command_response": command, "status": status}
data_out = json.dumps(jsondata)
SOCKET_QUEUE.put(data_out)

View file

@ -8,7 +8,7 @@ Here we are saving application wide variables and stats, which have to be access
Not nice, suggestions are appreciated :-)
"""
VERSION = '0.3.3-alpha'
VERSION = "0.3.3-alpha"
# DAEMON
DAEMONPORT = 3001
@ -17,16 +17,16 @@ TNCPROCESS = 0
# Operator Defaults
MYCALLSIGN = b'AA0AA'
MYCALLSIGN_CRC = b'A'
MYCALLSIGN = b"AA0AA"
MYCALLSIGN_CRC = b"A"
DXCALLSIGN = b'AA0AA'
DXCALLSIGN_CRC = b'A'
DXCALLSIGN = b"AA0AA"
DXCALLSIGN_CRC = b"A"
MYGRID = b''
DXGRID = b''
MYGRID = b""
DXGRID = b""
SSID_LIST = [] # ssid list we are responding to
SSID_LIST = [] # ssid list we are responding to
LOW_BANDWITH_MODE = False
# ---------------------------------
@ -34,7 +34,7 @@ LOW_BANDWITH_MODE = False
# Server Defaults
HOST = "0.0.0.0"
PORT = 3000
SOCKET_TIMEOUT = 1 # seconds
SOCKET_TIMEOUT = 1 # seconds
# ---------------------------------
SERIAL_DEVICES = []
# ---------------------------------
@ -43,21 +43,21 @@ SERIAL_DEVICES = []
PTT_STATE = False
TRANSMITTING = False
HAMLIB_VERSION = '0'
HAMLIB_PTT_TYPE = 'RTS'
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
HAMLIB_SERIAL_SPEED = '9600'
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
HAMLIB_STOP_BITS = '1'
HAMLIB_DATA_BITS = '8'
HAMLIB_HANDSHAKE = 'None'
HAMLIB_RADIOCONTROL = 'direct'
HAMLIB_RIGCTLD_IP = '127.0.0.1'
HAMLIB_RIGCTLD_PORT = '4532'
HAMLIB_VERSION = "0"
HAMLIB_PTT_TYPE = "RTS"
HAMLIB_DEVICE_NAME = "RIG_MODEL_DUMMY_NOVFO"
HAMLIB_DEVICE_PORT = "/dev/ttyUSB0"
HAMLIB_SERIAL_SPEED = "9600"
HAMLIB_PTT_PORT = "/dev/ttyUSB0"
HAMLIB_STOP_BITS = "1"
HAMLIB_DATA_BITS = "8"
HAMLIB_HANDSHAKE = "None"
HAMLIB_RADIOCONTROL = "direct"
HAMLIB_RIGCTLD_IP = "127.0.0.1"
HAMLIB_RIGCTLD_PORT = "4532"
HAMLIB_FREQUENCY = 0
HAMLIB_MODE = ''
HAMLIB_MODE = ""
HAMLIB_BANDWITH = 0
# -------------------------
# FreeDV Defaults
@ -75,7 +75,7 @@ AUDIO_INPUT_DEVICES = []
AUDIO_OUTPUT_DEVICES = []
AUDIO_INPUT_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
FFT = [0]
@ -96,11 +96,13 @@ ARQ_SPEED_LEVEL = 0
TOTAL_BYTES = 0
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = 'IDLE'
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = "IDLE"
ARQ_STATE = False
ARQ_SESSION = False
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed
ARQ_SESSION_STATE = (
"disconnected" # disconnected, connecting, connected, disconnecting, failed
)
# BEACON STATE
BEACON_STATE = False
@ -110,8 +112,8 @@ BEACON_PAUSE = False
RX_BUFFER = []
RX_MSG_BUFFER = []
RX_BURST_BUFFER = []
RX_FRAME_BUFFER = b''
#RX_BUFFER_SIZE = 0
RX_FRAME_BUFFER = b""
# RX_BUFFER_SIZE = 0
# ------- HEARD STATIOS BUFFER
HEARD_STATIONS = []
@ -121,4 +123,4 @@ INFO = []
# ------- CODEC2 SETTINGS
TUNING_RANGE_FMIN = -50.0
TUNING_RANGE_FMAX = 50.0
TUNING_RANGE_FMAX = 50.0