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 json
import sys import sys
import multiprocessing import multiprocessing
@ -7,10 +6,9 @@ import atexit
atexit.register(sd._terminate) atexit.register(sd._terminate)
def get_audio_devices(): def get_audio_devices():
""" """
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
@ -18,7 +16,7 @@ def get_audio_devices():
""" """
# we need to run this on windows for multiprocessing support # we need to run this on windows for multiprocessing support
# multiprocessing.freeze_support() # multiprocessing.freeze_support()
#multiprocessing.get_context('spawn') # multiprocessing.get_context('spawn')
# we need to reset and initialize sounddevice before running the multiprocessing part. # we need to reset and initialize sounddevice before running the multiprocessing part.
# If we are not doing this at this early point, not all devices will be displayed # If we are not doing this at this early point, not all devices will be displayed
@ -29,13 +27,16 @@ def get_audio_devices():
proxy_input_devices = manager.list() proxy_input_devices = manager.list()
proxy_output_devices = manager.list() proxy_output_devices = manager.list()
#print(multiprocessing.get_start_method()) # print(multiprocessing.get_start_method())
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)) p = multiprocessing.Process(
target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)
)
p.start() p.start()
p.join() 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): def fetch_audio_devices(input_devices, output_devices):
""" """
get audio devices from portaudio get audio devices from portaudio
@ -51,7 +52,7 @@ def fetch_audio_devices(input_devices, output_devices):
devices = sd.query_devices(device=None, kind=None) devices = sd.query_devices(device=None, kind=None)
index = 0 index = 0
for device in devices: 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 # we need to do a try exception, beacuse for windows theres no audio device range
try: try:
name = device["name"] name = device["name"]
@ -63,11 +64,10 @@ def fetch_audio_devices(input_devices, output_devices):
print(e) print(e)
maxInputChannels = 0 maxInputChannels = 0
maxOutputChannels = 0 maxOutputChannels = 0
name = '' name = ""
if maxInputChannels > 0: if maxInputChannels > 0:
input_devices.append({"id": index, "name": str(name)}) input_devices.append({"id": index, "name": str(name)})
if maxOutputChannels > 0: if maxOutputChannels > 0:
output_devices.append({"id": index, "name": str(name)}) output_devices.append({"id": index, "name": str(name)})
index += 1 index += 1

View file

@ -17,6 +17,7 @@ class FREEDV_MODE(Enum):
""" """
enum for codec2 modes and names enum for codec2 modes and names
""" """
fsk_ldpc_0 = 200 fsk_ldpc_0 = 200
fsk_ldpc_1 = 201 fsk_ldpc_1 = 201
fsk_ldpc = 9 fsk_ldpc = 9
@ -25,6 +26,7 @@ class FREEDV_MODE(Enum):
datac3 = 12 datac3 = 12
allmodes = 255 allmodes = 255
# function for returning the mode value # function for returning the mode value
def freedv_get_mode_value_by_name(mode): def freedv_get_mode_value_by_name(mode):
""" """
@ -37,6 +39,7 @@ def freedv_get_mode_value_by_name(mode):
""" """
return FREEDV_MODE[mode].value return FREEDV_MODE[mode].value
# function for returning the mode name # function for returning the mode name
def freedv_get_mode_name_by_value(mode): def freedv_get_mode_name_by_value(mode):
""" """
@ -58,14 +61,14 @@ except:
sys.path.append(app_path) sys.path.append(app_path)
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...") structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
if sys.platform == 'linux': if sys.platform == "linux":
files = glob.glob('**/*libcodec2*',recursive=True) files = glob.glob("**/*libcodec2*", recursive=True)
files.append('libcodec2.so') files.append("libcodec2.so")
elif sys.platform == 'darwin': elif sys.platform == "darwin":
files = glob.glob('**/*libcodec2*.dylib',recursive=True) files = glob.glob("**/*libcodec2*.dylib", recursive=True)
elif sys.platform == 'win32' or sys.platform == 'win64': elif sys.platform == "win32" or sys.platform == "win64":
files = glob.glob('**\*libcodec2*.dll',recursive=True) files = glob.glob("**\*libcodec2*.dll", recursive=True)
else: else:
files = [] files = []
@ -76,21 +79,21 @@ for file in files:
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file) structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
break break
except Exception as e: 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 # quit module if codec2 cant be loaded
if not 'api' in locals(): if not "api" in locals():
structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded", path=file) structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded", path=file)
os._exit(1) os._exit(1)
# ctypes function init # ctypes function init
#api.freedv_set_tuning_range.restype = c_int # 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.argype = [c_void_p, c_float, c_float]
api.freedv_open.argype = [c_int] api.freedv_open.argype = [c_int]
api.freedv_open.restype = c_void_p api.freedv_open.restype = c_void_p
@ -151,6 +154,7 @@ api.FREEDV_MODE_FSK_LDPC = 9
# advanced structure for fsk modes # advanced structure for fsk modes
class ADVANCED(ctypes.Structure): class ADVANCED(ctypes.Structure):
""" """ """ """
_fields_ = [ _fields_ = [
("interleave_frames", ctypes.c_int), ("interleave_frames", ctypes.c_int),
("M", ctypes.c_int), ("M", ctypes.c_int),
@ -161,7 +165,8 @@ class ADVANCED(ctypes.Structure):
("codename", ctypes.c_char_p), ("codename", ctypes.c_char_p),
] ]
'''
"""
adv.interleave_frames = 0 # max amplitude adv.interleave_frames = 0 # max amplitude
adv.M = 2 # number of fsk tones 2/4 adv.M = 2 # number of fsk tones 2/4
adv.Rs = 100 # symbol rate adv.Rs = 100 # symbol rate
@ -181,7 +186,7 @@ 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_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_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
''' """
# --------------- 2 FSK H_128_256_5, 16 bytes # --------------- 2 FSK H_128_256_5, 16 bytes
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED() 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.interleave_frames = 0
@ -189,8 +194,8 @@ 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.Rs = 100
api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000 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.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.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.codename = "H_128_256_5".encode("utf-8") # code word
# --------------- 4 H_256_512_4, 7 bytes # --------------- 4 H_256_512_4, 7 bytes
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED() api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED()
@ -200,11 +205,11 @@ 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.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.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 STRUCTURES
MODEM_STATS_NC_MAX = 50+1 MODEM_STATS_NC_MAX = 50 + 1
MODEM_STATS_NR_MAX = 160 MODEM_STATS_NR_MAX = 160
MODEM_STATS_ET_MAX = 8 MODEM_STATS_ET_MAX = 8
MODEM_STATS_EYE_IND_MAX = 160 MODEM_STATS_EYE_IND_MAX = 160
@ -214,10 +219,11 @@ MODEM_STATS_MAX_F_EST = 4
# modem stats structure # modem stats structure
class MODEMSTATS(ctypes.Structure): class MODEMSTATS(ctypes.Structure):
""" """ """ """
_fields_ = [ _fields_ = [
("Nc", ctypes.c_int), ("Nc", ctypes.c_int),
("snr_est", ctypes.c_float), ("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), ("nr", ctypes.c_int),
("sync", ctypes.c_int), ("sync", ctypes.c_int),
("foff", ctypes.c_float), ("foff", ctypes.c_float),
@ -229,17 +235,21 @@ class MODEMSTATS(ctypes.Structure):
("uw_fails", ctypes.c_int), ("uw_fails", ctypes.c_int),
("neyetr", ctypes.c_int), # How many eye traces are plotted ("neyetr", ctypes.c_int), # How many eye traces are plotted
("neyesamp", ctypes.c_int), # How many samples in the eye diagram ("neyesamp", ctypes.c_int), # How many samples in the eye diagram
("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), # How many samples in the eye diagram (
"f_est",
(ctypes.c_float * MODEM_STATS_MAX_F_EST),
), # How many samples in the eye diagram
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)), ("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
] ]
# Return code flags for freedv_get_rx_status() function # Return code flags for freedv_get_rx_status() function
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
api.FREEDV_RX_BITS = 0x4 # data bits have been returned 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_BIT_ERRORS = (
0x8 # FEC may not have corrected all bit errors (not all parity checks OK)
)
api.rx_sync_flags_to_text = [ api.rx_sync_flags_to_text = [
"----", "----",
@ -257,25 +267,31 @@ api.rx_sync_flags_to_text = [
"EB--", "EB--",
"EB-T", "EB-T",
"EBS-", "EBS-",
"EBST"] "EBST",
]
# audio buffer --------------------------------------------------------- # audio buffer ---------------------------------------------------------
class audio_buffer: class audio_buffer:
""" """
thread safe audio buffer, which fits to needs of codec2 thread safe audio buffer, which fits to needs of codec2
made by David Rowe, VK5DGR made by David Rowe, VK5DGR
""" """
# a buffer of int16 samples, using a fixed length numpy array self.buffer for storage # a buffer of int16 samples, using a fixed length numpy array self.buffer for storage
# self.nbuffer is the current number of samples in the buffer # self.nbuffer is the current number of samples in the buffer
def __init__(self, size): def __init__(self, size):
structlog.get_logger("structlog").debug("[C2 ] creating audio buffer", size=size) structlog.get_logger("structlog").debug(
"[C2 ] creating audio buffer", size=size
)
self.size = size self.size = size
self.buffer = np.zeros(size, dtype=np.int16) self.buffer = np.zeros(size, dtype=np.int16)
self.nbuffer = 0 self.nbuffer = 0
self.mutex = Lock() self.mutex = Lock()
def push(self,samples):
def push(self, samples):
""" """
Push new data to buffer Push new data to buffer
@ -287,11 +303,12 @@ class audio_buffer:
""" """
self.mutex.acquire() self.mutex.acquire()
# add samples at the end of the buffer # add samples at the end of the buffer
assert self.nbuffer+len(samples) <= self.size assert self.nbuffer + len(samples) <= self.size
self.buffer[self.nbuffer:self.nbuffer+len(samples)] = samples self.buffer[self.nbuffer : self.nbuffer + len(samples)] = samples
self.nbuffer += len(samples) self.nbuffer += len(samples)
self.mutex.release() self.mutex.release()
def pop(self,size):
def pop(self, size):
""" """
get data from buffer in size of NIN get data from buffer in size of NIN
Args: Args:
@ -302,23 +319,28 @@ class audio_buffer:
""" """
self.mutex.acquire() self.mutex.acquire()
# remove samples from the start of the buffer # remove samples from the start of the buffer
self.nbuffer -= size; self.nbuffer -= size
self.buffer[:self.nbuffer] = self.buffer[size:size+self.nbuffer] self.buffer[: self.nbuffer] = self.buffer[size : size + self.nbuffer]
assert self.nbuffer >= 0 assert self.nbuffer >= 0
self.mutex.release() self.mutex.release()
# resampler --------------------------------------------------------- # resampler ---------------------------------------------------------
api.FDMDV_OS_48 = int(6) # oversampling rate 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_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_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_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] api.fdmdv_48_to_8_short.argtype = [c_void_p, c_void_p, c_int]
class resampler: class resampler:
""" """
resampler class resampler class
""" """
# resample an array of variable length, we just store the filter memories here # resample an array of variable length, we just store the filter memories here
MEM8 = api.FDMDV_OS_TAPS_48_8K MEM8 = api.FDMDV_OS_TAPS_48_8K
MEM48 = api.FDMDV_OS_TAPS_48K MEM48 = api.FDMDV_OS_TAPS_48K
@ -328,8 +350,7 @@ class resampler:
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16) self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
self.filter_mem48 = np.zeros(self.MEM48) self.filter_mem48 = np.zeros(self.MEM48)
def resample48_to_8(self, in48):
def resample48_to_8(self,in48):
""" """
audio resampler integration from codec2 audio resampler integration from codec2
downsample audio from 48000Hz to 8000Hz downsample audio from 48000Hz to 8000Hz
@ -341,25 +362,25 @@ class resampler:
""" """
assert in48.dtype == np.int16 assert in48.dtype == np.int16
# length of input vector must be an integer multiple of api.FDMDV_OS_48 # 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 # concat filter memory and input samples
in48_mem = np.zeros(self.MEM48+len(in48), dtype=np.int16) in48_mem = np.zeros(self.MEM48 + len(in48), dtype=np.int16)
in48_mem[:self.MEM48] = self.filter_mem48 in48_mem[: self.MEM48] = self.filter_mem48
in48_mem[self.MEM48:] = in48 in48_mem[self.MEM48 :] = in48
# In C: pin48=&in48_mem[MEM48] # 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) n8 = int(len(in48) / api.FDMDV_OS_48)
out8 = np.zeros(n8, dtype=np.int16) 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 # store memory for next time
self.filter_mem48 = in48_mem[:self.MEM48] self.filter_mem48 = in48_mem[: self.MEM48]
return out8 return out8
def resample8_to_48(self,in8): def resample8_to_48(self, in8):
""" """
audio resampler integration from codec2 audio resampler integration from codec2
resample audio from 8000Hz to 48000Hz resample audio from 8000Hz to 48000Hz
@ -372,16 +393,16 @@ class resampler:
assert in8.dtype == np.int16 assert in8.dtype == np.int16
# concat filter memory and input samples # concat filter memory and input samples
in8_mem = np.zeros(self.MEM8+len(in8), dtype=np.int16) in8_mem = np.zeros(self.MEM8 + len(in8), dtype=np.int16)
in8_mem[:self.MEM8] = self.filter_mem8 in8_mem[: self.MEM8] = self.filter_mem8
in8_mem[self.MEM8:] = in8 in8_mem[self.MEM8 :] = in8
# In C: pin8=&in8_mem[MEM8] # In C: pin8=&in8_mem[MEM8]
pin8 = byref(np.ctypeslib.as_ctypes(in8_mem), 2*self.MEM8) pin8 = byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8)
out48 = np.zeros(api.FDMDV_OS_48*len(in8), dtype=np.int16) out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16)
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8)); api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8))
# store memory for next time # store memory for next time
self.filter_mem8 = in8_mem[:self.MEM8] self.filter_mem8 = in8_mem[: self.MEM8]
return out48 return out48

View file

@ -43,35 +43,39 @@ def signal_handler(sig, frame):
Returns: system exit Returns: system exit
""" """
print('Closing daemon...') print("Closing daemon...")
sock.CLOSE_SIGNAL = True sock.CLOSE_SIGNAL = True
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
class DAEMON:
class DAEMON():
""" """
daemon class daemon class
""" """
def __init__(self): def __init__(self):
# load crc engine # load crc engine
self.crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc8 library self.crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library
self.daemon_queue = sock.DAEMON_QUEUE self.daemon_queue = sock.DAEMON_QUEUE
update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True) update_audio_devices = threading.Thread(
target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True
)
update_audio_devices.start() update_audio_devices.start()
update_serial_devices = threading.Thread(target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True) update_serial_devices = threading.Thread(
target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True
)
update_serial_devices.start() update_serial_devices.start()
worker = threading.Thread(target=self.worker, name="WORKER", daemon=True) worker = threading.Thread(target=self.worker, name="WORKER", daemon=True)
worker.start() worker.start()
def update_audio_devices(self): def update_audio_devices(self):
""" """
update audio devices and set to static update audio devices and set to static
@ -80,29 +84,33 @@ class DAEMON():
try: try:
if not static.TNCSTARTED: 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: except Exception as e:
print(e) print(e)
time.sleep(1) time.sleep(1)
def update_serial_devices(self): def update_serial_devices(self):
""" """
update serial devices and set to static update serial devices and set to static
""" """
while 1: while 1:
try: try:
#print("update serial") # print("update serial")
serial_devices = [] serial_devices = []
ports = serial.tools.list_ports.comports() ports = serial.tools.list_ports.comports()
for port, desc, hwid in ports: for port, desc, hwid in ports:
# calculate hex of hwid if we have unique names # calculate hex of hwid if we have unique names
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8')) crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
crc_hwid = crc_hwid.to_bytes(2, byteorder='big') crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
crc_hwid = crc_hwid.hex() crc_hwid = crc_hwid.hex()
description = desc + ' [' + crc_hwid + ']' description = desc + " [" + crc_hwid + "]"
serial_devices.append({"port": str(port), "description": str(description) }) serial_devices.append(
{"port": str(port), "description": str(description)}
)
static.SERIAL_DEVICES = serial_devices static.SERIAL_DEVICES = serial_devices
time.sleep(1) time.sleep(1)
@ -139,131 +147,134 @@ class DAEMON():
# data[19] tuning_range_fmin # data[19] tuning_range_fmin
# data[20] tuning_range_fmax # data[20] tuning_range_fmax
if data[0] == 'STARTTNC': if data[0] == "STARTTNC":
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6]) 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 # list of parameters, necessary for running subprocess command as a list
options = [] options = []
options.append('--port') options.append("--port")
options.append(str(static.DAEMONPORT - 1)) options.append(str(static.DAEMONPORT - 1))
options.append('--mycall') options.append("--mycall")
options.append(data[1]) options.append(data[1])
options.append('--mygrid') options.append("--mygrid")
options.append(data[2]) options.append(data[2])
options.append('--rx') options.append("--rx")
options.append(data[3]) options.append(data[3])
options.append('--tx') options.append("--tx")
options.append(data[4]) options.append(data[4])
# if radiocontrol != disabled # if radiocontrol != disabled
# this should hopefully avoid a ton of problems if we are just running in # this should hopefully avoid a ton of problems if we are just running in
# disabled mode # disabled mode
if data[13] != 'disabled': if data[13] != "disabled":
options.append('--devicename') options.append("--devicename")
options.append(data[5]) options.append(data[5])
options.append('--deviceport') options.append("--deviceport")
options.append(data[6]) options.append(data[6])
options.append('--serialspeed') options.append("--serialspeed")
options.append(data[7]) options.append(data[7])
options.append('--pttprotocol') options.append("--pttprotocol")
options.append(data[8]) options.append(data[8])
options.append('--pttport') options.append("--pttport")
options.append(data[9]) options.append(data[9])
options.append('--data_bits') options.append("--data_bits")
options.append(data[10]) options.append(data[10])
options.append('--stop_bits') options.append("--stop_bits")
options.append(data[11]) options.append(data[11])
options.append('--handshake') options.append("--handshake")
options.append(data[12]) options.append(data[12])
options.append('--radiocontrol') options.append("--radiocontrol")
options.append(data[13]) options.append(data[13])
if data[13] != 'rigctld': if data[13] != "rigctld":
options.append('--rigctld_ip') options.append("--rigctld_ip")
options.append(data[14]) options.append(data[14])
options.append('--rigctld_port') options.append("--rigctld_port")
options.append(data[15]) options.append(data[15])
if data[16] == 'True': if data[16] == "True":
options.append('--scatter') options.append("--scatter")
if data[17] == 'True': if data[17] == "True":
options.append('--fft') options.append("--fft")
if data[18] == 'True': if data[18] == "True":
options.append('--500hz') options.append("--500hz")
options.append("--tuning_range_fmin")
options.append('--tuning_range_fmin')
options.append(data[19]) options.append(data[19])
options.append('--tuning_range_fmax') options.append("--tuning_range_fmax")
options.append(data[20]) options.append(data[20])
# overriding FSK mode # overriding FSK mode
#if data[21] == 'True': # if data[21] == 'True':
# options.append('--fsk') # options.append('--fsk')
options.append('--tx-audio-level') options.append("--tx-audio-level")
options.append(data[22]) options.append(data[22])
# try running tnc from binary, else run from source # try running tnc from binary, else run from source
# this helps running the tnc in a developer environment # this helps running the tnc in a developer environment
try: try:
command = [] command = []
if sys.platform == 'linux' or sys.platform == 'darwin': if sys.platform == "linux" or sys.platform == "darwin":
command.append('./freedata-tnc') command.append("./freedata-tnc")
elif sys.platform == 'win32' or sys.platform == 'win64': elif sys.platform == "win32" or sys.platform == "win64":
command.append('freedata-tnc.exe') command.append("freedata-tnc.exe")
command += options command += options
p = subprocess.Popen(command) p = subprocess.Popen(command)
atexit.register(p.kill) atexit.register(p.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary") structlog.get_logger("structlog").info(
"[DMN] TNC started", path="binary"
)
except: except:
command = [] command = []
if sys.platform == 'linux' or sys.platform == 'darwin': if sys.platform == "linux" or sys.platform == "darwin":
command.append('python3') command.append("python3")
elif sys.platform == 'win32' or sys.platform == 'win64': elif sys.platform == "win32" or sys.platform == "win64":
command.append('python') command.append("python")
command.append('main.py') command.append("main.py")
command += options command += options
p = subprocess.Popen(command) p = subprocess.Popen(command)
atexit.register(p.kill) atexit.register(p.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="source") structlog.get_logger("structlog").info(
"[DMN] TNC started", path="source"
)
static.TNCPROCESS = p # .pid static.TNCPROCESS = p # .pid
static.TNCSTARTED = True static.TNCSTARTED = True
''' """
# WE HAVE THIS PART in SOCKET # WE HAVE THIS PART in SOCKET
if data[0] == 'STOPTNC': if data[0] == 'STOPTNC':
static.TNCPROCESS.kill() static.TNCPROCESS.kill()
structlog.get_logger("structlog").warning("[DMN] Stopping TNC") structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
#os.kill(static.TNCPROCESS, signal.SIGKILL) #os.kill(static.TNCPROCESS, signal.SIGKILL)
static.TNCSTARTED = False static.TNCSTARTED = False
''' """
# data[1] devicename # data[1] devicename
# data[2] deviceport # data[2] deviceport
# data[3] serialspeed # data[3] serialspeed
@ -275,7 +286,7 @@ class DAEMON():
# data[9] radiocontrol # data[9] radiocontrol
# data[10] rigctld_ip # data[10] rigctld_ip
# data[11] rigctld_port # data[11] rigctld_port
if data[0] == 'TEST_HAMLIB': if data[0] == "TEST_HAMLIB":
devicename = data[1] devicename = data[1]
deviceport = data[2] deviceport = data[2]
@ -289,20 +300,29 @@ class DAEMON():
rigctld_ip = data[10] rigctld_ip = data[10]
rigctld_port = data[11] rigctld_port = data[11]
# check how we want to control the radio # check how we want to control the radio
if radiocontrol == 'direct': if radiocontrol == "direct":
import rig import rig
elif radiocontrol == 'rigctl': elif radiocontrol == "rigctl":
import rigctl as rig import rigctl as rig
elif radiocontrol == 'rigctld': elif radiocontrol == "rigctld":
import rigctld as rig import rigctld as rig
else: else:
import rigdummy as rig import rigdummy as rig
hamlib = rig.radio() hamlib = rig.radio()
hamlib.open_rig(devicename=devicename, deviceport=deviceport, hamlib_ptt_type=pttprotocol, 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_version = rig.hamlib_version
@ -310,14 +330,20 @@ class DAEMON():
pttstate = hamlib.get_ptt() pttstate = hamlib.get_ptt()
if pttstate: if pttstate:
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS') structlog.get_logger("structlog").info(
response = {'command': 'test_hamlib', 'result': 'SUCCESS'} "[DMN] Hamlib PTT", status="SUCCESS"
)
response = {"command": "test_hamlib", "result": "SUCCESS"}
elif not pttstate: elif not pttstate:
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS') structlog.get_logger("structlog").warning(
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'} "[DMN] Hamlib PTT", status="NO SUCCESS"
)
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
else: else:
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED') structlog.get_logger("structlog").error(
response = {'command': 'test_hamlib', 'result': 'FAILED'} "[DMN] Hamlib PTT", status="FAILED"
)
response = {"command": "test_hamlib", "result": "FAILED"}
hamlib.set_ptt(False) hamlib.set_ptt(False)
hamlib.close_rig() hamlib.close_rig()
@ -329,29 +355,38 @@ class DAEMON():
print(e) print(e)
if __name__ == "__main__":
if __name__ == '__main__':
# we need to run this on windows for multiprocessing support # we need to run this on windows for multiprocessing support
multiprocessing.freeze_support() multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='FreeDATA Daemon') PARSER = argparse.ArgumentParser(description="FreeDATA Daemon")
PARSER.add_argument('--port', dest="socket_port",default=3001, help="Socket port in the range of 1024-65536", type=int) PARSER.add_argument(
"--port",
dest="socket_port",
default=3001,
help="Socket port in the range of 1024-65536",
type=int,
)
ARGS = PARSER.parse_args() ARGS = PARSER.parse_args()
static.DAEMONPORT = ARGS.socket_port static.DAEMONPORT = ARGS.socket_port
try: try:
if sys.platform == 'linux': if sys.platform == "linux":
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon' logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
if sys.platform == 'darwin': if sys.platform == "darwin":
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon' logging_path = (
os.getenv("HOME")
+ "/Library/"
+ "Application Support/"
+ "FreeDATA/"
+ "daemon"
)
if sys.platform == 'win32' or sys.platform == 'win64': if sys.platform == "win32" or sys.platform == "win64":
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon' logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
if not os.path.exists(logging_path): if not os.path.exists(logging_path):
os.makedirs(logging_path) os.makedirs(logging_path)
@ -360,20 +395,30 @@ if __name__ == '__main__':
structlog.get_logger("structlog").error("[DMN] logger init error") structlog.get_logger("structlog").error("[DMN] logger init error")
try: 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 # https://stackoverflow.com/a/16641793
socketserver.TCPServer.allow_reuse_address = True socketserver.TCPServer.allow_reuse_address = True
cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler) cmdserver = sock.ThreadedTCPServer(
(static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler
)
server_thread = threading.Thread(target=cmdserver.serve_forever) server_thread = threading.Thread(target=cmdserver.serve_forever)
server_thread.daemon = True server_thread.daemon = True
server_thread.start() server_thread.start()
except Exception as e: except Exception as 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) os._exit(1)
daemon = DAEMON() daemon = DAEMON()
structlog.get_logger("structlog").info(
structlog.get_logger("structlog").info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION) "[DMN] Starting FreeDATA Daemon",
author="DJ2LS",
year="2022",
version=static.VERSION,
)
while True: while True:
time.sleep(1) time.sleep(1)

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,6 @@ import crcengine
import static import static
def wait(seconds): def wait(seconds):
""" """
@ -28,7 +27,6 @@ def wait(seconds):
return True return True
def get_crc_8(data): def get_crc_8(data):
"""Author: DJ2LS """Author: DJ2LS
@ -42,9 +40,9 @@ def get_crc_8(data):
Returns: 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_algorithm(data)
crc_data = crc_data.to_bytes(1, byteorder='big') crc_data = crc_data.to_bytes(1, byteorder="big")
return crc_data return crc_data
@ -61,11 +59,12 @@ def get_crc_16(data):
Returns: 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_algorithm(data)
crc_data = crc_data.to_bytes(2, byteorder='big') crc_data = crc_data.to_bytes(2, byteorder="big")
return crc_data return crc_data
def get_crc_32(data): def get_crc_32(data):
"""Author: DJ2LS """Author: DJ2LS
@ -79,9 +78,9 @@ def get_crc_32(data):
Returns: 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_algorithm(data)
crc_data = crc_data.to_bytes(4, byteorder='big') crc_data = crc_data.to_bytes(4, byteorder="big")
return crc_data return crc_data
@ -102,17 +101,37 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
# check if buffer empty # check if buffer empty
if len(static.HEARD_STATIONS) == 0: if len(static.HEARD_STATIONS) == 0:
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]) static.HEARD_STATIONS.append(
[dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
)
# if not, we search and update # if not, we search and update
else: else:
for i in range(0, len(static.HEARD_STATIONS)): for i in range(0, len(static.HEARD_STATIONS)):
# update callsign with new timestamp # update callsign with new timestamp
if static.HEARD_STATIONS[i].count(dxcallsign) > 0: if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
static.HEARD_STATIONS[i] = [dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency] static.HEARD_STATIONS[i] = [
dxcallsign,
dxgrid,
int(time.time()),
datatype,
snr,
offset,
frequency,
]
break break
# insert if nothing found # insert if nothing found
if i == len(static.HEARD_STATIONS) - 1: if i == len(static.HEARD_STATIONS) - 1:
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]) static.HEARD_STATIONS.append(
[
dxcallsign,
dxgrid,
int(time.time()),
datatype,
snr,
offset,
frequency,
]
)
break break
@ -122,7 +141,6 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
# static.HEARD_STATIONS[idx] = item # static.HEARD_STATIONS[idx] = item
def callsign_to_bytes(callsign): def callsign_to_bytes(callsign):
""" """
@ -133,31 +151,31 @@ def callsign_to_bytes(callsign):
""" """
# http://www.aprs.org/aprs11/SSIDs.txt # http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable # -0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc # -1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc # -2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc # -3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc # -4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc) # -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc # -6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable # -7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile # -8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable) # -9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc # -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc # -11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc # -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations # -13 Weather stations
#-14 Truckers or generally full time drivers # -14 Truckers or generally full time drivers
#-15 generic additional station, digi, mobile, wx, etc # -15 generic additional station, digi, mobile, wx, etc
# try converting to bytestring if possible type string # try converting to bytestring if possible type string
try: try:
callsign = bytes(callsign, 'utf-8') callsign = bytes(callsign, "utf-8")
except: except:
pass pass
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign ) # we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
callsign = callsign.split(b'-') callsign = callsign.split(b"-")
try: try:
ssid = int(callsign[1]) ssid = int(callsign[1])
except: except:
@ -166,11 +184,12 @@ def callsign_to_bytes(callsign):
callsign = callsign[0] callsign = callsign[0]
bytestring = bytearray(8) bytestring = bytearray(8)
bytestring[:len(callsign)] = callsign bytestring[: len(callsign)] = callsign
bytestring[7:8] = bytes([ssid]) bytestring[7:8] = bytes([ssid])
return bytes(bytestring) return bytes(bytestring)
def bytes_to_callsign(bytestring): def bytes_to_callsign(bytestring):
""" """
@ -182,40 +201,38 @@ def bytes_to_callsign(bytestring):
""" """
# http://www.aprs.org/aprs11/SSIDs.txt # http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable # -0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc # -1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc # -2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc # -3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc # -4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc) # -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc # -6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable # -7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile # -8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable) # -9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc # -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc # -11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc # -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations # -13 Weather stations
#-14 Truckers or generally full time drivers # -14 Truckers or generally full time drivers
#-15 generic additional station, digi, mobile, wx, etc # -15 generic additional station, digi, mobile, wx, etc
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign ) # we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
callsign = bytes(bytestring[:7]) callsign = bytes(bytestring[:7])
callsign = callsign.rstrip(b'\x00') callsign = callsign.rstrip(b"\x00")
ssid = int.from_bytes(bytes(bytestring[7:8]), "big") ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
callsign = callsign + b'-' callsign = callsign + b"-"
callsign = callsign.decode('utf-8') callsign = callsign.decode("utf-8")
callsign = callsign + str(ssid) callsign = callsign + str(ssid)
callsign = callsign.encode('utf-8') callsign = callsign.encode("utf-8")
return bytes(callsign) 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 Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it
@ -228,10 +245,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
False False
""" """
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
try: try:
callsign = callsign.split(b'-') callsign = callsign.split(b"-")
callsign = callsign[0] # we want the callsign without SSID callsign = callsign[0] # we want the callsign without SSID
except: except:
@ -241,10 +258,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
for ssid in static.SSID_LIST: for ssid in static.SSID_LIST:
print(ssid) print(ssid)
for ssid in static.SSID_LIST: for ssid in static.SSID_LIST:
#for ssid in range(0,254): # for ssid in range(0,254):
call_with_ssid = bytearray(callsign) call_with_ssid = bytearray(callsign)
call_with_ssid.extend('-'.encode('utf-8')) call_with_ssid.extend("-".encode("utf-8"))
call_with_ssid.extend(str(ssid).encode('utf-8')) call_with_ssid.extend(str(ssid).encode("utf-8"))
callsign_crc = get_crc_16(call_with_ssid) callsign_crc = get_crc_16(call_with_ssid)

File diff suppressed because it is too large Load diff

View file

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

View file

@ -13,18 +13,19 @@ main module for running the tnc
import argparse import argparse
import threading import threading
import static
import socketserver import socketserver
import helpers
import data_handler
import structlog
import log_handler
import modem
import sys import sys
import os import os
import signal import signal
import time import time
import multiprocessing import multiprocessing
import structlog
import modem
import static
import log_handler
import helpers
import data_handler
# signal handler for closing aplication # signal handler for closing aplication
@ -38,56 +39,202 @@ def signal_handler(sig, frame):
Returns: system exit Returns: system exit
""" """
print('Closing TNC...') print("Closing TNC...")
sock.CLOSE_SIGNAL = True sock.CLOSE_SIGNAL = True
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
if __name__ == '__main__': if __name__ == "__main__":
# we need to run this on windows for multiprocessing support # we need to run this on windows for multiprocessing support
multiprocessing.freeze_support() multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='FreeDATA TNC') PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str) PARSER.add_argument(
PARSER.add_argument('--ssid', dest="ssid_list", nargs='*', default=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], help="SSID list we are responding to", type=str) "--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str
PARSER.add_argument('--mygrid', dest="mygrid", default="JN12AA", help="My gridsquare", type=str) )
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int) PARSER.add_argument(
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int) "--ssid",
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int) dest="ssid_list",
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str) nargs="*",
PARSER.add_argument('--devicename', dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str) default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int) help="SSID list we are responding to",
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", choices=['USB', 'RIG', 'RTS', 'DTR', 'CM108', 'MICDATA', 'PARALLEL', 'DTR-H', 'DTR-L', 'NONE'], default='USB', help="PTT Type", type=str) type=str,
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str) )
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int) PARSER.add_argument(
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int) "--mygrid", dest="mygrid", default="JN12AA", help="My gridsquare", type=str
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str) )
PARSER.add_argument('--radiocontrol', dest="hamlib_radiocontrol", choices=['disabled', 'direct', 'rigctl', 'rigctld'], default="disabled", help="Set how you want to control your radio") PARSER.add_argument(
PARSER.add_argument('--rigctld_port', dest="rigctld_port", default=4532, type=int, help="Set rigctld port") "--rx",
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="localhost", help="Set rigctld ip") dest="audio_input_device",
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network") default=0,
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network") help="listening sound card",
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )") type=int,
PARSER.add_argument('--fsk', dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ") )
PARSER.add_argument('--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(
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) "--tx",
PARSER.add_argument('--tx-audio-level', dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int) 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() ARGS = PARSER.parse_args()
# additional step for beeing sure our callsign is correctly # additional step for beeing sure our callsign is correctly
# in case we are not getting a station ssid # in case we are not getting a station ssid
# then we are forcing a station ssid = 0 # then we are forcing a station ssid = 0
mycallsign = bytes(ARGS.mycall.upper(), 'utf-8') mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
mycallsign = helpers.callsign_to_bytes(mycallsign) mycallsign = helpers.callsign_to_bytes(mycallsign)
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign) static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN) static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
static.SSID_LIST = ARGS.ssid_list static.SSID_LIST = ARGS.ssid_list
static.MYGRID = bytes(ARGS.mygrid, 'utf-8') static.MYGRID = bytes(ARGS.mygrid, "utf-8")
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
static.PORT = ARGS.socket_port static.PORT = ARGS.socket_port
@ -110,20 +257,25 @@ if __name__ == '__main__':
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level 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 # we need to wait until we got all parameters from argparse first before we can load the other modules
import sock import sock
# config logging # config logging
try: try:
if sys.platform == 'linux': if sys.platform == "linux":
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc' logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
if sys.platform == 'darwin': if sys.platform == "darwin":
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc' logging_path = (
os.getenv("HOME")
+ "/Library/"
+ "Application Support/"
+ "FreeDATA/"
+ "tnc"
)
if sys.platform == 'win32' or sys.platform == 'win64': if sys.platform in ["win32", "win64"]:
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc' logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
if not os.path.exists(logging_path): if not os.path.exists(logging_path):
os.makedirs(logging_path) os.makedirs(logging_path)
@ -131,9 +283,9 @@ if __name__ == '__main__':
except: 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 # start data handler
data_handler.DATA() data_handler.DATA()
@ -141,21 +293,26 @@ if __name__ == '__main__':
# start modem # start modem
modem = modem.RF() modem = modem.RF()
# --------------------------------------------START CMD SERVER # --------------------------------------------START CMD SERVER
try: 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 # https://stackoverflow.com/a/16641793
socketserver.TCPServer.allow_reuse_address = True socketserver.TCPServer.allow_reuse_address = True
cmdserver = sock.ThreadedTCPServer((static.HOST, static.PORT), sock.ThreadedTCPRequestHandler) cmdserver = sock.ThreadedTCPServer(
(static.HOST, static.PORT), sock.ThreadedTCPRequestHandler
)
server_thread = threading.Thread(target=cmdserver.serve_forever) server_thread = threading.Thread(target=cmdserver.serve_forever)
server_thread.daemon = True server_thread.daemon = True
server_thread.start() server_thread.start()
except Exception as e: except Exception as 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) os._exit(1)
while 1: while 1:
time.sleep(1) time.sleep(1)

View file

@ -41,7 +41,7 @@ RECEIVE_DATAC3 = False
RECEIVE_FSK_LDPC_1 = False RECEIVE_FSK_LDPC_1 = False
class RF(): class RF:
""" """ """ """
def __init__(self): def __init__(self):
@ -49,13 +49,16 @@ class RF():
self.sampler_avg = 0 self.sampler_avg = 0
self.buffer_avg = 0 self.buffer_avg = 0
self.AUDIO_SAMPLE_RATE_RX = 48000 self.AUDIO_SAMPLE_RATE_RX = 48000
self.AUDIO_SAMPLE_RATE_TX = 48000 self.AUDIO_SAMPLE_RATE_TX = 48000
self.MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000 self.MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000
self.AUDIO_FRAMES_PER_BUFFER_RX = 2400*2 #8192 self.AUDIO_FRAMES_PER_BUFFER_RX = 2400 * 2 # 8192
self.AUDIO_FRAMES_PER_BUFFER_TX = 2400*2 #8192 Lets to some tests with very small chunks for TX self.AUDIO_FRAMES_PER_BUFFER_TX = (
self.AUDIO_CHUNKS = 48 #8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) #48 2400 * 2
) # 8192 Lets to some tests with very small chunks for TX
self.AUDIO_CHUNKS = (
48 # 8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) #48
)
self.AUDIO_CHANNELS = 1 self.AUDIO_CHANNELS = 1
# locking state for mod out so buffer will be filled before we can use it # locking state for mod out so buffer will be filled before we can use it
@ -64,7 +67,9 @@ class RF():
self.mod_out_locked = True self.mod_out_locked = True
# make sure our resampler will work # make sure our resampler will work
assert (self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48 assert (
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48
# small hack for initializing codec2 via codec2.py module # small hack for initializing codec2 via codec2.py module
# TODO: we need to change the entire modem module to integrate codec2 module # TODO: we need to change the entire modem module to integrate codec2 module
@ -81,43 +86,94 @@ class RF():
self.fft_data = bytes() self.fft_data = bytes()
# open codec2 instance # open codec2 instance
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p) self.datac0_freedv = cast(
self.c_lib.freedv_set_tuning_range(self.datac0_freedv, c_float(static.TUNING_RANGE_FMIN), c_float(static.TUNING_RANGE_FMAX)) codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p
self.datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv)/8) )
self.datac0_payload_per_frame = self.datac0_bytes_per_frame -2 self.c_lib.freedv_set_tuning_range(
self.datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(self.datac0_freedv) self.datac0_freedv,
self.datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(self.datac0_freedv) c_float(static.TUNING_RANGE_FMIN),
self.datac0_n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.datac0_freedv) c_float(static.TUNING_RANGE_FMAX),
self.datac0_n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.datac0_freedv) )
self.datac0_bytes_per_frame = int(
codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv) / 8
)
self.datac0_payload_per_frame = self.datac0_bytes_per_frame - 2
self.datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(
self.datac0_freedv
)
self.datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(
self.datac0_freedv
)
self.datac0_n_tx_preamble_modem_samples = (
self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.datac0_freedv)
)
self.datac0_n_tx_postamble_modem_samples = (
self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.datac0_freedv)
)
self.datac0_bytes_out = create_string_buffer(self.datac0_bytes_per_frame) self.datac0_bytes_out = create_string_buffer(self.datac0_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac0_freedv,1) codec2.api.freedv_set_frames_per_burst(self.datac0_freedv, 1)
self.datac0_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.datac1_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p) self.datac1_freedv = cast(
self.c_lib.freedv_set_tuning_range(self.datac1_freedv, c_float(static.TUNING_RANGE_FMIN), c_float(static.TUNING_RANGE_FMAX)) codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p
self.datac1_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv)/8) )
self.c_lib.freedv_set_tuning_range(
self.datac1_freedv,
c_float(static.TUNING_RANGE_FMIN),
c_float(static.TUNING_RANGE_FMAX),
)
self.datac1_bytes_per_frame = int(
codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8
)
self.datac1_bytes_out = create_string_buffer(self.datac1_bytes_per_frame) self.datac1_bytes_out = create_string_buffer(self.datac1_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv,1) codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, 1)
self.datac1_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.datac3_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p) self.datac3_freedv = cast(
self.c_lib.freedv_set_tuning_range(self.datac3_freedv, c_float(static.TUNING_RANGE_FMIN), c_float(static.TUNING_RANGE_FMAX)) codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p
self.datac3_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv)/8) )
self.c_lib.freedv_set_tuning_range(
self.datac3_freedv,
c_float(static.TUNING_RANGE_FMIN),
c_float(static.TUNING_RANGE_FMAX),
)
self.datac3_bytes_per_frame = int(
codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8
)
self.datac3_bytes_out = create_string_buffer(self.datac3_bytes_per_frame) self.datac3_bytes_out = create_string_buffer(self.datac3_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv,1) codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, 1)
self.datac3_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.fsk_ldpc_freedv_0 = cast(
self.fsk_ldpc_freedv_0 = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), c_void_p) codec2.api.freedv_open_advanced(
self.fsk_ldpc_bytes_per_frame_0 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_0)/8) codec2.api.FREEDV_MODE_FSK_LDPC,
self.fsk_ldpc_bytes_out_0 = create_string_buffer(self.fsk_ldpc_bytes_per_frame_0) ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV),
#codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0,1) ),
c_void_p,
)
self.fsk_ldpc_bytes_per_frame_0 = int(
codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_0) / 8
)
self.fsk_ldpc_bytes_out_0 = create_string_buffer(
self.fsk_ldpc_bytes_per_frame_0
)
# codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0,1)
self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX)
self.fsk_ldpc_freedv_1 = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), c_void_p) self.fsk_ldpc_freedv_1 = cast(
self.fsk_ldpc_bytes_per_frame_1 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_1)/8) codec2.api.freedv_open_advanced(
self.fsk_ldpc_bytes_out_1 = create_string_buffer(self.fsk_ldpc_bytes_per_frame_1) codec2.api.FREEDV_MODE_FSK_LDPC,
#codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0,1) ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV),
),
c_void_p,
)
self.fsk_ldpc_bytes_per_frame_1 = int(
codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_1) / 8
)
self.fsk_ldpc_bytes_out_1 = create_string_buffer(
self.fsk_ldpc_bytes_per_frame_1
)
# codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0,1)
self.fsk_ldpc_buffer_1 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) self.fsk_ldpc_buffer_1 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX)
# initial nin values # initial nin values
@ -128,7 +184,7 @@ class RF():
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1) self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
# --------------------------------------------CREATE PYAUDIO INSTANCE # --------------------------------------------CREATE PYAUDIO INSTANCE
''' """
try: try:
# we need to "try" this, because sometimes libasound.so isn't in the default place # we need to "try" this, because sometimes libasound.so isn't in the default place
# try to supress error messages # try to supress error messages
@ -151,9 +207,9 @@ class RF():
static.AUDIO_OUTPUT_DEVICE = loopback_list[1] #1 = TX static.AUDIO_OUTPUT_DEVICE = loopback_list[1] #1 = TX
print(f"loopback_list rx: {loopback_list}", file=sys.stderr) print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
''' """
try: try:
''' """
self.audio_stream = self.p.open(format=audio.pyaudio.paInt16, self.audio_stream = self.p.open(format=audio.pyaudio.paInt16,
channels=self.AUDIO_CHANNELS, channels=self.AUDIO_CHANNELS,
rate=self.AUDIO_SAMPLE_RATE_RX, rate=self.AUDIO_SAMPLE_RATE_RX,
@ -164,76 +220,114 @@ class RF():
output_device_index=static.AUDIO_OUTPUT_DEVICE, output_device_index=static.AUDIO_OUTPUT_DEVICE,
stream_callback=self.audio_callback stream_callback=self.audio_callback
) )
''' """
self.stream = sd.RawStream(channels=1, dtype='int16', callback=self.callback, device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE), samplerate = self.AUDIO_SAMPLE_RATE_RX, blocksize=4800)
self.stream = sd.RawStream(
channels=1,
dtype="int16",
callback=self.callback,
device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE),
samplerate=self.AUDIO_SAMPLE_RATE_RX,
blocksize=4800,
)
atexit.register(self.stream.stop) atexit.register(self.stream.stop)
structlog.get_logger("structlog").info("opened audio devices") structlog.get_logger("structlog").info("opened audio devices")
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error("can't open audio device. Exit", e=e) structlog.get_logger("structlog").error(
"can't open audio device. Exit", e=e
)
os._exit(1) os._exit(1)
try: try:
structlog.get_logger("structlog").debug("[TNC] starting pyaudio callback") structlog.get_logger("structlog").debug("[TNC] starting pyaudio callback")
#self.audio_stream.start_stream() # self.audio_stream.start_stream()
self.stream.start() self.stream.start()
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error("[TNC] starting pyaudio callback failed", e=e) structlog.get_logger("structlog").error(
"[TNC] starting pyaudio callback failed", e=e
)
# --------------------------------------------INIT AND OPEN HAMLIB # --------------------------------------------INIT AND OPEN HAMLIB
# check how we want to control the radio # check how we want to control the radio
if static.HAMLIB_RADIOCONTROL == 'direct': if static.HAMLIB_RADIOCONTROL == "direct":
import rig import rig
elif static.HAMLIB_RADIOCONTROL == 'rigctl': elif static.HAMLIB_RADIOCONTROL == "rigctl":
import rigctl as rig import rigctl as rig
elif static.HAMLIB_RADIOCONTROL == 'rigctld': elif static.HAMLIB_RADIOCONTROL == "rigctld":
import rigctld as rig import rigctld as rig
elif static.HAMLIB_RADIOCONTROL == 'disabled': elif static.HAMLIB_RADIOCONTROL == "disabled":
import rigdummy as rig import rigdummy as rig
else: else:
import rigdummy as rig import rigdummy as rig
self.hamlib = rig.radio() self.hamlib = rig.radio()
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT, hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED, pttport=static.HAMLIB_PTT_PORT, data_bits=static.HAMLIB_DATA_BITS, stop_bits=static.HAMLIB_STOP_BITS, handshake=static.HAMLIB_HANDSHAKE, rigctld_ip = static.HAMLIB_RGICTLD_IP, rigctld_port = static.HAMLIB_RGICTLD_PORT) self.hamlib.open_rig(
devicename=static.HAMLIB_DEVICE_NAME,
deviceport=static.HAMLIB_DEVICE_PORT,
hamlib_ptt_type=static.HAMLIB_PTT_TYPE,
serialspeed=static.HAMLIB_SERIAL_SPEED,
pttport=static.HAMLIB_PTT_PORT,
data_bits=static.HAMLIB_DATA_BITS,
stop_bits=static.HAMLIB_STOP_BITS,
handshake=static.HAMLIB_HANDSHAKE,
rigctld_ip=static.HAMLIB_RGICTLD_IP,
rigctld_port=static.HAMLIB_RGICTLD_PORT,
)
# --------------------------------------------START DECODER THREAD # --------------------------------------------START DECODER THREAD
if static.ENABLE_FFT: if static.ENABLE_FFT:
fft_thread = threading.Thread(target=self.calculate_fft, name="FFT_THREAD" ,daemon=True) fft_thread = threading.Thread(
target=self.calculate_fft, name="FFT_THREAD", daemon=True
)
fft_thread.start() fft_thread.start()
audio_thread_datac0 = threading.Thread(target=self.audio_datac0, name="AUDIO_THREAD DATAC0",daemon=True) audio_thread_datac0 = threading.Thread(
target=self.audio_datac0, name="AUDIO_THREAD DATAC0", daemon=True
)
audio_thread_datac0.start() audio_thread_datac0.start()
audio_thread_datac1 = threading.Thread(target=self.audio_datac1, name="AUDIO_THREAD DATAC1",daemon=True) audio_thread_datac1 = threading.Thread(
target=self.audio_datac1, name="AUDIO_THREAD DATAC1", daemon=True
)
audio_thread_datac1.start() audio_thread_datac1.start()
audio_thread_datac3 = threading.Thread(target=self.audio_datac3, name="AUDIO_THREAD DATAC3",daemon=True) audio_thread_datac3 = threading.Thread(
target=self.audio_datac3, name="AUDIO_THREAD DATAC3", daemon=True
)
audio_thread_datac3.start() audio_thread_datac3.start()
if static.ENABLE_FSK: if static.ENABLE_FSK:
audio_thread_fsk_ldpc0 = threading.Thread(target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0",daemon=True) audio_thread_fsk_ldpc0 = threading.Thread(
target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0", daemon=True
)
audio_thread_fsk_ldpc0.start() audio_thread_fsk_ldpc0.start()
audio_thread_fsk_ldpc1 = threading.Thread(target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1",daemon=True) audio_thread_fsk_ldpc1 = threading.Thread(
target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1", daemon=True
)
audio_thread_fsk_ldpc1.start() audio_thread_fsk_ldpc1.start()
hamlib_thread = threading.Thread(target=self.update_rig_data, name="HAMLIB_THREAD",daemon=True) hamlib_thread = threading.Thread(
target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True
)
hamlib_thread.start() hamlib_thread.start()
worker_received = threading.Thread(target=self.worker_received, name="WORKER_THREAD",daemon=True) worker_received = threading.Thread(
target=self.worker_received, name="WORKER_THREAD", daemon=True
)
worker_received.start() worker_received.start()
worker_transmit = threading.Thread(target=self.worker_transmit, name="WORKER_THREAD",daemon=True) worker_transmit = threading.Thread(
target=self.worker_transmit, name="WORKER_THREAD", daemon=True
)
worker_transmit.start() worker_transmit.start()
# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
#def audio_callback(self, data_in48k, frame_count, time_info, status): # def audio_callback(self, data_in48k, frame_count, time_info, status):
def callback(self, data_in48k, outdata, frames, time, status): def callback(self, data_in48k, outdata, frames, time, status):
""" """
@ -255,41 +349,47 @@ class RF():
# avoid decoding when transmitting to reduce CPU # avoid decoding when transmitting to reduce CPU
if not static.TRANSMITTING: if not static.TRANSMITTING:
# avoid buffer overflow by filling only if buffer not full # avoid buffer overflow by filling only if buffer not full
if not self.datac0_buffer.nbuffer+length_x > self.datac0_buffer.size: if not self.datac0_buffer.nbuffer + length_x > self.datac0_buffer.size:
self.datac0_buffer.push(x) self.datac0_buffer.push(x)
else: else:
static.BUFFER_OVERFLOW_COUNTER[0] += 1 static.BUFFER_OVERFLOW_COUNTER[0] += 1
# avoid buffer overflow by filling only if buffer not full and selected datachannel mode # avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.datac1_buffer.nbuffer+length_x > self.datac1_buffer.size: if not self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size:
if RECEIVE_DATAC1: if RECEIVE_DATAC1:
self.datac1_buffer.push(x) self.datac1_buffer.push(x)
else: else:
static.BUFFER_OVERFLOW_COUNTER[1] += 1 static.BUFFER_OVERFLOW_COUNTER[1] += 1
# avoid buffer overflow by filling only if buffer not full and selected datachannel mode # avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.datac3_buffer.nbuffer+length_x > self.datac3_buffer.size: if not self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size:
if RECEIVE_DATAC3: if RECEIVE_DATAC3:
self.datac3_buffer.push(x) self.datac3_buffer.push(x)
else: else:
static.BUFFER_OVERFLOW_COUNTER[2] += 1 static.BUFFER_OVERFLOW_COUNTER[2] += 1
# avoid buffer overflow by filling only if buffer not full and selected datachannel mode # avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.fsk_ldpc_buffer_0.nbuffer+length_x > self.fsk_ldpc_buffer_0.size: if (
not self.fsk_ldpc_buffer_0.nbuffer + length_x
> self.fsk_ldpc_buffer_0.size
):
if static.ENABLE_FSK: if static.ENABLE_FSK:
self.fsk_ldpc_buffer_0.push(x) self.fsk_ldpc_buffer_0.push(x)
else: else:
static.BUFFER_OVERFLOW_COUNTER[3] += 1 static.BUFFER_OVERFLOW_COUNTER[3] += 1
# avoid buffer overflow by filling only if buffer not full and selected datachannel mode # avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.fsk_ldpc_buffer_1.nbuffer+length_x > self.fsk_ldpc_buffer_1.size: if (
not self.fsk_ldpc_buffer_1.nbuffer + length_x
> self.fsk_ldpc_buffer_1.size
):
if RECEIVE_FSK_LDPC_1 and static.ENABLE_FSK: if RECEIVE_FSK_LDPC_1 and static.ENABLE_FSK:
self.fsk_ldpc_buffer_1.push(x) self.fsk_ldpc_buffer_1.push(x)
else: else:
static.BUFFER_OVERFLOW_COUNTER[4] += 1 static.BUFFER_OVERFLOW_COUNTER[4] += 1
if len(self.modoutqueue) <= 0 or self.mod_out_locked: if len(self.modoutqueue) <= 0 or self.mod_out_locked:
#if not self.modoutqueue or self.mod_out_locked: # if not self.modoutqueue or self.mod_out_locked:
data_out48k = np.zeros(frames, dtype=np.int16) data_out48k = np.zeros(frames, dtype=np.int16)
self.fft_data = x self.fft_data = x
@ -302,7 +402,7 @@ class RF():
except Exception as e: except Exception as e:
print(e) print(e)
#return (data_out48k, audio.pyaudio.paContinue) # return (data_out48k, audio.pyaudio.paContinue)
# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
@ -321,77 +421,112 @@ class RF():
static.TRANSMITTING = True static.TRANSMITTING = True
# toggle ptt early to save some time and send ptt state via socket # toggle ptt early to save some time and send ptt state via socket
static.PTT_STATE = self.hamlib.set_ptt(True) static.PTT_STATE = self.hamlib.set_ptt(True)
jsondata = {"ptt":"True"} jsondata = {"ptt": "True"}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out) sock.SOCKET_QUEUE.put(data_out)
# open codec2 instance # open codec2 instance
self.MODE = mode self.MODE = mode
if self.MODE == 'FSK_LDPC_0' or self.MODE == 200: if self.MODE == "FSK_LDPC_0" or self.MODE == 200:
freedv = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), c_void_p) freedv = cast(
elif self.MODE == 'FSK_LDPC_1' or self.MODE == 201: codec2.api.freedv_open_advanced(
freedv = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), c_void_p) codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV),
),
c_void_p,
)
elif self.MODE == "FSK_LDPC_1" or self.MODE == 201:
freedv = cast(
codec2.api.freedv_open_advanced(
codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV),
),
c_void_p,
)
else: else:
freedv = cast(codec2.api.freedv_open(self.MODE), c_void_p) freedv = cast(codec2.api.freedv_open(self.MODE), c_void_p)
# get number of bytes per frame for mode # get number of bytes per frame for mode
bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(freedv)/8) bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
payload_bytes_per_frame = bytes_per_frame -2 payload_bytes_per_frame = bytes_per_frame - 2
# init buffer for data # init buffer for data
n_tx_modem_samples = codec2.api.freedv_get_n_tx_modem_samples(freedv) n_tx_modem_samples = codec2.api.freedv_get_n_tx_modem_samples(freedv)
mod_out = create_string_buffer(n_tx_modem_samples * 2) mod_out = create_string_buffer(n_tx_modem_samples * 2)
# init buffer for preample # init buffer for preample
n_tx_preamble_modem_samples = codec2.api.freedv_get_n_tx_preamble_modem_samples(freedv) n_tx_preamble_modem_samples = codec2.api.freedv_get_n_tx_preamble_modem_samples(
freedv
)
mod_out_preamble = create_string_buffer(n_tx_preamble_modem_samples * 2) mod_out_preamble = create_string_buffer(n_tx_preamble_modem_samples * 2)
# init buffer for postamble # init buffer for postamble
n_tx_postamble_modem_samples = codec2.api.freedv_get_n_tx_postamble_modem_samples(freedv) n_tx_postamble_modem_samples = (
codec2.api.freedv_get_n_tx_postamble_modem_samples(freedv)
)
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2) mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
# add empty data to handle ptt toggle time # add empty data to handle ptt toggle time
data_delay_mseconds = 0 #miliseconds data_delay_mseconds = 0 # miliseconds
data_delay = int(self.MODEM_SAMPLE_RATE*(data_delay_mseconds/1000)) data_delay = int(self.MODEM_SAMPLE_RATE * (data_delay_mseconds / 1000))
mod_out_silence = create_string_buffer(data_delay*2) mod_out_silence = create_string_buffer(data_delay * 2)
txbuffer = bytes(mod_out_silence) txbuffer = bytes(mod_out_silence)
structlog.get_logger("structlog").debug("TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame) structlog.get_logger("structlog").debug(
"TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame
)
for i in range(0,repeats): for i in range(0, repeats):
# codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing # codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing
if not self.MODE == 'FSK_LDPC_0' or self.MODE == 200 or self.MODE == 'FSK_LDPC_1' or self.MODE == 201: if (
not self.MODE == "FSK_LDPC_0"
or self.MODE == 200
or self.MODE == "FSK_LDPC_1"
or self.MODE == 201
):
# write preamble to txbuffer # write preamble to txbuffer
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble) codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
txbuffer += bytes(mod_out_preamble) txbuffer += bytes(mod_out_preamble)
# create modulaton for n frames in list # create modulaton for n frames in list
for n in range(0,len(frames)): for n in range(0, len(frames)):
# create buffer for data # create buffer for data
buffer = bytearray(payload_bytes_per_frame) # use this if CRC16 checksum is required ( DATA1-3) buffer = bytearray(
buffer[:len(frames[n])] = frames[n] # set buffersize to length of data which will be send payload_bytes_per_frame
) # use this if CRC16 checksum is required ( DATA1-3)
buffer[: len(frames[n])] = frames[
n
] # set buffersize to length of data which will be send
# create crc for data frame - we are using the crc function shipped with codec2 to avoid # create crc for data frame - we are using the crc function shipped with codec2 to avoid
# crc algorithm incompatibilities # crc algorithm incompatibilities
crc = ctypes.c_ushort(codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)) # generate CRC16 crc = ctypes.c_ushort(
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)
) # generate CRC16
crc = crc.value.to_bytes(
2, byteorder="big"
) # convert crc to 2 byte hex string
buffer += crc # append crc16 to buffer buffer += crc # append crc16 to buffer
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer) data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer codec2.api.freedv_rawdatatx(
freedv, mod_out, data
) # modulate DATA and save it into mod_out pointer
txbuffer += bytes(mod_out) txbuffer += bytes(mod_out)
# codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing # codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing
if not self.MODE == 'FSK_LDPC_0' or self.MODE == 200 or self.MODE == 'FSK_LDPC_1' or self.MODE == 201: if (
not self.MODE == "FSK_LDPC_0"
or self.MODE == 200
or self.MODE == "FSK_LDPC_1"
or self.MODE == 201
):
# write preamble to txbuffer # write preamble to txbuffer
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble) codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
txbuffer += bytes(mod_out_postamble) txbuffer += bytes(mod_out_postamble)
# append postamble to txbuffer # append postamble to txbuffer
# add delay to end of frames # add delay to end of frames
samples_delay = int(self.MODEM_SAMPLE_RATE*(repeat_delay/1000)) samples_delay = int(self.MODEM_SAMPLE_RATE * (repeat_delay / 1000))
mod_out_silence = create_string_buffer(samples_delay*2) mod_out_silence = create_string_buffer(samples_delay * 2)
txbuffer += bytes(mod_out_silence) txbuffer += bytes(mod_out_silence)
# resample up to 48k (resampler works on np.int16) # resample up to 48k (resampler works on np.int16)
@ -404,9 +539,11 @@ class RF():
# deaktivated for testing purposes # deaktivated for testing purposes
self.mod_out_locked = False self.mod_out_locked = False
chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX # 4800
chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX #4800 chunk = [
chunk = [txbuffer_48k[i:i+chunk_length] for i in range(0, len(txbuffer_48k), chunk_length)] txbuffer_48k[i : i + chunk_length]
for i in range(0, len(txbuffer_48k), chunk_length)
]
for c in chunk: for c in chunk:
if len(c) < chunk_length: if len(c) < chunk_length:
@ -414,11 +551,9 @@ class RF():
delta_zeros = np.zeros(delta, dtype=np.int16) delta_zeros = np.zeros(delta, dtype=np.int16)
c = np.append(c, delta_zeros) c = np.append(c, delta_zeros)
#structlog.get_logger("structlog").debug("[TNC] mod out shorter than audio buffer", delta=delta) # structlog.get_logger("structlog").debug("[TNC] mod out shorter than audio buffer", delta=delta)
self.modoutqueue.append(c) self.modoutqueue.append(c)
# Release our mod_out_lock so we can use the queue # Release our mod_out_lock so we can use the queue
self.mod_out_locked = False self.mod_out_locked = False
@ -428,7 +563,7 @@ class RF():
static.PTT_STATE = self.hamlib.set_ptt(False) static.PTT_STATE = self.hamlib.set_ptt(False)
# push ptt state to socket stream # push ptt state to socket stream
jsondata = {"ptt":"False"} jsondata = {"ptt": "False"}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out) sock.SOCKET_QUEUE.put(data_out)
@ -447,12 +582,22 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac0_buffer.nbuffer >= self.datac0_nin: while self.datac0_buffer.nbuffer >= self.datac0_nin:
# demodulate audio # demodulate audio
nbytes_datac0 = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out, self.datac0_buffer.buffer.ctypes) nbytes_datac0 = codec2.api.freedv_rawdatarx(
self.datac0_freedv,
self.datac0_bytes_out,
self.datac0_buffer.buffer.ctypes,
)
self.datac0_buffer.pop(self.datac0_nin) self.datac0_buffer.pop(self.datac0_nin)
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv) self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
if nbytes_datac0 == self.datac0_bytes_per_frame: if nbytes_datac0 == self.datac0_bytes_per_frame:
self.modem_received_queue.put([self.datac0_bytes_out, self.datac0_freedv ,self.datac0_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac0_freedv) [
self.datac0_bytes_out,
self.datac0_freedv,
self.datac0_bytes_per_frame,
]
)
# self.get_scatter(self.datac0_freedv)
self.calculate_snr(self.datac0_freedv) self.calculate_snr(self.datac0_freedv)
def audio_datac1(self): def audio_datac1(self):
@ -462,12 +607,22 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac1_buffer.nbuffer >= self.datac1_nin: while self.datac1_buffer.nbuffer >= self.datac1_nin:
# demodulate audio # demodulate audio
nbytes_datac1 = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out, self.datac1_buffer.buffer.ctypes) nbytes_datac1 = codec2.api.freedv_rawdatarx(
self.datac1_freedv,
self.datac1_bytes_out,
self.datac1_buffer.buffer.ctypes,
)
self.datac1_buffer.pop(self.datac1_nin) self.datac1_buffer.pop(self.datac1_nin)
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv) self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
if nbytes_datac1 == self.datac1_bytes_per_frame: if nbytes_datac1 == self.datac1_bytes_per_frame:
self.modem_received_queue.put([self.datac1_bytes_out, self.datac1_freedv ,self.datac1_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac1_freedv) [
self.datac1_bytes_out,
self.datac1_freedv,
self.datac1_bytes_per_frame,
]
)
# self.get_scatter(self.datac1_freedv)
self.calculate_snr(self.datac1_freedv) self.calculate_snr(self.datac1_freedv)
def audio_datac3(self): def audio_datac3(self):
@ -477,12 +632,22 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac3_buffer.nbuffer >= self.datac3_nin: while self.datac3_buffer.nbuffer >= self.datac3_nin:
# demodulate audio # demodulate audio
nbytes_datac3 = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out, self.datac3_buffer.buffer.ctypes) nbytes_datac3 = codec2.api.freedv_rawdatarx(
self.datac3_freedv,
self.datac3_bytes_out,
self.datac3_buffer.buffer.ctypes,
)
self.datac3_buffer.pop(self.datac3_nin) self.datac3_buffer.pop(self.datac3_nin)
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv) self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
if nbytes_datac3 == self.datac3_bytes_per_frame: if nbytes_datac3 == self.datac3_bytes_per_frame:
self.modem_received_queue.put([self.datac3_bytes_out, self.datac3_freedv ,self.datac3_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac3_freedv) [
self.datac3_bytes_out,
self.datac3_freedv,
self.datac3_bytes_per_frame,
]
)
# self.get_scatter(self.datac3_freedv)
self.calculate_snr(self.datac3_freedv) self.calculate_snr(self.datac3_freedv)
def audio_fsk_ldpc_0(self): def audio_fsk_ldpc_0(self):
@ -492,12 +657,22 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0: while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0:
# demodulate audio # demodulate audio
nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_buffer_0.buffer.ctypes) nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(
self.fsk_ldpc_freedv_0,
self.fsk_ldpc_bytes_out_0,
self.fsk_ldpc_buffer_0.buffer.ctypes,
)
self.fsk_ldpc_buffer_0.pop(self.fsk_ldpc_nin_0) self.fsk_ldpc_buffer_0.pop(self.fsk_ldpc_nin_0)
self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0) self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0)
if nbytes_fsk_ldpc_0 == self.fsk_ldpc_bytes_per_frame_0: if nbytes_fsk_ldpc_0 == self.fsk_ldpc_bytes_per_frame_0:
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_freedv_0 ,self.fsk_ldpc_bytes_per_frame_0]) self.modem_received_queue.put(
#self.get_scatter(self.fsk_ldpc_freedv_0) [
self.fsk_ldpc_bytes_out_0,
self.fsk_ldpc_freedv_0,
self.fsk_ldpc_bytes_per_frame_0,
]
)
# self.get_scatter(self.fsk_ldpc_freedv_0)
self.calculate_snr(self.fsk_ldpc_freedv_0) self.calculate_snr(self.fsk_ldpc_freedv_0)
def audio_fsk_ldpc_1(self): def audio_fsk_ldpc_1(self):
@ -507,26 +682,34 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1: while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1:
# demodulate audio # demodulate audio
nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_buffer_1.buffer.ctypes) nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(
self.fsk_ldpc_freedv_1,
self.fsk_ldpc_bytes_out_1,
self.fsk_ldpc_buffer_1.buffer.ctypes,
)
self.fsk_ldpc_buffer_1.pop(self.fsk_ldpc_nin_1) self.fsk_ldpc_buffer_1.pop(self.fsk_ldpc_nin_1)
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1) self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
if nbytes_fsk_ldpc_1 == self.fsk_ldpc_bytes_per_frame_1: if nbytes_fsk_ldpc_1 == self.fsk_ldpc_bytes_per_frame_1:
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_freedv_1 ,self.fsk_ldpc_bytes_per_frame_1]) self.modem_received_queue.put(
#self.get_scatter(self.fsk_ldpc_freedv_1) [
self.fsk_ldpc_bytes_out_1,
self.fsk_ldpc_freedv_1,
self.fsk_ldpc_bytes_per_frame_1,
]
)
# self.get_scatter(self.fsk_ldpc_freedv_1)
self.calculate_snr(self.fsk_ldpc_freedv_1) self.calculate_snr(self.fsk_ldpc_freedv_1)
# worker for FIFO queue for processing received frames # worker for FIFO queue for processing received frames
def worker_transmit(self): def worker_transmit(self):
""" """ """ """
while True: while True:
data = self.modem_transmit_queue.get() data = self.modem_transmit_queue.get()
self.transmit(mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3]) self.transmit(
#self.modem_transmit_queue.task_done() mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3]
)
# self.modem_transmit_queue.task_done()
# worker for FIFO queue for processing received frames # worker for FIFO queue for processing received frames
def worker_received(self): def worker_received(self):
@ -539,7 +722,6 @@ class RF():
data_handler.DATA_QUEUE_RECEIVED.put([data[0], data[1], data[2]]) data_handler.DATA_QUEUE_RECEIVED.put([data[0], data[1], data[2]])
self.modem_received_queue.task_done() self.modem_received_queue.task_done()
def get_frequency_offset(self, freedv): def get_frequency_offset(self, freedv):
""" """
@ -556,7 +738,6 @@ class RF():
static.FREQ_OFFSET = offset static.FREQ_OFFSET = offset
return offset return offset
def get_scatter(self, freedv): def get_scatter(self, freedv):
""" """
@ -577,8 +758,8 @@ class RF():
for j in range(codec2.MODEM_STATS_NR_MAX): for j in range(codec2.MODEM_STATS_NR_MAX):
# check if odd or not to get every 2nd item for x # check if odd or not to get every 2nd item for x
if (j % 2) == 0: if (j % 2) == 0:
xsymbols = round(modemStats.rx_symbols[i][j]/1000) xsymbols = round(modemStats.rx_symbols[i][j] / 1000)
ysymbols = round(modemStats.rx_symbols[i][j+1]/1000) ysymbols = round(modemStats.rx_symbols[i][j + 1] / 1000)
# check if value 0.0 or has real data # check if value 0.0 or has real data
if xsymbols != 0.0 and ysymbols != 0.0: if xsymbols != 0.0 and ysymbols != 0.0:
scatterdata.append({"x": xsymbols, "y": ysymbols}) scatterdata.append({"x": xsymbols, "y": ysymbols})
@ -591,7 +772,6 @@ class RF():
scatterdata_small = scatterdata[::10] scatterdata_small = scatterdata[::10]
static.SCATTER = scatterdata_small static.SCATTER = scatterdata_small
def calculate_snr(self, freedv): def calculate_snr(self, freedv):
""" """
@ -606,13 +786,15 @@ class RF():
modem_stats_snr = c_float() modem_stats_snr = c_float()
modem_stats_sync = c_int() modem_stats_sync = c_int()
self.c_lib.freedv_get_modem_stats(freedv, byref(modem_stats_sync), byref(modem_stats_snr)) self.c_lib.freedv_get_modem_stats(
freedv, byref(modem_stats_sync), byref(modem_stats_snr)
)
modem_stats_snr = modem_stats_snr.value modem_stats_snr = modem_stats_snr.value
modem_stats_sync = modem_stats_sync.value modem_stats_sync = modem_stats_sync.value
snr = round(modem_stats_snr, 1) snr = round(modem_stats_snr, 1)
print(snr) print(snr)
static.SNR = np.clip(snr, 0, 255) #limit to max value of 255 static.SNR = np.clip(snr, 0, 255) # limit to max value of 255
return static.SNR return static.SNR
except: except:
static.SNR = 0 static.SNR = 0
@ -621,21 +803,20 @@ class RF():
def update_rig_data(self): def update_rig_data(self):
""" """ """ """
while True: while True:
#time.sleep(1.5) # time.sleep(1.5)
threading.Event().wait(0.5) threading.Event().wait(0.5)
#(static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data() # (static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data()
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency() static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
static.HAMLIB_MODE = self.hamlib.get_mode() static.HAMLIB_MODE = self.hamlib.get_mode()
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith() static.HAMLIB_BANDWITH = self.hamlib.get_bandwith()
def calculate_fft(self): def calculate_fft(self):
""" """ """ """
# channel_busy_delay counter # channel_busy_delay counter
channel_busy_delay = 0 channel_busy_delay = 0
while True: while True:
#time.sleep(0.01) # time.sleep(0.01)
threading.Event().wait(0.01) threading.Event().wait(0.01)
# WE NEED TO OPTIMIZE THIS! # WE NEED TO OPTIMIZE THIS!
@ -650,26 +831,24 @@ class RF():
# set value 0 to 1 to avoid division by zero # set value 0 to 1 to avoid division by zero
fftarray[fftarray == 0] = 1 fftarray[fftarray == 0] = 1
dfft = 10.*np.log10(abs(fftarray)) dfft = 10.0 * np.log10(abs(fftarray))
# get average of dfft # get average of dfft
avg = np.mean(dfft) avg = np.mean(dfft)
# detect signals which are higher than the average + 10 ( +10 smoothes the output ) # detect signals which are higher than the average + 10 ( +10 smoothes the output )
# data higher than the average must be a signal. Therefore we are setting it to 100 so it will be highlighted # data higher than the average must be a signal. Therefore we are setting it to 100 so it will be highlighted
# have to do this when we are not transmittig so our own sending data will not affect this too much # have to do this when we are not transmittig so our own sending data will not affect this too much
if not static.TRANSMITTING: if not static.TRANSMITTING:
dfft[dfft>avg+10] = 100 dfft[dfft > avg + 10] = 100
# calculate audio max value # calculate audio max value
#static.AUDIO_RMS = np.amax(self.fft_data) # static.AUDIO_RMS = np.amax(self.fft_data)
# check for signals higher than average by checking for "100" # check for signals higher than average by checking for "100"
# if we have a signal, increment our channel_busy delay counter so we have a smoother state toggle # if we have a signal, increment our channel_busy delay counter so we have a smoother state toggle
if np.sum(dfft[dfft>avg+10]) >= 300 and not static.TRANSMITTING: if np.sum(dfft[dfft > avg + 10]) >= 300 and not static.TRANSMITTING:
static.CHANNEL_BUSY = True static.CHANNEL_BUSY = True
channel_busy_delay += 5 channel_busy_delay += 5
# limit delay counter to a maximun of 30. The higher this value, the linger we will wait until releasing state # limit delay counter to a maximun of 30. The higher this value, the linger we will wait until releasing state
@ -688,7 +867,7 @@ class RF():
dfft = np.around(dfft, 0) dfft = np.around(dfft, 0)
dfftlist = dfft.tolist() dfftlist = dfft.tolist()
static.FFT = dfftlist[0:320] #200 --> bandwith 3000 static.FFT = dfftlist[0:320] # 200 --> bandwith 3000
except: except:
@ -707,10 +886,11 @@ class RF():
Returns: Returns:
""" """
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv,n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, n_frames_per_burst)
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv,n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, n_frames_per_burst)
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0,n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(
self.fsk_ldpc_freedv_0, n_frames_per_burst
)
def get_bytes_per_frame(mode): def get_bytes_per_frame(mode):
@ -724,18 +904,28 @@ def get_bytes_per_frame(mode):
""" """
if mode == 200: if mode == 200:
freedv = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), c_void_p) freedv = cast(
codec2.api.freedv_open_advanced(
codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV),
),
c_void_p,
)
elif mode == 201: elif mode == 201:
freedv = cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), c_void_p) freedv = cast(
codec2.api.freedv_open_advanced(
codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV),
),
c_void_p,
)
else: else:
freedv = cast(codec2.api.freedv_open(mode), c_void_p) freedv = cast(codec2.api.freedv_open(mode), c_void_p)
# get number of bytes per frame for mode # get number of bytes per frame for mode
return int(codec2.api.freedv_get_bits_per_modem_frame(freedv)/8) return int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
def set_audio_volume(datalist, volume): def set_audio_volume(datalist, volume):
data = np.fromstring(datalist, np.int16) * (volume / 100.) data = np.fromstring(datalist, np.int16) * (volume / 100.0)
return data.astype(np.int16) return data.astype(np.int16)

View file

@ -26,23 +26,23 @@ try:
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
# installation path for Ubuntu 20.04 LTS python modules # installation path for Ubuntu 20.04 LTS python modules
#sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages') # sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
# installation path for Ubuntu 20.10 + # installation path for Ubuntu 20.10 +
sys.path.append('/usr/local/lib/') sys.path.append("/usr/local/lib/")
# installation path for Suse # installation path for Suse
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages') sys.path.append("/usr/local/lib64/python" + python_version + "/site-packages")
# everything else... not nice, but an attempt to see how its running within app bundle # everything else... not nice, but an attempt to see how its running within app bundle
# this is not needed as python will be shipped with app bundle # this is not needed as python will be shipped with app bundle
sys.path.append('/usr/local/lib/python3.6/site-packages') sys.path.append("/usr/local/lib/python3.6/site-packages")
sys.path.append('/usr/local/lib/python3.7/site-packages') sys.path.append("/usr/local/lib/python3.7/site-packages")
sys.path.append('/usr/local/lib/python3.8/site-packages') sys.path.append("/usr/local/lib/python3.8/site-packages")
sys.path.append('/usr/local/lib/python3.9/site-packages') sys.path.append("/usr/local/lib/python3.9/site-packages")
sys.path.append('/usr/local/lib/python3.10/site-packages') sys.path.append("/usr/local/lib/python3.10/site-packages")
sys.path.append('lib/hamlib/linux/python3.8/site-packages') sys.path.append("lib/hamlib/linux/python3.8/site-packages")
import Hamlib import Hamlib
# https://stackoverflow.com/a/4703409 # https://stackoverflow.com/a/4703409
@ -51,44 +51,73 @@ try:
min_hamlib_version = 4.1 min_hamlib_version = 4.1
if hamlib_version > min_hamlib_version: if hamlib_version > min_hamlib_version:
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version) structlog.get_logger("structlog").info(
"[RIG] Hamlib found", version=hamlib_version
)
else: 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: 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: try:
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl") 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 = rigctl.stdout.readline()
hamlib_version = hamlib_version.split(' ') hamlib_version = hamlib_version.split(" ")
if hamlib_version[1] == 'Hamlib': if hamlib_version[1] == "Hamlib":
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2]) structlog.get_logger("structlog").warning(
"[RIG] Rigctl found! Please try using this", version=hamlib_version[2]
)
sys.exit() sys.exit()
else: else:
raise Exception raise Exception
except Exception as e: except Exception as 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 hamlib_version = 0
sys.exit() sys.exit()
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
self.devicename = '' self.devicename = ""
self.devicenumber = '' self.devicenumber = ""
self.deviceport = '' self.deviceport = ""
self.serialspeed = '' self.serialspeed = ""
self.hamlib_ptt_type = '' self.hamlib_ptt_type = ""
self.my_rig = '' self.my_rig = ""
self.pttport = '' self.pttport = ""
self.data_bits = '' self.data_bits = ""
self.stop_bits = '' self.stop_bits = ""
self.handshake = '' self.handshake = ""
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip): def open_rig(
self,
devicename,
deviceport,
hamlib_ptt_type,
serialspeed,
pttport,
data_bits,
stop_bits,
handshake,
rigctld_port,
rigctld_ip,
):
""" """
Args: Args:
@ -109,14 +138,15 @@ class radio:
self.devicename = devicename self.devicename = devicename
self.deviceport = str(deviceport) self.deviceport = str(deviceport)
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing 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.hamlib_ptt_type = str(hamlib_ptt_type)
self.pttport = str(pttport) self.pttport = str(pttport)
self.data_bits = str(data_bits) self.data_bits = str(data_bits)
self.stop_bits = str(stop_bits) self.stop_bits = str(stop_bits)
self.handshake = str(handshake) self.handshake = str(handshake)
# try to init hamlib # try to init hamlib
try: try:
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE) Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
@ -125,10 +155,11 @@ class radio:
try: try:
self.devicenumber = int(getattr(Hamlib, self.devicename)) self.devicenumber = int(getattr(Hamlib, self.devicename))
except: 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.devicenumber = 0
self.my_rig = Hamlib.Rig(self.devicenumber) self.my_rig = Hamlib.Rig(self.devicenumber)
self.my_rig.set_conf("rig_pathname", self.deviceport) self.my_rig.set_conf("rig_pathname", self.deviceport)
self.my_rig.set_conf("retry", "5") self.my_rig.set_conf("retry", "5")
@ -138,50 +169,54 @@ class radio:
self.my_rig.set_conf("data_bits", self.data_bits) self.my_rig.set_conf("data_bits", self.data_bits)
self.my_rig.set_conf("ptt_pathname", self.pttport) self.my_rig.set_conf("ptt_pathname", self.pttport)
if self.hamlib_ptt_type == "RIG":
if self.hamlib_ptt_type == 'RIG':
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
self.my_rig.set_conf("ptt_type", 'RIG') self.my_rig.set_conf("ptt_type", "RIG")
elif self.hamlib_ptt_type == 'USB': elif self.hamlib_ptt_type == "USB":
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
self.my_rig.set_conf("ptt_type", 'USB') self.my_rig.set_conf("ptt_type", "USB")
elif self.hamlib_ptt_type == "DTR-H":
elif self.hamlib_ptt_type == 'DTR-H':
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
self.my_rig.set_conf("dtr_state", "HIGH") self.my_rig.set_conf("dtr_state", "HIGH")
self.my_rig.set_conf("ptt_type", "DTR") self.my_rig.set_conf("ptt_type", "DTR")
elif self.hamlib_ptt_type == 'DTR-L': elif self.hamlib_ptt_type == "DTR-L":
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
self.my_rig.set_conf("dtr_state", "LOW") self.my_rig.set_conf("dtr_state", "LOW")
self.my_rig.set_conf("ptt_type", "DTR") self.my_rig.set_conf("ptt_type", "DTR")
elif self.hamlib_ptt_type == 'RTS': elif self.hamlib_ptt_type == "RTS":
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
self.my_rig.set_conf("dtr_state", "OFF") self.my_rig.set_conf("dtr_state", "OFF")
self.my_rig.set_conf("ptt_type", "RTS") self.my_rig.set_conf("ptt_type", "RTS")
elif self.hamlib_ptt_type == 'PARALLEL': elif self.hamlib_ptt_type == "PARALLEL":
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
elif self.hamlib_ptt_type == 'MICDATA': elif self.hamlib_ptt_type == "MICDATA":
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
elif self.hamlib_ptt_type == 'CM108': elif self.hamlib_ptt_type == "CM108":
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108 self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
elif self.hamlib_ptt_type == 'RIG_PTT_NONE': elif self.hamlib_ptt_type == "RIG_PTT_NONE":
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE': else: # self.hamlib_ptt_type == 'RIG_PTT_NONE':
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname")) 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() self.my_rig.open()
atexit.register(self.my_rig.close) atexit.register(self.my_rig.close)
@ -189,28 +224,35 @@ class radio:
try: try:
# lets determine the error message when opening rig # lets determine the error message when opening rig
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines() error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
error = error[1].split('err=') error = error[1].split("err=")
error = error[1] error = error[1]
if error == 'Permission denied': if error == "Permission denied":
structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error) structlog.get_logger("structlog").error(
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions' "[RIG] Hamlib has no permissions", e=error
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url) )
help_url = "https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions"
structlog.get_logger("structlog").error(
"[RIG] HELP:", check=help_url
)
except: except:
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS') structlog.get_logger("structlog").info(
"[RIG] Hamlib device opened", status="SUCCESS"
)
# set ptt to false if ptt is stuck for some reason # set ptt to false if ptt is stuck for some reason
self.set_ptt(False) self.set_ptt(False)
# set rig mode to USB # set rig mode to USB
# temporarly outcommented because of possible problems. # temporarly outcommented because of possible problems.
#self.my_rig.set_mode(Hamlib.RIG_MODE_USB) # self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB) # self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
return True return True
except Exception as e: except Exception as 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 return False
def get_frequency(self): def get_frequency(self):
@ -228,7 +270,7 @@ class radio:
return bandwith return bandwith
# not needed yet beacuse of some possible problems # not needed yet beacuse of some possible problems
#def set_mode(self, mode): # def set_mode(self, mode):
# return 0 # return 0
def get_ptt(self): def get_ptt(self):

View file

@ -13,27 +13,42 @@ import structlog
import time import time
import sys import sys
import os import os
# for rig_model -> rig_number only # for rig_model -> rig_number only
# set global hamlib version # set global hamlib version
hamlib_version = 0 hamlib_version = 0
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
self.devicename = '' self.devicename = ""
self.devicenumber = '' self.devicenumber = ""
self.deviceport = '' self.deviceport = ""
self.serialspeed = '' self.serialspeed = ""
self.hamlib_ptt_type = '' self.hamlib_ptt_type = ""
self.my_rig = '' self.my_rig = ""
self.pttport = '' self.pttport = ""
self.data_bits = '' self.data_bits = ""
self.stop_bits = '' self.stop_bits = ""
self.handshake = '' self.handshake = ""
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port): def open_rig(
self,
devicename,
deviceport,
hamlib_ptt_type,
serialspeed,
pttport,
data_bits,
stop_bits,
handshake,
rigctld_ip,
rigctld_port,
):
""" """
Args: Args:
@ -54,14 +69,15 @@ class radio:
self.devicename = devicename self.devicename = devicename
self.deviceport = deviceport self.deviceport = deviceport
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing 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.hamlib_ptt_type = hamlib_ptt_type
self.pttport = pttport self.pttport = pttport
self.data_bits = data_bits self.data_bits = data_bits
self.stop_bits = stop_bits self.stop_bits = stop_bits
self.handshake = handshake self.handshake = handshake
# check if we are running in a pyinstaller environment # check if we are running in a pyinstaller environment
try: try:
app_path = sys._MEIPASS app_path = sys._MEIPASS
@ -72,30 +88,40 @@ class radio:
# get devicenumber by looking for deviceobject in Hamlib module # get devicenumber by looking for deviceobject in Hamlib module
try: try:
import Hamlib import Hamlib
self.devicenumber = int(getattr(Hamlib, self.devicename)) self.devicenumber = int(getattr(Hamlib, self.devicename))
except: except:
if int(self.devicename): if int(self.devicename):
self.devicenumber = int(self.devicename) self.devicenumber = int(self.devicename)
else: else:
self.devicenumber = 6 #dummy self.devicenumber = 6 # dummy
structlog.get_logger("structlog").warning("[RIGCTL] RADIO NOT FOUND USING DUMMY!", error=e) structlog.get_logger("structlog").warning(
"[RIGCTL] RADIO NOT FOUND USING DUMMY!", error=e
)
# set deviceport to dummy port, if we selected dummy model # set deviceport to dummy port, if we selected dummy model
if self.devicenumber == 1 or self.devicenumber == 6: if self.devicenumber == 1 or self.devicenumber == 6:
self.deviceport = '/dev/ttyUSB0' self.deviceport = "/dev/ttyUSB0"
print(self.devicenumber, self.deviceport, self.serialspeed) print(self.devicenumber, self.deviceport, self.serialspeed)
# select precompiled executable for win32/win64 rigctl # select precompiled executable for win32/win64 rigctl
# this is really a hack...somewhen we need a native hamlib integration for windows # this is really a hack...somewhen we need a native hamlib integration for windows
if sys.platform == 'win32' or sys.platform == 'win64': 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)) self.cmd = (
app_path
+ "lib\\hamlib\\"
+ sys.platform
+ "\\rigctl -m %d -r %s -s %d "
% (int(self.devicenumber), self.deviceport, int(self.serialspeed))
)
else: else:
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed)) self.cmd = "rigctl -m %d -r %s -s %d " % (
int(self.devicenumber),
self.deviceport,
int(self.serialspeed),
)
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per # eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
# il set e t per il get # il set e t per il get
@ -106,30 +132,30 @@ class radio:
def get_frequency(self): def get_frequency(self):
""" """ """ """
cmd = self.cmd + ' f' cmd = self.cmd + " f"
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) sw_proc = subprocess.Popen(
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
)
time.sleep(0.5) time.sleep(0.5)
freq = sw_proc.communicate()[0] freq = sw_proc.communicate()[0]
#print('get_frequency', freq, sw_proc.communicate()) # print('get_frequency', freq, sw_proc.communicate())
try: try:
return int(freq) return int(freq)
except: except:
return False return False
def get_mode(self): def get_mode(self):
""" """ """ """
#(hamlib_mode, bandwith) = self.my_rig.get_mode() # (hamlib_mode, bandwith) = self.my_rig.get_mode()
#return Hamlib.rig_strrmode(hamlib_mode) # return Hamlib.rig_strrmode(hamlib_mode)
try: try:
return 'PKTUSB' return "PKTUSB"
except: except:
return False return False
def get_bandwith(self): def get_bandwith(self):
""" """ """ """
#(hamlib_mode, bandwith) = self.my_rig.get_mode() # (hamlib_mode, bandwith) = self.my_rig.get_mode()
bandwith = 2700 bandwith = 2700
try: try:
@ -151,8 +177,10 @@ class radio:
def get_ptt(self): def get_ptt(self):
""" """ """ """
cmd = self.cmd + ' t' cmd = self.cmd + " t"
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) sw_proc = subprocess.Popen(
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
)
time.sleep(0.5) time.sleep(0.5)
status = sw_proc.communicate()[0] status = sw_proc.communicate()[0]
@ -170,13 +198,13 @@ class radio:
Returns: Returns:
""" """
cmd = self.cmd + ' T ' cmd = self.cmd + " T "
print('set_ptt', state) print("set_ptt", state)
if state: if state:
cmd = cmd + '1' cmd = cmd + "1"
else: else:
cmd = cmd + '0' cmd = cmd + "0"
print('set_ptt', cmd) print("set_ptt", cmd)
sw_proc = subprocess.Popen(cmd, shell=True, text=True) sw_proc = subprocess.Popen(cmd, shell=True, text=True)
try: try:
@ -186,5 +214,5 @@ class radio:
def close_rig(self): def close_rig(self):
""" """ """ """
#self.my_rig.close() # self.my_rig.close()
return return

View file

@ -5,6 +5,7 @@ import log_handler
import logging import logging
import time import time
import static import static
# class taken from darsidelemm # class taken from darsidelemm
# rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35 # rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35
# #
@ -13,21 +14,35 @@ import static
# set global hamlib version # set global hamlib version
hamlib_version = 0 hamlib_version = 0
class radio():
class radio:
"""rotctld (hamlib) communication class""" """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): def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
""" Open a connection to rotctld, and test it for validity """ """Open a connection to rotctld, and test it for validity"""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#self.sock.settimeout(timeout) # self.sock.settimeout(timeout)
self.connected = False self.connected = False
self.hostname = hostname self.hostname = hostname
self.port = port self.port = port
self.connection_attempts = 5 self.connection_attempts = 5
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port): def open_rig(
self,
devicename,
deviceport,
hamlib_ptt_type,
serialspeed,
pttport,
data_bits,
stop_bits,
handshake,
rigctld_ip,
rigctld_port,
):
""" """
Args: Args:
@ -48,26 +63,34 @@ class radio():
self.hostname = rigctld_ip self.hostname = rigctld_ip
self.port = int(rigctld_port) self.port = int(rigctld_port)
if self.connect(): if self.connect():
logging.debug(f"Rigctl intialized") logging.debug(f"Rigctl intialized")
return True return True
else: 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 return False
def connect(self): def connect(self):
"""Connect to rigctld instance""" """Connect to rigctld instance"""
if not self.connected: if not self.connected:
try: try:
self.connection = socket.create_connection((self.hostname,self.port)) self.connection = socket.create_connection((self.hostname, self.port))
self.connected = True self.connected = True
structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port) structlog.get_logger("structlog").info(
"[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port
)
return True return True
except Exception as e: except Exception as e:
# ConnectionRefusedError: [Errno 111] Connection refused # ConnectionRefusedError: [Errno 111] Connection refused
self.close_rig() self.close_rig()
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=e) structlog.get_logger("structlog").warning(
"[RIGCTLD] Connection to rigctld refused! Reconnect...",
ip=self.hostname,
port=self.port,
e=e,
)
return False return False
def close_rig(self): def close_rig(self):
@ -75,7 +98,6 @@ class radio():
self.sock.close() self.sock.close()
self.connected = False self.connected = False
def send_command(self, command): def send_command(self, command):
"""Send a command to the connected rotctld instance, """Send a command to the connected rotctld instance,
and return the return value. and return the return value.
@ -88,15 +110,25 @@ class radio():
""" """
if self.connected: if self.connected:
try: try:
self.connection.sendall(command+b'\n') self.connection.sendall(command + b"\n")
except: 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 self.connected = False
try: try:
return self.connection.recv(1024) return self.connection.recv(1024)
except: 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 self.connected = False
else: else:
@ -104,21 +136,21 @@ class radio():
time.sleep(0.5) time.sleep(0.5)
self.connect() self.connect()
def get_mode(self): def get_mode(self):
""" """ """ """
try: try:
data = self.send_command(b"m") data = self.send_command(b"m")
data = data.split(b'\n') data = data.split(b"\n")
mode = data[0] mode = data[0]
return mode.decode("utf-8") return mode.decode("utf-8")
except: except:
0 0
def get_bandwith(self): def get_bandwith(self):
""" """ """ """
try: try:
data = self.send_command(b"m") data = self.send_command(b"m")
data = data.split(b'\n') data = data.split(b"\n")
bandwith = data[1] bandwith = data[1]
return bandwith.decode("utf-8") return bandwith.decode("utf-8")
except: except:

View file

@ -4,12 +4,13 @@ import structlog
hamlib_version = 0 hamlib_version = 0
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
pass pass
def open_rig(self, **kwargs): def open_rig(self, **kwargs):
""" """
@ -62,4 +63,3 @@ class radio:
def close_rig(self): def close_rig(self):
""" """ """ """
return return

View file

@ -42,29 +42,24 @@ CONNECTED_CLIENTS = set()
CLOSE_SIGNAL = False CLOSE_SIGNAL = False
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
""" """
the socket handler base class the socket handler base class
""" """
pass
pass
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler): class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
""" """ """ """
def send_to_client(self): def send_to_client(self):
""" """
function called by socket handler function called by socket handler
send data to a network client if available send data to a network client if available
""" """
tempdata = b'' tempdata = b""
while self.connection_alive and not CLOSE_SIGNAL: while self.connection_alive and not CLOSE_SIGNAL:
# send tnc state as network stream # send tnc state as network stream
@ -82,14 +77,13 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
SOCKET_QUEUE.put(data) SOCKET_QUEUE.put(data)
time.sleep(0.5) time.sleep(0.5)
while not SOCKET_QUEUE.empty(): while not SOCKET_QUEUE.empty():
data = SOCKET_QUEUE.get() data = SOCKET_QUEUE.get()
sock_data = bytes(data, 'utf-8') sock_data = bytes(data, "utf-8")
sock_data += b'\n' # append line limiter sock_data += b"\n" # append line limiter
# send data to all clients # send data to all clients
#try: # try:
for client in CONNECTED_CLIENTS: for client in CONNECTED_CLIENTS:
try: try:
client.send(sock_data) client.send(sock_data)
@ -102,7 +96,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
static.SCATTER = [] static.SCATTER = []
# we want to display INFO messages only once # we want to display INFO messages only once
static.INFO = [] static.INFO = []
#self.request.sendall(sock_data) # self.request.sendall(sock_data)
time.sleep(0.15) time.sleep(0.15)
def receive_from_client(self): def receive_from_client(self):
@ -116,16 +110,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
chunk = self.request.recv(1024) chunk = self.request.recv(1024)
data += chunk data += chunk
if chunk == b'': if chunk == b"":
#print("connection broken. Closing...") # print("connection broken. Closing...")
self.connection_alive = False self.connection_alive = False
if data.startswith(b"{") and data.endswith(b"}\n"):
if data.startswith(b'{') and data.endswith(b'}\n'):
# split data by \n if we have multiple commands in socket buffer # split data by \n if we have multiple commands in socket buffer
data = data.split(b'\n') data = data.split(b"\n")
# remove empty data # remove empty data
data.remove(b'') data.remove(b"")
# iterate thorugh data list # iterate thorugh data list
for commands in data: for commands in data:
@ -141,14 +134,17 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
# and which one can be processed during a running transmission # and which one can be processed during a running transmission
time.sleep(3) time.sleep(3)
# finally delete our rx buffer to be ready for new commands # finally delete our rx buffer to be ready for new commands
data = bytes() data = bytes()
except Exception as e: except Exception as 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 self.connection_alive = False
def handle(self): def handle(self):
""" """
socket handler socket handler
@ -156,25 +152,38 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
CONNECTED_CLIENTS.add(self.request) CONNECTED_CLIENTS.add(self.request)
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1]) structlog.get_logger("structlog").debug(
"[SCK] Client connected",
ip=self.client_address[0],
port=self.client_address[1],
)
self.connection_alive = True self.connection_alive = True
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start() self.sendThread = threading.Thread(
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start() target=self.send_to_client, args=[], daemon=True
).start()
self.receiveThread = threading.Thread(
target=self.receive_from_client, args=[], daemon=True
).start()
# keep connection alive until we close it # keep connection alive until we close it
while self.connection_alive and not CLOSE_SIGNAL: while self.connection_alive and not CLOSE_SIGNAL:
time.sleep(1) time.sleep(1)
def finish(self): def finish(self):
""" """ """ """
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1]) structlog.get_logger("structlog").warning(
"[SCK] Closing client socket",
ip=self.client_address[0],
port=self.client_address[1],
)
try: try:
CONNECTED_CLIENTS.remove(self.request) CONNECTED_CLIENTS.remove(self.request)
except: except:
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): def process_tnc_commands(data):
@ -194,58 +203,73 @@ def process_tnc_commands(data):
received_json = json.loads(data) received_json = json.loads(data)
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json) structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
# SET TX AUDIO LEVEL ----------------------------------------------------- # SET TX AUDIO LEVEL -----------------------------------------------------
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level": if (
received_json["type"] == "set"
and received_json["command"] == "tx_audio_level"
):
try: try:
static.TX_AUDIO_LEVEL = int(received_json["value"]) static.TX_AUDIO_LEVEL = int(received_json["value"])
command_response("tx_audio_level", True) command_response("tx_audio_level", True)
except Exception as e: except Exception as e:
command_response("tx_audio_level", False) command_response("tx_audio_level", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# TRANSMIT SINE WAVE ----------------------------------------------------- # TRANSMIT SINE WAVE -----------------------------------------------------
if received_json["type"] == "set" and received_json["command"] == "send_test_frame": if (
received_json["type"] == "set"
and received_json["command"] == "send_test_frame"
):
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME']) data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
command_response("send_test_frame", True) command_response("send_test_frame", True)
except Exception as e: except Exception as e:
command_response("send_test_frame", False) command_response("send_test_frame", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# CQ CQ CQ ----------------------------------------------------- # CQ CQ CQ -----------------------------------------------------
if received_json["command"] == "cqcqcq": if received_json["command"] == "cqcqcq":
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ']) data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
command_response("cqcqcq", True) command_response("cqcqcq", True)
except Exception as e: except Exception as e:
command_response("cqcqcq", False) command_response("cqcqcq", 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
)
# START_BEACON ----------------------------------------------------- # START_BEACON -----------------------------------------------------
if received_json["command"] == "start_beacon": if received_json["command"] == "start_beacon":
try: try:
static.BEACON_STATE = True static.BEACON_STATE = True
interval = int(received_json["parameter"]) interval = int(received_json["parameter"])
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True]) data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
command_response("start_beacon", True) command_response("start_beacon", True)
except Exception as e: except Exception as e:
command_response("start_beacon", False) command_response("start_beacon", 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
)
# STOP_BEACON ----------------------------------------------------- # STOP_BEACON -----------------------------------------------------
if received_json["command"] == "stop_beacon": if received_json["command"] == "stop_beacon":
try: try:
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!") structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
static.BEACON_STATE = False static.BEACON_STATE = False
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False]) data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
command_response("stop_beacon", True) command_response("stop_beacon", True)
except Exception as e: except Exception as e:
command_response("stop_beacon", False) command_response("stop_beacon", 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
)
# PING ---------------------------------------------------------- # PING ----------------------------------------------------------
if received_json["type"] == 'ping' and received_json["command"] == "ping": if received_json["type"] == "ping" and received_json["command"] == "ping":
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
dxcallsign = received_json["dxcallsign"] dxcallsign = received_json["dxcallsign"]
@ -256,15 +280,16 @@ def process_tnc_commands(data):
dxcallsign = helpers.callsign_to_bytes(dxcallsign) dxcallsign = helpers.callsign_to_bytes(dxcallsign)
dxcallsign = helpers.bytes_to_callsign(dxcallsign) dxcallsign = helpers.bytes_to_callsign(dxcallsign)
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign]) data_handler.DATA_QUEUE_TRANSMIT.put(["PING", dxcallsign])
command_response("ping", True) command_response("ping", True)
except Exception as e: except Exception as e:
command_response("ping", False) 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 ---------------------------------------------------------- # CONNECT ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "connect": if received_json["type"] == "arq" and received_json["command"] == "connect":
static.BEACON_PAUSE = True static.BEACON_PAUSE = True
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
@ -279,24 +304,28 @@ def process_tnc_commands(data):
static.DXCALLSIGN = dxcallsign static.DXCALLSIGN = dxcallsign
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.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) command_response("connect", True)
except Exception as e: except Exception as e:
command_response("connect", False) command_response("connect", 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
)
# DISCONNECT ---------------------------------------------------------- # DISCONNECT ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "disconnect": if received_json["type"] == "arq" and received_json["command"] == "disconnect":
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT']) data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
command_response("disconnect", True) command_response("disconnect", True)
except Exception as e: except Exception as e:
command_response("disconnect", False) 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 ------------------------------------------- # TRANSMIT RAW DATA -------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "send_raw": if received_json["type"] == "arq" and received_json["command"] == "send_raw":
static.BEACON_PAUSE = True static.BEACON_PAUSE = True
try: try:
@ -314,7 +343,6 @@ def process_tnc_commands(data):
dxcallsign = static.DXCALLSIGN dxcallsign = static.DXCALLSIGN
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN) static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
mode = int(received_json["parameter"][0]["mode"]) mode = int(received_json["parameter"][0]["mode"])
n_frames = int(received_json["parameter"][0]["n_frames"]) n_frames = int(received_json["parameter"][0]["n_frames"])
base64data = received_json["parameter"][0]["data"] base64data = received_json["parameter"][0]["data"]
@ -329,36 +357,44 @@ def process_tnc_commands(data):
try: try:
arq_uuid = received_json["uuid"] arq_uuid = received_json["uuid"]
except: except:
arq_uuid = 'no-uuid' arq_uuid = "no-uuid"
if not len(base64data) % 4: if not len(base64data) % 4:
binarydata = base64.b64decode(base64data) binarydata = base64.b64decode(base64data)
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', binarydata, mode, n_frames, arq_uuid, mycallsign]) data_handler.DATA_QUEUE_TRANSMIT.put(
["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign]
)
else: else:
raise TypeError raise TypeError
except Exception as e: except Exception as e:
command_response("send_raw", False) command_response("send_raw", 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
)
# STOP TRANSMISSION ---------------------------------------------------------- # STOP TRANSMISSION ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission": if (
received_json["type"] == "arq"
and received_json["command"] == "stop_transmission"
):
try: try:
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE: if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP']) data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!") structlog.get_logger("structlog").warning(
static.TNC_STATE = 'IDLE' "[TNC] Stopping transmission!"
)
static.TNC_STATE = "IDLE"
static.ARQ_STATE = False static.ARQ_STATE = False
command_response("stop_transmission", True) command_response("stop_transmission", True)
except Exception as e: except Exception as e:
command_response("stop_transmission", False) command_response("stop_transmission", 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
)
if received_json["type"] == "get" and received_json["command"] == "rx_buffer":
if received_json["type"] == 'get' and received_json["command"] == 'rx_buffer':
try: try:
output = { output = {
"command": "rx_buffer", "command": "rx_buffer",
@ -366,39 +402,54 @@ def process_tnc_commands(data):
} }
for i in range(0, len(static.RX_BUFFER)): for i in range(0, len(static.RX_BUFFER)):
#print(static.RX_BUFFER[i][4]) # print(static.RX_BUFFER[i][4])
#rawdata = json.loads(static.RX_BUFFER[i][4]) # rawdata = json.loads(static.RX_BUFFER[i][4])
base64_data = static.RX_BUFFER[i][4] base64_data = static.RX_BUFFER[i][4]
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data}) output["data-array"].append(
{
"uuid": static.RX_BUFFER[i][0],
"timestamp": static.RX_BUFFER[i][1],
"dxcallsign": str(static.RX_BUFFER[i][2], "utf-8"),
"dxgrid": str(static.RX_BUFFER[i][3], "utf-8"),
"data": base64_data,
}
)
jsondata = json.dumps(output) jsondata = json.dumps(output)
#self.request.sendall(bytes(jsondata, encoding)) # self.request.sendall(bytes(jsondata, encoding))
SOCKET_QUEUE.put(jsondata) SOCKET_QUEUE.put(jsondata)
command_response("rx_buffer", True) command_response("rx_buffer", True)
except Exception as e: except Exception as e:
command_response("rx_buffer", False) command_response("rx_buffer", 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
)
if (
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer': received_json["type"] == "set"
and received_json["command"] == "del_rx_buffer"
):
try: try:
static.RX_BUFFER = [] static.RX_BUFFER = []
command_response("del_rx_buffer", True) command_response("del_rx_buffer", True)
except Exception as e: except Exception as e:
command_response("del_rx_buffer", False) command_response("del_rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning(
"[SCK] command execution error", e=e, command=received_json
)
# exception, if JSON cant be decoded # exception, if JSON cant be decoded
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e) structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
def send_tnc_state(): def send_tnc_state():
""" """
send the tnc state to network send the tnc state to network
""" """
encoding = 'utf-8' encoding = "utf-8"
output = { output = {
"command": "tnc_state", "command": "tnc_state",
@ -423,8 +474,8 @@ def send_tnc_state():
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR), "arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT), "arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
"total_bytes": str(static.TOTAL_BYTES), "total_bytes": str(static.TOTAL_BYTES),
"info" : static.INFO, "info": static.INFO,
"beacon_state" : str(static.BEACON_STATE), "beacon_state": str(static.BEACON_STATE),
"stations": [], "stations": [],
"mycallsign": str(static.MYCALLSIGN, encoding), "mycallsign": str(static.MYCALLSIGN, encoding),
"dxcallsign": str(static.DXCALLSIGN, encoding), "dxcallsign": str(static.DXCALLSIGN, encoding),
@ -433,7 +484,17 @@ def send_tnc_state():
# add heard stations to heard stations object # add heard stations to heard stations object
for i in range(0, len(static.HEARD_STATIONS)): 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) jsondata = json.dumps(output)
return jsondata return jsondata
@ -452,40 +513,56 @@ def process_daemon_commands(data):
# convert data to json object # convert data to json object
received_json = json.loads(data) received_json = json.loads(data)
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json) 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: try:
callsign = received_json["parameter"] callsign = received_json["parameter"]
if bytes(callsign, 'utf-8') == b'': if bytes(callsign, "utf-8") == b"":
self.request.sendall(b'INVALID CALLSIGN') self.request.sendall(b"INVALID CALLSIGN")
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC) structlog.get_logger("structlog").warning(
"[DMN] SET MYCALL FAILED",
call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC,
)
else: else:
static.MYCALLSIGN = bytes(callsign, 'utf-8') static.MYCALLSIGN = bytes(callsign, "utf-8")
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN) static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
command_response("mycallsign", True) command_response("mycallsign", True)
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC) structlog.get_logger("structlog").info(
"[DMN] SET MYCALL",
call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC,
)
except Exception as e: except Exception as e:
command_response("mycallsign", False) command_response("mycallsign", 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
)
if received_json["type"] == "set" and received_json["command"] == "mygrid":
if received_json["type"] == 'set' and received_json["command"] == 'mygrid':
try: try:
mygrid = received_json["parameter"] mygrid = received_json["parameter"]
if bytes(mygrid, 'utf-8') == b'': if bytes(mygrid, "utf-8") == b"":
self.request.sendall(b'INVALID GRID') self.request.sendall(b"INVALID GRID")
else: else:
static.MYGRID = bytes(mygrid, 'utf-8') static.MYGRID = bytes(mygrid, "utf-8")
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID) structlog.get_logger("structlog").info(
"[SCK] SET MYGRID", grid=static.MYGRID
)
command_response("mygrid", True) command_response("mygrid", True)
except Exception as e: except Exception as e:
command_response("mygrid", False) command_response("mygrid", 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
)
if (
if received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED: received_json["type"] == "set"
and received_json["command"] == "start_tnc"
and not static.TNCSTARTED
):
try: try:
mycall = str(received_json["parameter"][0]["mycall"]) mycall = str(received_json["parameter"][0]["mycall"])
@ -513,39 +590,47 @@ def process_daemon_commands(data):
# print some debugging parameters # print some debugging parameters
for item in received_json["parameter"][0]: for item in received_json["parameter"][0]:
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item]) structlog.get_logger("structlog").debug(
"[DMN] TNC Startup Config : " + item,
value=received_json["parameter"][0][item],
)
DAEMON_QUEUE.put(['STARTTNC', \ DAEMON_QUEUE.put(
mycall, \ [
mygrid, \ "STARTTNC",
rx_audio, \ mycall,
tx_audio, \ mygrid,
devicename, \ rx_audio,
deviceport, \ tx_audio,
serialspeed, \ devicename,
pttprotocol, \ deviceport,
pttport, \ serialspeed,
data_bits, \ pttprotocol,
stop_bits, \ pttport,
handshake, \ data_bits,
radiocontrol, \ stop_bits,
rigctld_ip, \ handshake,
rigctld_port, \ radiocontrol,
enable_scatter, \ rigctld_ip,
enable_fft, \ rigctld_port,
low_bandwith_mode, \ enable_scatter,
tuning_range_fmin, \ enable_fft,
tuning_range_fmax, \ low_bandwith_mode,
enable_fsk, \ tuning_range_fmin,
tx_audio_level \ tuning_range_fmax,
]) enable_fsk,
tx_audio_level,
]
)
command_response("start_tnc", True) command_response("start_tnc", True)
except Exception as e: except Exception as e:
command_response("start_tnc", False) command_response("start_tnc", 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
)
if received_json["type"] == 'get' and received_json["command"] == 'test_hamlib': if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
try: try:
devicename = str(received_json["parameter"][0]["devicename"]) devicename = str(received_json["parameter"][0]["devicename"])
@ -560,25 +645,30 @@ def process_daemon_commands(data):
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"]) rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
rigctld_port = str(received_json["parameter"][0]["rigctld_port"]) rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
DAEMON_QUEUE.put(['TEST_HAMLIB', \ DAEMON_QUEUE.put(
devicename, \ [
deviceport, \ "TEST_HAMLIB",
serialspeed, \ devicename,
pttprotocol, \ deviceport,
pttport, \ serialspeed,
data_bits, \ pttprotocol,
stop_bits, \ pttport,
handshake, \ data_bits,
radiocontrol, \ stop_bits,
rigctld_ip, \ handshake,
rigctld_port \ radiocontrol,
]) rigctld_ip,
rigctld_port,
]
)
command_response("test_hamlib", True) command_response("test_hamlib", True)
except Exception as e: except Exception as e:
command_response("test_hamlib", False) command_response("test_hamlib", 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
)
if received_json["type"] == 'set' and received_json["command"] == 'stop_tnc': if received_json["type"] == "set" and received_json["command"] == "stop_tnc":
try: try:
static.TNCPROCESS.kill() static.TNCPROCESS.kill()
# unregister process from atexit to avoid process zombies # unregister process from atexit to avoid process zombies
@ -589,7 +679,10 @@ def process_daemon_commands(data):
command_response("stop_tnc", True) command_response("stop_tnc", True)
except Exception as e: except Exception as e:
command_response("stop_tnc", False) command_response("stop_tnc", 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
)
def send_daemon_state(): def send_daemon_state():
""" """
@ -599,16 +692,16 @@ def send_daemon_state():
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
output = { output = {
'command': 'daemon_state', "command": "daemon_state",
'daemon_state': [], "daemon_state": [],
'python_version': str(python_version), "python_version": str(python_version),
'hamlib_version': static.HAMLIB_VERSION, "hamlib_version": static.HAMLIB_VERSION,
'input_devices': static.AUDIO_INPUT_DEVICES, "input_devices": static.AUDIO_INPUT_DEVICES,
'output_devices': static.AUDIO_OUTPUT_DEVICES, "output_devices": static.AUDIO_OUTPUT_DEVICES,
'serial_devices': static.SERIAL_DEVICES, "serial_devices": static.SERIAL_DEVICES,
#'cpu': str(psutil.cpu_percent()), #'cpu': str(psutil.cpu_percent()),
#'ram': str(psutil.virtual_memory().percent), #'ram': str(psutil.virtual_memory().percent),
'version': '0.1' "version": "0.1",
} }
if static.TNCSTARTED: if static.TNCSTARTED:
@ -616,7 +709,6 @@ def send_daemon_state():
else: else:
output["daemon_state"].append({"status": "stopped"}) output["daemon_state"].append({"status": "stopped"})
jsondata = json.dumps(output) jsondata = json.dumps(output)
return jsondata return jsondata
@ -624,12 +716,13 @@ def send_daemon_state():
structlog.get_logger("structlog").warning("[SCK] error", e=e) structlog.get_logger("structlog").warning("[SCK] error", e=e)
return None return None
def command_response(command, status): def command_response(command, status):
if status: if status:
status = "OK" status = "OK"
else: else:
status = "Failed" status = "Failed"
jsondata = {"command_response": command, "status" : status} jsondata = {"command_response": command, "status": status}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
SOCKET_QUEUE.put(data_out) 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 :-) Not nice, suggestions are appreciated :-)
""" """
VERSION = '0.3.3-alpha' VERSION = "0.3.3-alpha"
# DAEMON # DAEMON
DAEMONPORT = 3001 DAEMONPORT = 3001
@ -17,14 +17,14 @@ TNCPROCESS = 0
# Operator Defaults # Operator Defaults
MYCALLSIGN = b'AA0AA' MYCALLSIGN = b"AA0AA"
MYCALLSIGN_CRC = b'A' MYCALLSIGN_CRC = b"A"
DXCALLSIGN = b'AA0AA' DXCALLSIGN = b"AA0AA"
DXCALLSIGN_CRC = b'A' DXCALLSIGN_CRC = b"A"
MYGRID = b'' MYGRID = b""
DXGRID = b'' DXGRID = b""
SSID_LIST = [] # ssid list we are responding to SSID_LIST = [] # ssid list we are responding to
@ -43,21 +43,21 @@ SERIAL_DEVICES = []
PTT_STATE = False PTT_STATE = False
TRANSMITTING = False TRANSMITTING = False
HAMLIB_VERSION = '0' HAMLIB_VERSION = "0"
HAMLIB_PTT_TYPE = 'RTS' HAMLIB_PTT_TYPE = "RTS"
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO' HAMLIB_DEVICE_NAME = "RIG_MODEL_DUMMY_NOVFO"
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0' HAMLIB_DEVICE_PORT = "/dev/ttyUSB0"
HAMLIB_SERIAL_SPEED = '9600' HAMLIB_SERIAL_SPEED = "9600"
HAMLIB_PTT_PORT = '/dev/ttyUSB0' HAMLIB_PTT_PORT = "/dev/ttyUSB0"
HAMLIB_STOP_BITS = '1' HAMLIB_STOP_BITS = "1"
HAMLIB_DATA_BITS = '8' HAMLIB_DATA_BITS = "8"
HAMLIB_HANDSHAKE = 'None' HAMLIB_HANDSHAKE = "None"
HAMLIB_RADIOCONTROL = 'direct' HAMLIB_RADIOCONTROL = "direct"
HAMLIB_RIGCTLD_IP = '127.0.0.1' HAMLIB_RIGCTLD_IP = "127.0.0.1"
HAMLIB_RIGCTLD_PORT = '4532' HAMLIB_RIGCTLD_PORT = "4532"
HAMLIB_FREQUENCY = 0 HAMLIB_FREQUENCY = 0
HAMLIB_MODE = '' HAMLIB_MODE = ""
HAMLIB_BANDWITH = 0 HAMLIB_BANDWITH = 0
# ------------------------- # -------------------------
# FreeDV Defaults # FreeDV Defaults
@ -75,7 +75,7 @@ AUDIO_INPUT_DEVICES = []
AUDIO_OUTPUT_DEVICES = [] AUDIO_OUTPUT_DEVICES = []
AUDIO_INPUT_DEVICE = -2 AUDIO_INPUT_DEVICE = -2
AUDIO_OUTPUT_DEVICE = -2 AUDIO_OUTPUT_DEVICE = -2
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0] BUFFER_OVERFLOW_COUNTER = [0, 0, 0, 0, 0]
AUDIO_RMS = 0 AUDIO_RMS = 0
FFT = [0] FFT = [0]
@ -96,11 +96,13 @@ ARQ_SPEED_LEVEL = 0
TOTAL_BYTES = 0 TOTAL_BYTES = 0
#CHANNEL_STATE = 'RECEIVING_SIGNALLING' # CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = 'IDLE' TNC_STATE = "IDLE"
ARQ_STATE = False ARQ_STATE = False
ARQ_SESSION = False ARQ_SESSION = False
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed ARQ_SESSION_STATE = (
"disconnected" # disconnected, connecting, connected, disconnecting, failed
)
# BEACON STATE # BEACON STATE
BEACON_STATE = False BEACON_STATE = False
@ -110,8 +112,8 @@ BEACON_PAUSE = False
RX_BUFFER = [] RX_BUFFER = []
RX_MSG_BUFFER = [] RX_MSG_BUFFER = []
RX_BURST_BUFFER = [] RX_BURST_BUFFER = []
RX_FRAME_BUFFER = b'' RX_FRAME_BUFFER = b""
#RX_BUFFER_SIZE = 0 # RX_BUFFER_SIZE = 0
# ------- HEARD STATIOS BUFFER # ------- HEARD STATIOS BUFFER
HEARD_STATIONS = [] HEARD_STATIONS = []