mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
black code formatting
This commit is contained in:
parent
952c9b3839
commit
92cfa367f3
15 changed files with 4393 additions and 2248 deletions
18
tnc/audio.py
18
tnc/audio.py
|
@ -1,4 +1,3 @@
|
|||
|
||||
import json
|
||||
import sys
|
||||
import multiprocessing
|
||||
|
@ -7,10 +6,9 @@ import atexit
|
|||
|
||||
atexit.register(sd._terminate)
|
||||
|
||||
|
||||
def get_audio_devices():
|
||||
|
||||
|
||||
|
||||
"""
|
||||
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
|
||||
# multiprocessing.freeze_support()
|
||||
#multiprocessing.get_context('spawn')
|
||||
# multiprocessing.get_context('spawn')
|
||||
|
||||
# we need to reset and initialize sounddevice before running the multiprocessing part.
|
||||
# If we are not doing this at this early point, not all devices will be displayed
|
||||
|
@ -29,13 +27,16 @@ def get_audio_devices():
|
|||
|
||||
proxy_input_devices = manager.list()
|
||||
proxy_output_devices = manager.list()
|
||||
#print(multiprocessing.get_start_method())
|
||||
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
|
||||
# print(multiprocessing.get_start_method())
|
||||
p = multiprocessing.Process(
|
||||
target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)
|
||||
)
|
||||
p.start()
|
||||
p.join()
|
||||
|
||||
return list(proxy_input_devices), list(proxy_output_devices)
|
||||
|
||||
|
||||
def fetch_audio_devices(input_devices, output_devices):
|
||||
"""
|
||||
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)
|
||||
index = 0
|
||||
for device in devices:
|
||||
#for i in range(0, p.get_device_count()):
|
||||
# for i in range(0, p.get_device_count()):
|
||||
# we need to do a try exception, beacuse for windows theres no audio device range
|
||||
try:
|
||||
name = device["name"]
|
||||
|
@ -63,11 +64,10 @@ def fetch_audio_devices(input_devices, output_devices):
|
|||
print(e)
|
||||
maxInputChannels = 0
|
||||
maxOutputChannels = 0
|
||||
name = ''
|
||||
name = ""
|
||||
|
||||
if maxInputChannels > 0:
|
||||
input_devices.append({"id": index, "name": str(name)})
|
||||
if maxOutputChannels > 0:
|
||||
output_devices.append({"id": index, "name": str(name)})
|
||||
index += 1
|
||||
|
||||
|
|
119
tnc/codec2.py
119
tnc/codec2.py
|
@ -17,6 +17,7 @@ class FREEDV_MODE(Enum):
|
|||
"""
|
||||
enum for codec2 modes and names
|
||||
"""
|
||||
|
||||
fsk_ldpc_0 = 200
|
||||
fsk_ldpc_1 = 201
|
||||
fsk_ldpc = 9
|
||||
|
@ -25,6 +26,7 @@ class FREEDV_MODE(Enum):
|
|||
datac3 = 12
|
||||
allmodes = 255
|
||||
|
||||
|
||||
# function for returning the mode value
|
||||
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
|
||||
|
||||
|
||||
# function for returning the mode name
|
||||
def freedv_get_mode_name_by_value(mode):
|
||||
"""
|
||||
|
@ -58,14 +61,14 @@ except:
|
|||
sys.path.append(app_path)
|
||||
|
||||
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
|
||||
if sys.platform == 'linux':
|
||||
files = glob.glob('**/*libcodec2*',recursive=True)
|
||||
files.append('libcodec2.so')
|
||||
elif sys.platform == 'darwin':
|
||||
files = glob.glob('**/*libcodec2*.dylib',recursive=True)
|
||||
if sys.platform == "linux":
|
||||
files = glob.glob("**/*libcodec2*", recursive=True)
|
||||
files.append("libcodec2.so")
|
||||
elif sys.platform == "darwin":
|
||||
files = glob.glob("**/*libcodec2*.dylib", recursive=True)
|
||||
|
||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||
files = glob.glob('**\*libcodec2*.dll',recursive=True)
|
||||
elif sys.platform == "win32" or sys.platform == "win64":
|
||||
files = glob.glob("**\*libcodec2*.dll", recursive=True)
|
||||
else:
|
||||
files = []
|
||||
|
||||
|
@ -76,21 +79,21 @@ for file in files:
|
|||
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
|
||||
break
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=e)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[C2 ] Libcodec2 found but not loaded", path=file, e=e
|
||||
)
|
||||
|
||||
|
||||
# quit module if codec2 cant be loaded
|
||||
if not 'api' in locals():
|
||||
if not "api" in locals():
|
||||
structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded", path=file)
|
||||
os._exit(1)
|
||||
|
||||
|
||||
|
||||
|
||||
# ctypes function init
|
||||
|
||||
#api.freedv_set_tuning_range.restype = c_int
|
||||
#api.freedv_set_tuning_range.argype = [c_void_p, c_float, c_float]
|
||||
# api.freedv_set_tuning_range.restype = c_int
|
||||
# api.freedv_set_tuning_range.argype = [c_void_p, c_float, c_float]
|
||||
|
||||
api.freedv_open.argype = [c_int]
|
||||
api.freedv_open.restype = c_void_p
|
||||
|
@ -151,6 +154,7 @@ api.FREEDV_MODE_FSK_LDPC = 9
|
|||
# advanced structure for fsk modes
|
||||
class ADVANCED(ctypes.Structure):
|
||||
""" """
|
||||
|
||||
_fields_ = [
|
||||
("interleave_frames", ctypes.c_int),
|
||||
("M", ctypes.c_int),
|
||||
|
@ -161,7 +165,8 @@ class ADVANCED(ctypes.Structure):
|
|||
("codename", ctypes.c_char_p),
|
||||
]
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
adv.interleave_frames = 0 # max amplitude
|
||||
adv.M = 2 # number of fsk tones 2/4
|
||||
adv.Rs = 100 # symbol rate
|
||||
|
@ -181,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_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
|
||||
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
|
||||
'''
|
||||
"""
|
||||
# --------------- 2 FSK H_128_256_5, 16 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED()
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0
|
||||
|
@ -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.Fs = 8000
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 #200
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = 'H_128_256_5'.encode('utf-8') # code word
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 # 200
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = "H_128_256_5".encode("utf-8") # code word
|
||||
|
||||
# --------------- 4 H_256_512_4, 7 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED()
|
||||
|
@ -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.first_tone = 1250 # 1250 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = 'H_256_512_4'.encode('utf-8') # code word
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_256_512_4".encode("utf-8") # code word
|
||||
|
||||
# ------- MODEM STATS STRUCTURES
|
||||
|
||||
MODEM_STATS_NC_MAX = 50+1
|
||||
MODEM_STATS_NC_MAX = 50 + 1
|
||||
MODEM_STATS_NR_MAX = 160
|
||||
MODEM_STATS_ET_MAX = 8
|
||||
MODEM_STATS_EYE_IND_MAX = 160
|
||||
|
@ -214,10 +219,11 @@ MODEM_STATS_MAX_F_EST = 4
|
|||
# modem stats structure
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
""" """
|
||||
|
||||
_fields_ = [
|
||||
("Nc", ctypes.c_int),
|
||||
("snr_est", ctypes.c_float),
|
||||
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX),
|
||||
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX) * MODEM_STATS_NC_MAX),
|
||||
("nr", ctypes.c_int),
|
||||
("sync", ctypes.c_int),
|
||||
("foff", ctypes.c_float),
|
||||
|
@ -229,17 +235,21 @@ class MODEMSTATS(ctypes.Structure):
|
|||
("uw_fails", ctypes.c_int),
|
||||
("neyetr", ctypes.c_int), # How many eye traces are plotted
|
||||
("neyesamp", ctypes.c_int), # How many samples in the eye diagram
|
||||
("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), # How many samples in the eye diagram
|
||||
(
|
||||
"f_est",
|
||||
(ctypes.c_float * MODEM_STATS_MAX_F_EST),
|
||||
), # How many samples in the eye diagram
|
||||
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
|
||||
]
|
||||
|
||||
|
||||
|
||||
# Return code flags for freedv_get_rx_status() function
|
||||
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
|
||||
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
|
||||
api.FREEDV_RX_BITS = 0x4 # data bits have been returned
|
||||
api.FREEDV_RX_BIT_ERRORS = 0x8 # FEC may not have corrected all bit errors (not all parity checks OK)
|
||||
api.FREEDV_RX_BIT_ERRORS = (
|
||||
0x8 # FEC may not have corrected all bit errors (not all parity checks OK)
|
||||
)
|
||||
|
||||
api.rx_sync_flags_to_text = [
|
||||
"----",
|
||||
|
@ -257,25 +267,31 @@ api.rx_sync_flags_to_text = [
|
|||
"EB--",
|
||||
"EB-T",
|
||||
"EBS-",
|
||||
"EBST"]
|
||||
"EBST",
|
||||
]
|
||||
|
||||
# audio buffer ---------------------------------------------------------
|
||||
|
||||
|
||||
class audio_buffer:
|
||||
"""
|
||||
thread safe audio buffer, which fits to needs of codec2
|
||||
|
||||
made by David Rowe, VK5DGR
|
||||
"""
|
||||
|
||||
# a buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
||||
# self.nbuffer is the current number of samples in the buffer
|
||||
def __init__(self, size):
|
||||
structlog.get_logger("structlog").debug("[C2 ] creating audio buffer", size=size)
|
||||
structlog.get_logger("structlog").debug(
|
||||
"[C2 ] creating audio buffer", size=size
|
||||
)
|
||||
self.size = size
|
||||
self.buffer = np.zeros(size, dtype=np.int16)
|
||||
self.nbuffer = 0
|
||||
self.mutex = Lock()
|
||||
def push(self,samples):
|
||||
|
||||
def push(self, samples):
|
||||
"""
|
||||
Push new data to buffer
|
||||
|
||||
|
@ -287,11 +303,12 @@ class audio_buffer:
|
|||
"""
|
||||
self.mutex.acquire()
|
||||
# add samples at the end of the buffer
|
||||
assert self.nbuffer+len(samples) <= self.size
|
||||
self.buffer[self.nbuffer:self.nbuffer+len(samples)] = samples
|
||||
assert self.nbuffer + len(samples) <= self.size
|
||||
self.buffer[self.nbuffer : self.nbuffer + len(samples)] = samples
|
||||
self.nbuffer += len(samples)
|
||||
self.mutex.release()
|
||||
def pop(self,size):
|
||||
|
||||
def pop(self, size):
|
||||
"""
|
||||
get data from buffer in size of NIN
|
||||
Args:
|
||||
|
@ -302,23 +319,28 @@ class audio_buffer:
|
|||
"""
|
||||
self.mutex.acquire()
|
||||
# remove samples from the start of the buffer
|
||||
self.nbuffer -= size;
|
||||
self.buffer[:self.nbuffer] = self.buffer[size:size+self.nbuffer]
|
||||
self.nbuffer -= size
|
||||
self.buffer[: self.nbuffer] = self.buffer[size : size + self.nbuffer]
|
||||
assert self.nbuffer >= 0
|
||||
self.mutex.release()
|
||||
|
||||
|
||||
# resampler ---------------------------------------------------------
|
||||
|
||||
api.FDMDV_OS_48 = int(6) # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = int(api.FDMDV_OS_TAPS_48K/api.FDMDV_OS_48) # number of OS filter taps at 8kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = int(
|
||||
api.FDMDV_OS_TAPS_48K / api.FDMDV_OS_48
|
||||
) # number of OS filter taps at 8kHz
|
||||
api.fdmdv_8_to_48_short.argtype = [c_void_p, c_void_p, c_int]
|
||||
api.fdmdv_48_to_8_short.argtype = [c_void_p, c_void_p, c_int]
|
||||
|
||||
|
||||
class resampler:
|
||||
"""
|
||||
resampler class
|
||||
"""
|
||||
|
||||
# resample an array of variable length, we just store the filter memories here
|
||||
MEM8 = api.FDMDV_OS_TAPS_48_8K
|
||||
MEM48 = api.FDMDV_OS_TAPS_48K
|
||||
|
@ -328,8 +350,7 @@ class resampler:
|
|||
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
|
||||
self.filter_mem48 = np.zeros(self.MEM48)
|
||||
|
||||
|
||||
def resample48_to_8(self,in48):
|
||||
def resample48_to_8(self, in48):
|
||||
"""
|
||||
audio resampler integration from codec2
|
||||
downsample audio from 48000Hz to 8000Hz
|
||||
|
@ -341,25 +362,25 @@ class resampler:
|
|||
"""
|
||||
assert in48.dtype == np.int16
|
||||
# length of input vector must be an integer multiple of api.FDMDV_OS_48
|
||||
assert(len(in48) % api.FDMDV_OS_48 == 0)
|
||||
assert len(in48) % api.FDMDV_OS_48 == 0
|
||||
|
||||
# concat filter memory and input samples
|
||||
in48_mem = np.zeros(self.MEM48+len(in48), dtype=np.int16)
|
||||
in48_mem[:self.MEM48] = self.filter_mem48
|
||||
in48_mem[self.MEM48:] = in48
|
||||
in48_mem = np.zeros(self.MEM48 + len(in48), dtype=np.int16)
|
||||
in48_mem[: self.MEM48] = self.filter_mem48
|
||||
in48_mem[self.MEM48 :] = in48
|
||||
|
||||
# In C: pin48=&in48_mem[MEM48]
|
||||
pin48 = byref(np.ctypeslib.as_ctypes(in48_mem), 2*self.MEM48)
|
||||
pin48 = byref(np.ctypeslib.as_ctypes(in48_mem), 2 * self.MEM48)
|
||||
n8 = int(len(in48) / api.FDMDV_OS_48)
|
||||
out8 = np.zeros(n8, dtype=np.int16)
|
||||
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8);
|
||||
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8)
|
||||
|
||||
# store memory for next time
|
||||
self.filter_mem48 = in48_mem[:self.MEM48]
|
||||
self.filter_mem48 = in48_mem[: self.MEM48]
|
||||
|
||||
return out8
|
||||
|
||||
def resample8_to_48(self,in8):
|
||||
def resample8_to_48(self, in8):
|
||||
"""
|
||||
audio resampler integration from codec2
|
||||
resample audio from 8000Hz to 48000Hz
|
||||
|
@ -372,16 +393,16 @@ class resampler:
|
|||
assert in8.dtype == np.int16
|
||||
|
||||
# concat filter memory and input samples
|
||||
in8_mem = np.zeros(self.MEM8+len(in8), dtype=np.int16)
|
||||
in8_mem[:self.MEM8] = self.filter_mem8
|
||||
in8_mem[self.MEM8:] = in8
|
||||
in8_mem = np.zeros(self.MEM8 + len(in8), dtype=np.int16)
|
||||
in8_mem[: self.MEM8] = self.filter_mem8
|
||||
in8_mem[self.MEM8 :] = in8
|
||||
|
||||
# In C: pin8=&in8_mem[MEM8]
|
||||
pin8 = byref(np.ctypeslib.as_ctypes(in8_mem), 2*self.MEM8)
|
||||
out48 = np.zeros(api.FDMDV_OS_48*len(in8), dtype=np.int16)
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8));
|
||||
pin8 = byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8)
|
||||
out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16)
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8))
|
||||
|
||||
# store memory for next time
|
||||
self.filter_mem8 = in8_mem[:self.MEM8]
|
||||
self.filter_mem8 = in8_mem[: self.MEM8]
|
||||
|
||||
return out48
|
||||
|
|
227
tnc/daemon.py
227
tnc/daemon.py
|
@ -43,35 +43,39 @@ def signal_handler(sig, frame):
|
|||
Returns: system exit
|
||||
|
||||
"""
|
||||
print('Closing daemon...')
|
||||
print("Closing daemon...")
|
||||
sock.CLOSE_SIGNAL = True
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
|
||||
|
||||
class DAEMON():
|
||||
class DAEMON:
|
||||
"""
|
||||
daemon class
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# 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
|
||||
update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True)
|
||||
update_audio_devices = threading.Thread(
|
||||
target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True
|
||||
)
|
||||
update_audio_devices.start()
|
||||
|
||||
update_serial_devices = threading.Thread(target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True)
|
||||
update_serial_devices = threading.Thread(
|
||||
target=self.update_serial_devices, name="UPDATE_SERIAL_DEVICES", daemon=True
|
||||
)
|
||||
update_serial_devices.start()
|
||||
|
||||
worker = threading.Thread(target=self.worker, name="WORKER", daemon=True)
|
||||
worker.start()
|
||||
|
||||
|
||||
|
||||
def update_audio_devices(self):
|
||||
"""
|
||||
update audio devices and set to static
|
||||
|
@ -80,29 +84,33 @@ class DAEMON():
|
|||
try:
|
||||
if not static.TNCSTARTED:
|
||||
|
||||
static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices()
|
||||
(
|
||||
static.AUDIO_INPUT_DEVICES,
|
||||
static.AUDIO_OUTPUT_DEVICES,
|
||||
) = audio.get_audio_devices()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def update_serial_devices(self):
|
||||
"""
|
||||
update serial devices and set to static
|
||||
"""
|
||||
while 1:
|
||||
try:
|
||||
#print("update serial")
|
||||
# print("update serial")
|
||||
serial_devices = []
|
||||
ports = serial.tools.list_ports.comports()
|
||||
for port, desc, hwid in ports:
|
||||
|
||||
# calculate hex of hwid if we have unique names
|
||||
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8'))
|
||||
crc_hwid = crc_hwid.to_bytes(2, byteorder='big')
|
||||
crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
|
||||
crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
|
||||
crc_hwid = crc_hwid.hex()
|
||||
description = desc + ' [' + crc_hwid + ']'
|
||||
serial_devices.append({"port": str(port), "description": str(description) })
|
||||
description = desc + " [" + crc_hwid + "]"
|
||||
serial_devices.append(
|
||||
{"port": str(port), "description": str(description)}
|
||||
)
|
||||
|
||||
static.SERIAL_DEVICES = serial_devices
|
||||
time.sleep(1)
|
||||
|
@ -139,131 +147,134 @@ class DAEMON():
|
|||
# data[19] tuning_range_fmin
|
||||
# data[20] tuning_range_fmax
|
||||
|
||||
if data[0] == 'STARTTNC':
|
||||
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||
if data[0] == "STARTTNC":
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[DMN] Starting TNC", rig=data[5], port=data[6]
|
||||
)
|
||||
|
||||
# list of parameters, necessary for running subprocess command as a list
|
||||
options = []
|
||||
|
||||
options.append('--port')
|
||||
options.append("--port")
|
||||
options.append(str(static.DAEMONPORT - 1))
|
||||
|
||||
options.append('--mycall')
|
||||
options.append("--mycall")
|
||||
options.append(data[1])
|
||||
|
||||
options.append('--mygrid')
|
||||
options.append("--mygrid")
|
||||
options.append(data[2])
|
||||
|
||||
options.append('--rx')
|
||||
options.append("--rx")
|
||||
options.append(data[3])
|
||||
|
||||
options.append('--tx')
|
||||
options.append("--tx")
|
||||
options.append(data[4])
|
||||
|
||||
# if radiocontrol != disabled
|
||||
# this should hopefully avoid a ton of problems if we are just running in
|
||||
# disabled mode
|
||||
|
||||
if data[13] != 'disabled':
|
||||
if data[13] != "disabled":
|
||||
|
||||
options.append('--devicename')
|
||||
options.append("--devicename")
|
||||
options.append(data[5])
|
||||
|
||||
options.append('--deviceport')
|
||||
options.append("--deviceport")
|
||||
options.append(data[6])
|
||||
|
||||
options.append('--serialspeed')
|
||||
options.append("--serialspeed")
|
||||
options.append(data[7])
|
||||
|
||||
options.append('--pttprotocol')
|
||||
options.append("--pttprotocol")
|
||||
options.append(data[8])
|
||||
|
||||
options.append('--pttport')
|
||||
options.append("--pttport")
|
||||
options.append(data[9])
|
||||
|
||||
options.append('--data_bits')
|
||||
options.append("--data_bits")
|
||||
options.append(data[10])
|
||||
|
||||
options.append('--stop_bits')
|
||||
options.append("--stop_bits")
|
||||
options.append(data[11])
|
||||
|
||||
options.append('--handshake')
|
||||
options.append("--handshake")
|
||||
options.append(data[12])
|
||||
|
||||
options.append('--radiocontrol')
|
||||
options.append("--radiocontrol")
|
||||
options.append(data[13])
|
||||
|
||||
if data[13] != 'rigctld':
|
||||
options.append('--rigctld_ip')
|
||||
if data[13] != "rigctld":
|
||||
options.append("--rigctld_ip")
|
||||
options.append(data[14])
|
||||
|
||||
options.append('--rigctld_port')
|
||||
options.append("--rigctld_port")
|
||||
options.append(data[15])
|
||||
|
||||
if data[16] == 'True':
|
||||
options.append('--scatter')
|
||||
if data[16] == "True":
|
||||
options.append("--scatter")
|
||||
|
||||
if data[17] == 'True':
|
||||
options.append('--fft')
|
||||
if data[17] == "True":
|
||||
options.append("--fft")
|
||||
|
||||
if data[18] == 'True':
|
||||
options.append('--500hz')
|
||||
if data[18] == "True":
|
||||
options.append("--500hz")
|
||||
|
||||
|
||||
options.append('--tuning_range_fmin')
|
||||
options.append("--tuning_range_fmin")
|
||||
options.append(data[19])
|
||||
|
||||
options.append('--tuning_range_fmax')
|
||||
options.append("--tuning_range_fmax")
|
||||
options.append(data[20])
|
||||
|
||||
# overriding FSK mode
|
||||
#if data[21] == 'True':
|
||||
# if data[21] == 'True':
|
||||
# options.append('--fsk')
|
||||
|
||||
options.append('--tx-audio-level')
|
||||
options.append("--tx-audio-level")
|
||||
options.append(data[22])
|
||||
|
||||
|
||||
|
||||
# try running tnc from binary, else run from source
|
||||
# this helps running the tnc in a developer environment
|
||||
try:
|
||||
command = []
|
||||
if sys.platform == 'linux' or sys.platform == 'darwin':
|
||||
command.append('./freedata-tnc')
|
||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||
command.append('freedata-tnc.exe')
|
||||
if sys.platform == "linux" or sys.platform == "darwin":
|
||||
command.append("./freedata-tnc")
|
||||
elif sys.platform == "win32" or sys.platform == "win64":
|
||||
command.append("freedata-tnc.exe")
|
||||
|
||||
command += options
|
||||
p = subprocess.Popen(command)
|
||||
|
||||
atexit.register(p.kill)
|
||||
|
||||
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary")
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] TNC started", path="binary"
|
||||
)
|
||||
except:
|
||||
command = []
|
||||
if sys.platform == 'linux' or sys.platform == 'darwin':
|
||||
command.append('python3')
|
||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||
command.append('python')
|
||||
if sys.platform == "linux" or sys.platform == "darwin":
|
||||
command.append("python3")
|
||||
elif sys.platform == "win32" or sys.platform == "win64":
|
||||
command.append("python")
|
||||
|
||||
command.append('main.py')
|
||||
command.append("main.py")
|
||||
command += options
|
||||
p = subprocess.Popen(command)
|
||||
atexit.register(p.kill)
|
||||
|
||||
structlog.get_logger("structlog").info("[DMN] TNC started", path="source")
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] TNC started", path="source"
|
||||
)
|
||||
|
||||
static.TNCPROCESS = p # .pid
|
||||
static.TNCSTARTED = True
|
||||
'''
|
||||
"""
|
||||
# WE HAVE THIS PART in SOCKET
|
||||
if data[0] == 'STOPTNC':
|
||||
static.TNCPROCESS.kill()
|
||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
||||
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
||||
static.TNCSTARTED = False
|
||||
'''
|
||||
"""
|
||||
# data[1] devicename
|
||||
# data[2] deviceport
|
||||
# data[3] serialspeed
|
||||
|
@ -275,7 +286,7 @@ class DAEMON():
|
|||
# data[9] radiocontrol
|
||||
# data[10] rigctld_ip
|
||||
# data[11] rigctld_port
|
||||
if data[0] == 'TEST_HAMLIB':
|
||||
if data[0] == "TEST_HAMLIB":
|
||||
|
||||
devicename = data[1]
|
||||
deviceport = data[2]
|
||||
|
@ -289,20 +300,29 @@ class DAEMON():
|
|||
rigctld_ip = data[10]
|
||||
rigctld_port = data[11]
|
||||
|
||||
|
||||
|
||||
# check how we want to control the radio
|
||||
if radiocontrol == 'direct':
|
||||
if radiocontrol == "direct":
|
||||
import rig
|
||||
elif radiocontrol == 'rigctl':
|
||||
elif radiocontrol == "rigctl":
|
||||
import rigctl as rig
|
||||
elif radiocontrol == 'rigctld':
|
||||
elif radiocontrol == "rigctld":
|
||||
import rigctld as rig
|
||||
else:
|
||||
import rigdummy as rig
|
||||
|
||||
hamlib = rig.radio()
|
||||
hamlib.open_rig(devicename=devicename, deviceport=deviceport, hamlib_ptt_type=pttprotocol, serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits, handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port)
|
||||
hamlib.open_rig(
|
||||
devicename=devicename,
|
||||
deviceport=deviceport,
|
||||
hamlib_ptt_type=pttprotocol,
|
||||
serialspeed=serialspeed,
|
||||
pttport=pttport,
|
||||
data_bits=data_bits,
|
||||
stop_bits=stop_bits,
|
||||
handshake=handshake,
|
||||
rigctld_ip=rigctld_ip,
|
||||
rigctld_port=rigctld_port,
|
||||
)
|
||||
|
||||
hamlib_version = rig.hamlib_version
|
||||
|
||||
|
@ -310,14 +330,20 @@ class DAEMON():
|
|||
pttstate = hamlib.get_ptt()
|
||||
|
||||
if pttstate:
|
||||
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS')
|
||||
response = {'command': 'test_hamlib', 'result': 'SUCCESS'}
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] Hamlib PTT", status="SUCCESS"
|
||||
)
|
||||
response = {"command": "test_hamlib", "result": "SUCCESS"}
|
||||
elif not pttstate:
|
||||
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS')
|
||||
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'}
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[DMN] Hamlib PTT", status="NO SUCCESS"
|
||||
)
|
||||
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
|
||||
else:
|
||||
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED')
|
||||
response = {'command': 'test_hamlib', 'result': 'FAILED'}
|
||||
structlog.get_logger("structlog").error(
|
||||
"[DMN] Hamlib PTT", status="FAILED"
|
||||
)
|
||||
response = {"command": "test_hamlib", "result": "FAILED"}
|
||||
|
||||
hamlib.set_ptt(False)
|
||||
hamlib.close_rig()
|
||||
|
@ -329,29 +355,38 @@ class DAEMON():
|
|||
print(e)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
# we need to run this on windows for multiprocessing support
|
||||
multiprocessing.freeze_support()
|
||||
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description='FreeDATA Daemon')
|
||||
PARSER.add_argument('--port', dest="socket_port",default=3001, help="Socket port in the range of 1024-65536", type=int)
|
||||
PARSER = argparse.ArgumentParser(description="FreeDATA Daemon")
|
||||
PARSER.add_argument(
|
||||
"--port",
|
||||
dest="socket_port",
|
||||
default=3001,
|
||||
help="Socket port in the range of 1024-65536",
|
||||
type=int,
|
||||
)
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
static.DAEMONPORT = ARGS.socket_port
|
||||
|
||||
|
||||
try:
|
||||
if sys.platform == 'linux':
|
||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform == "linux":
|
||||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform == "darwin":
|
||||
logging_path = (
|
||||
os.getenv("HOME")
|
||||
+ "/Library/"
|
||||
+ "Application Support/"
|
||||
+ "FreeDATA/"
|
||||
+ "daemon"
|
||||
)
|
||||
|
||||
if sys.platform == 'win32' or sys.platform == 'win64':
|
||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform == "win32" or sys.platform == "win64":
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
|
||||
|
||||
if not os.path.exists(logging_path):
|
||||
os.makedirs(logging_path)
|
||||
|
@ -360,20 +395,30 @@ if __name__ == '__main__':
|
|||
structlog.get_logger("structlog").error("[DMN] logger init error")
|
||||
|
||||
try:
|
||||
structlog.get_logger("structlog").info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] Starting TCP/IP socket", port=static.DAEMONPORT
|
||||
)
|
||||
# https://stackoverflow.com/a/16641793
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler)
|
||||
cmdserver = sock.ThreadedTCPServer(
|
||||
(static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler
|
||||
)
|
||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e)
|
||||
structlog.get_logger("structlog").error(
|
||||
"[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e
|
||||
)
|
||||
os._exit(1)
|
||||
daemon = DAEMON()
|
||||
|
||||
|
||||
structlog.get_logger("structlog").info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] Starting FreeDATA Daemon",
|
||||
author="DJ2LS",
|
||||
year="2022",
|
||||
version=static.VERSION,
|
||||
)
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
|
1334
tnc/data_handler.py
1334
tnc/data_handler.py
File diff suppressed because it is too large
Load diff
135
tnc/helpers.py
135
tnc/helpers.py
|
@ -11,7 +11,6 @@ import crcengine
|
|||
import static
|
||||
|
||||
|
||||
|
||||
def wait(seconds):
|
||||
"""
|
||||
|
||||
|
@ -28,7 +27,6 @@ def wait(seconds):
|
|||
return True
|
||||
|
||||
|
||||
|
||||
def get_crc_8(data):
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -42,9 +40,9 @@ def get_crc_8(data):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
crc_algorithm = crcengine.new('crc8-ccitt') # load crc8 library
|
||||
crc_algorithm = crcengine.new("crc8-ccitt") # load crc8 library
|
||||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(1, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(1, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
|
@ -61,11 +59,12 @@ def get_crc_16(data):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library
|
||||
crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
|
||||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(2, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(2, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_32(data):
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -79,9 +78,9 @@ def get_crc_32(data):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
crc_algorithm = crcengine.new('crc32') # load crc16 library
|
||||
crc_algorithm = crcengine.new("crc32") # load crc16 library
|
||||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(4, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(4, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
|
@ -102,17 +101,37 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
|||
|
||||
# check if buffer empty
|
||||
if len(static.HEARD_STATIONS) == 0:
|
||||
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency])
|
||||
static.HEARD_STATIONS.append(
|
||||
[dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
|
||||
)
|
||||
# if not, we search and update
|
||||
else:
|
||||
for i in range(0, len(static.HEARD_STATIONS)):
|
||||
# update callsign with new timestamp
|
||||
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
||||
static.HEARD_STATIONS[i] = [dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]
|
||||
static.HEARD_STATIONS[i] = [
|
||||
dxcallsign,
|
||||
dxgrid,
|
||||
int(time.time()),
|
||||
datatype,
|
||||
snr,
|
||||
offset,
|
||||
frequency,
|
||||
]
|
||||
break
|
||||
# insert if nothing found
|
||||
if i == len(static.HEARD_STATIONS) - 1:
|
||||
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency])
|
||||
static.HEARD_STATIONS.append(
|
||||
[
|
||||
dxcallsign,
|
||||
dxgrid,
|
||||
int(time.time()),
|
||||
datatype,
|
||||
snr,
|
||||
offset,
|
||||
frequency,
|
||||
]
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
|
@ -122,7 +141,6 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
|||
# static.HEARD_STATIONS[idx] = item
|
||||
|
||||
|
||||
|
||||
def callsign_to_bytes(callsign):
|
||||
"""
|
||||
|
||||
|
@ -133,31 +151,31 @@ def callsign_to_bytes(callsign):
|
|||
|
||||
"""
|
||||
# http://www.aprs.org/aprs11/SSIDs.txt
|
||||
#-0 Your primary station usually fixed and message capable
|
||||
#-1 generic additional station, digi, mobile, wx, etc
|
||||
#-2 generic additional station, digi, mobile, wx, etc
|
||||
#-3 generic additional station, digi, mobile, wx, etc
|
||||
#-4 generic additional station, digi, mobile, wx, etc
|
||||
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||
#-6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||
#-7 walkie talkies, HT's or other human portable
|
||||
#-8 boats, sailboats, RV's or second main mobile
|
||||
#-9 Primary Mobile (usually message capable)
|
||||
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||
#-11 balloons, aircraft, spacecraft, etc
|
||||
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||
#-13 Weather stations
|
||||
#-14 Truckers or generally full time drivers
|
||||
#-15 generic additional station, digi, mobile, wx, etc
|
||||
# -0 Your primary station usually fixed and message capable
|
||||
# -1 generic additional station, digi, mobile, wx, etc
|
||||
# -2 generic additional station, digi, mobile, wx, etc
|
||||
# -3 generic additional station, digi, mobile, wx, etc
|
||||
# -4 generic additional station, digi, mobile, wx, etc
|
||||
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||
# -6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||
# -7 walkie talkies, HT's or other human portable
|
||||
# -8 boats, sailboats, RV's or second main mobile
|
||||
# -9 Primary Mobile (usually message capable)
|
||||
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||
# -11 balloons, aircraft, spacecraft, etc
|
||||
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||
# -13 Weather stations
|
||||
# -14 Truckers or generally full time drivers
|
||||
# -15 generic additional station, digi, mobile, wx, etc
|
||||
|
||||
# try converting to bytestring if possible type string
|
||||
try:
|
||||
callsign = bytes(callsign, 'utf-8')
|
||||
callsign = bytes(callsign, "utf-8")
|
||||
except:
|
||||
pass
|
||||
|
||||
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
|
||||
callsign = callsign.split(b'-')
|
||||
callsign = callsign.split(b"-")
|
||||
try:
|
||||
ssid = int(callsign[1])
|
||||
except:
|
||||
|
@ -166,11 +184,12 @@ def callsign_to_bytes(callsign):
|
|||
callsign = callsign[0]
|
||||
|
||||
bytestring = bytearray(8)
|
||||
bytestring[:len(callsign)] = callsign
|
||||
bytestring[: len(callsign)] = callsign
|
||||
bytestring[7:8] = bytes([ssid])
|
||||
|
||||
return bytes(bytestring)
|
||||
|
||||
|
||||
def bytes_to_callsign(bytestring):
|
||||
"""
|
||||
|
||||
|
@ -182,40 +201,38 @@ def bytes_to_callsign(bytestring):
|
|||
"""
|
||||
|
||||
# http://www.aprs.org/aprs11/SSIDs.txt
|
||||
#-0 Your primary station usually fixed and message capable
|
||||
#-1 generic additional station, digi, mobile, wx, etc
|
||||
#-2 generic additional station, digi, mobile, wx, etc
|
||||
#-3 generic additional station, digi, mobile, wx, etc
|
||||
#-4 generic additional station, digi, mobile, wx, etc
|
||||
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||
#-6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||
#-7 walkie talkies, HT's or other human portable
|
||||
#-8 boats, sailboats, RV's or second main mobile
|
||||
#-9 Primary Mobile (usually message capable)
|
||||
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||
#-11 balloons, aircraft, spacecraft, etc
|
||||
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||
#-13 Weather stations
|
||||
#-14 Truckers or generally full time drivers
|
||||
#-15 generic additional station, digi, mobile, wx, etc
|
||||
# -0 Your primary station usually fixed and message capable
|
||||
# -1 generic additional station, digi, mobile, wx, etc
|
||||
# -2 generic additional station, digi, mobile, wx, etc
|
||||
# -3 generic additional station, digi, mobile, wx, etc
|
||||
# -4 generic additional station, digi, mobile, wx, etc
|
||||
# -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
|
||||
# -6 Special activity, Satellite ops, camping or 6 meters, etc
|
||||
# -7 walkie talkies, HT's or other human portable
|
||||
# -8 boats, sailboats, RV's or second main mobile
|
||||
# -9 Primary Mobile (usually message capable)
|
||||
# -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
|
||||
# -11 balloons, aircraft, spacecraft, etc
|
||||
# -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
|
||||
# -13 Weather stations
|
||||
# -14 Truckers or generally full time drivers
|
||||
# -15 generic additional station, digi, mobile, wx, etc
|
||||
|
||||
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
|
||||
|
||||
callsign = bytes(bytestring[:7])
|
||||
callsign = callsign.rstrip(b'\x00')
|
||||
callsign = callsign.rstrip(b"\x00")
|
||||
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
|
||||
|
||||
callsign = callsign + b'-'
|
||||
callsign = callsign.decode('utf-8')
|
||||
callsign = callsign + b"-"
|
||||
callsign = callsign.decode("utf-8")
|
||||
callsign = callsign + str(ssid)
|
||||
callsign = callsign.encode('utf-8')
|
||||
callsign = callsign.encode("utf-8")
|
||||
|
||||
return bytes(callsign)
|
||||
|
||||
|
||||
|
||||
|
||||
def check_callsign(callsign:bytes, crc_to_check:bytes):
|
||||
def check_callsign(callsign: bytes, crc_to_check: bytes):
|
||||
"""
|
||||
Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it
|
||||
|
||||
|
@ -228,10 +245,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|||
False
|
||||
"""
|
||||
|
||||
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library
|
||||
crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
|
||||
|
||||
try:
|
||||
callsign = callsign.split(b'-')
|
||||
callsign = callsign.split(b"-")
|
||||
callsign = callsign[0] # we want the callsign without SSID
|
||||
|
||||
except:
|
||||
|
@ -241,10 +258,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|||
for ssid in static.SSID_LIST:
|
||||
print(ssid)
|
||||
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.extend('-'.encode('utf-8'))
|
||||
call_with_ssid.extend(str(ssid).encode('utf-8'))
|
||||
call_with_ssid.extend("-".encode("utf-8"))
|
||||
call_with_ssid.extend(str(ssid).encode("utf-8"))
|
||||
|
||||
callsign_crc = get_crc_16(call_with_ssid)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,8 @@ def setup_logging(filename):
|
|||
timestamper,
|
||||
]
|
||||
|
||||
logging.config.dictConfig({
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
|
@ -44,7 +45,7 @@ def setup_logging(filename):
|
|||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.WatchedFileHandler",
|
||||
"filename": filename + '.log',
|
||||
"filename": filename + ".log",
|
||||
"formatter": "plain",
|
||||
},
|
||||
},
|
||||
|
@ -54,8 +55,9 @@ def setup_logging(filename):
|
|||
"level": "DEBUG",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.add_log_level,
|
||||
|
|
257
tnc/main.py
257
tnc/main.py
|
@ -13,18 +13,19 @@ main module for running the tnc
|
|||
|
||||
import argparse
|
||||
import threading
|
||||
import static
|
||||
import socketserver
|
||||
import helpers
|
||||
import data_handler
|
||||
import structlog
|
||||
import log_handler
|
||||
import modem
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
import multiprocessing
|
||||
import structlog
|
||||
|
||||
import modem
|
||||
import static
|
||||
import log_handler
|
||||
import helpers
|
||||
import data_handler
|
||||
|
||||
|
||||
# signal handler for closing aplication
|
||||
|
@ -38,56 +39,202 @@ def signal_handler(sig, frame):
|
|||
Returns: system exit
|
||||
|
||||
"""
|
||||
print('Closing TNC...')
|
||||
print("Closing TNC...")
|
||||
sock.CLOSE_SIGNAL = True
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
# we need to run this on windows for multiprocessing support
|
||||
multiprocessing.freeze_support()
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description='FreeDATA TNC')
|
||||
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str)
|
||||
PARSER.add_argument('--ssid', dest="ssid_list", nargs='*', default=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], help="SSID list we are responding to", type=str)
|
||||
PARSER.add_argument('--mygrid', dest="mygrid", default="JN12AA", help="My gridsquare", type=str)
|
||||
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int)
|
||||
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
||||
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int)
|
||||
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
|
||||
PARSER.add_argument('--devicename', dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str)
|
||||
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int)
|
||||
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", choices=['USB', 'RIG', 'RTS', 'DTR', 'CM108', 'MICDATA', 'PARALLEL', 'DTR-H', 'DTR-L', 'NONE'], default='USB', help="PTT Type", type=str)
|
||||
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
||||
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int)
|
||||
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int)
|
||||
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
|
||||
PARSER.add_argument('--radiocontrol', dest="hamlib_radiocontrol", choices=['disabled', 'direct', 'rigctl', 'rigctld'], default="disabled", help="Set how you want to control your radio")
|
||||
PARSER.add_argument('--rigctld_port', dest="rigctld_port", default=4532, type=int, help="Set rigctld port")
|
||||
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="localhost", help="Set rigctld ip")
|
||||
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network")
|
||||
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network")
|
||||
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )")
|
||||
PARSER.add_argument('--fsk', dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ")
|
||||
PARSER.add_argument('--tuning_range_fmin', dest="tuning_range_fmin", choices=[-50.0, -100.0, -150.0, -200.0, -250.0], default=-50.0, help="Tuning range fmin", type=float)
|
||||
PARSER.add_argument('--tuning_range_fmax', dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float)
|
||||
PARSER.add_argument('--tx-audio-level', dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int)
|
||||
|
||||
PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
|
||||
PARSER.add_argument(
|
||||
"--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--ssid",
|
||||
dest="ssid_list",
|
||||
nargs="*",
|
||||
default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
help="SSID list we are responding to",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--mygrid", dest="mygrid", default="JN12AA", help="My gridsquare", type=str
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--rx",
|
||||
dest="audio_input_device",
|
||||
default=0,
|
||||
help="listening sound card",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--tx",
|
||||
dest="audio_output_device",
|
||||
default=0,
|
||||
help="transmitting sound card",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--port",
|
||||
dest="socket_port",
|
||||
default=3000,
|
||||
help="Socket port in the range of 1024-65536",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--deviceport",
|
||||
dest="hamlib_device_port",
|
||||
default="/dev/ttyUSB0",
|
||||
help="Hamlib device port",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--devicename",
|
||||
dest="hamlib_device_name",
|
||||
default="2028",
|
||||
help="Hamlib device name",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--serialspeed",
|
||||
dest="hamlib_serialspeed",
|
||||
choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200],
|
||||
default=9600,
|
||||
help="Serialspeed",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--pttprotocol",
|
||||
dest="hamlib_ptt_type",
|
||||
choices=[
|
||||
"USB",
|
||||
"RIG",
|
||||
"RTS",
|
||||
"DTR",
|
||||
"CM108",
|
||||
"MICDATA",
|
||||
"PARALLEL",
|
||||
"DTR-H",
|
||||
"DTR-L",
|
||||
"NONE",
|
||||
],
|
||||
default="USB",
|
||||
help="PTT Type",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--pttport",
|
||||
dest="hamlib_ptt_port",
|
||||
default="/dev/ttyUSB0",
|
||||
help="PTT Port",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--data_bits",
|
||||
dest="hamlib_data_bits",
|
||||
choices=[7, 8],
|
||||
default=8,
|
||||
help="Hamlib data bits",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--stop_bits",
|
||||
dest="hamlib_stop_bits",
|
||||
choices=[1, 2],
|
||||
default=1,
|
||||
help="Hamlib stop bits",
|
||||
type=int,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--handshake",
|
||||
dest="hamlib_handshake",
|
||||
default="None",
|
||||
help="Hamlib handshake",
|
||||
type=str,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--radiocontrol",
|
||||
dest="hamlib_radiocontrol",
|
||||
choices=["disabled", "direct", "rigctl", "rigctld"],
|
||||
default="disabled",
|
||||
help="Set how you want to control your radio",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--rigctld_port",
|
||||
dest="rigctld_port",
|
||||
default=4532,
|
||||
type=int,
|
||||
help="Set rigctld port",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--rigctld_ip", dest="rigctld_ip", default="localhost", help="Set rigctld ip"
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--scatter",
|
||||
dest="send_scatter",
|
||||
action="store_true",
|
||||
help="Send scatter information via network",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--fft",
|
||||
dest="send_fft",
|
||||
action="store_true",
|
||||
help="Send fft information via network",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--500hz",
|
||||
dest="low_bandwith_mode",
|
||||
action="store_true",
|
||||
help="Enable low bandwith mode ( 500 Hz only )",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--fsk",
|
||||
dest="enable_fsk",
|
||||
action="store_true",
|
||||
help="Enable FSK mode for ping, beacon and CQ",
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--tuning_range_fmin",
|
||||
dest="tuning_range_fmin",
|
||||
choices=[-50.0, -100.0, -150.0, -200.0, -250.0],
|
||||
default=-50.0,
|
||||
help="Tuning range fmin",
|
||||
type=float,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--tuning_range_fmax",
|
||||
dest="tuning_range_fmax",
|
||||
choices=[50.0, 100.0, 150.0, 200.0, 250.0],
|
||||
default=50.0,
|
||||
help="Tuning range fmax",
|
||||
type=float,
|
||||
)
|
||||
PARSER.add_argument(
|
||||
"--tx-audio-level",
|
||||
dest="tx_audio_level",
|
||||
default=50,
|
||||
help="Set the tx audio level at an early stage",
|
||||
type=int,
|
||||
)
|
||||
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
# additional step for beeing sure our callsign is correctly
|
||||
# in case we are not getting a station ssid
|
||||
# then we are forcing a station ssid = 0
|
||||
mycallsign = bytes(ARGS.mycall.upper(), 'utf-8')
|
||||
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
|
||||
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
||||
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
||||
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
|
||||
|
||||
static.SSID_LIST = ARGS.ssid_list
|
||||
|
||||
static.MYGRID = bytes(ARGS.mygrid, 'utf-8')
|
||||
static.MYGRID = bytes(ARGS.mygrid, "utf-8")
|
||||
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
||||
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
||||
static.PORT = ARGS.socket_port
|
||||
|
@ -110,20 +257,25 @@ if __name__ == '__main__':
|
|||
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
|
||||
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
|
||||
|
||||
|
||||
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
||||
import sock
|
||||
|
||||
# config logging
|
||||
try:
|
||||
if sys.platform == 'linux':
|
||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform == "linux":
|
||||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform == "darwin":
|
||||
logging_path = (
|
||||
os.getenv("HOME")
|
||||
+ "/Library/"
|
||||
+ "Application Support/"
|
||||
+ "FreeDATA/"
|
||||
+ "tnc"
|
||||
)
|
||||
|
||||
if sys.platform == 'win32' or sys.platform == 'win64':
|
||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform in ["win32", "win64"]:
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
|
||||
|
||||
if not os.path.exists(logging_path):
|
||||
os.makedirs(logging_path)
|
||||
|
@ -131,9 +283,9 @@ if __name__ == '__main__':
|
|||
except:
|
||||
structlog.get_logger("structlog").error("[DMN] logger init error")
|
||||
|
||||
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION
|
||||
)
|
||||
|
||||
# start data handler
|
||||
data_handler.DATA()
|
||||
|
@ -141,21 +293,26 @@ if __name__ == '__main__':
|
|||
# start modem
|
||||
modem = modem.RF()
|
||||
|
||||
|
||||
# --------------------------------------------START CMD SERVER
|
||||
|
||||
try:
|
||||
structlog.get_logger("structlog").info("[TNC] Starting TCP/IP socket", port=static.PORT)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[TNC] Starting TCP/IP socket", port=static.PORT
|
||||
)
|
||||
# https://stackoverflow.com/a/16641793
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
cmdserver = sock.ThreadedTCPServer((static.HOST, static.PORT), sock.ThreadedTCPRequestHandler)
|
||||
cmdserver = sock.ThreadedTCPServer(
|
||||
(static.HOST, static.PORT), sock.ThreadedTCPRequestHandler
|
||||
)
|
||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e)
|
||||
structlog.get_logger("structlog").error(
|
||||
"[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e
|
||||
)
|
||||
os._exit(1)
|
||||
while 1:
|
||||
time.sleep(1)
|
||||
|
|
490
tnc/modem.py
490
tnc/modem.py
|
@ -41,7 +41,7 @@ RECEIVE_DATAC3 = False
|
|||
RECEIVE_FSK_LDPC_1 = False
|
||||
|
||||
|
||||
class RF():
|
||||
class RF:
|
||||
""" """
|
||||
|
||||
def __init__(self):
|
||||
|
@ -49,13 +49,16 @@ class RF():
|
|||
self.sampler_avg = 0
|
||||
self.buffer_avg = 0
|
||||
|
||||
|
||||
self.AUDIO_SAMPLE_RATE_RX = 48000
|
||||
self.AUDIO_SAMPLE_RATE_TX = 48000
|
||||
self.MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000
|
||||
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_CHUNKS = 48 #8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) #48
|
||||
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_CHUNKS = (
|
||||
48 # 8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) #48
|
||||
)
|
||||
self.AUDIO_CHANNELS = 1
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# TODO: we need to change the entire modem module to integrate codec2 module
|
||||
|
@ -81,43 +86,94 @@ class RF():
|
|||
self.fft_data = bytes()
|
||||
|
||||
# open codec2 instance
|
||||
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
|
||||
self.c_lib.freedv_set_tuning_range(self.datac0_freedv, c_float(static.TUNING_RANGE_FMIN), c_float(static.TUNING_RANGE_FMAX))
|
||||
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_freedv = cast(
|
||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p
|
||||
)
|
||||
self.c_lib.freedv_set_tuning_range(
|
||||
self.datac0_freedv,
|
||||
c_float(static.TUNING_RANGE_FMIN),
|
||||
c_float(static.TUNING_RANGE_FMAX),
|
||||
)
|
||||
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)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac0_freedv,1)
|
||||
self.datac0_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
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.datac1_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p)
|
||||
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_freedv = cast(
|
||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p
|
||||
)
|
||||
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)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv,1)
|
||||
self.datac1_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
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.datac3_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p)
|
||||
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_freedv = cast(
|
||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p
|
||||
)
|
||||
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)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv,1)
|
||||
self.datac3_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
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.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)
|
||||
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_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,
|
||||
)
|
||||
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_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_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_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_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)
|
||||
|
||||
# initial nin values
|
||||
|
@ -128,7 +184,7 @@ class RF():
|
|||
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
|
||||
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
||||
|
||||
'''
|
||||
"""
|
||||
try:
|
||||
# we need to "try" this, because sometimes libasound.so isn't in the default place
|
||||
# try to supress error messages
|
||||
|
@ -151,9 +207,9 @@ class RF():
|
|||
static.AUDIO_OUTPUT_DEVICE = loopback_list[1] #1 = TX
|
||||
print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
|
||||
|
||||
'''
|
||||
"""
|
||||
try:
|
||||
'''
|
||||
"""
|
||||
self.audio_stream = self.p.open(format=audio.pyaudio.paInt16,
|
||||
channels=self.AUDIO_CHANNELS,
|
||||
rate=self.AUDIO_SAMPLE_RATE_RX,
|
||||
|
@ -164,76 +220,114 @@ class RF():
|
|||
output_device_index=static.AUDIO_OUTPUT_DEVICE,
|
||||
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)
|
||||
|
||||
structlog.get_logger("structlog").info("opened audio devices")
|
||||
|
||||
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)
|
||||
|
||||
try:
|
||||
structlog.get_logger("structlog").debug("[TNC] starting pyaudio callback")
|
||||
#self.audio_stream.start_stream()
|
||||
# self.audio_stream.start_stream()
|
||||
self.stream.start()
|
||||
|
||||
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
|
||||
# check how we want to control the radio
|
||||
if static.HAMLIB_RADIOCONTROL == 'direct':
|
||||
if static.HAMLIB_RADIOCONTROL == "direct":
|
||||
import rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'rigctl':
|
||||
elif static.HAMLIB_RADIOCONTROL == "rigctl":
|
||||
import rigctl as rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'rigctld':
|
||||
elif static.HAMLIB_RADIOCONTROL == "rigctld":
|
||||
import rigctld as rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'disabled':
|
||||
elif static.HAMLIB_RADIOCONTROL == "disabled":
|
||||
import rigdummy as rig
|
||||
else:
|
||||
import rigdummy as rig
|
||||
|
||||
|
||||
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
|
||||
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()
|
||||
|
||||
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_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_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()
|
||||
|
||||
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_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()
|
||||
|
||||
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()
|
||||
|
||||
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_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()
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
#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):
|
||||
"""
|
||||
|
||||
|
@ -255,41 +349,47 @@ class RF():
|
|||
# avoid decoding when transmitting to reduce CPU
|
||||
if not static.TRANSMITTING:
|
||||
# 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)
|
||||
else:
|
||||
static.BUFFER_OVERFLOW_COUNTER[0] += 1
|
||||
|
||||
# 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:
|
||||
self.datac1_buffer.push(x)
|
||||
else:
|
||||
static.BUFFER_OVERFLOW_COUNTER[1] += 1
|
||||
|
||||
# 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:
|
||||
self.datac3_buffer.push(x)
|
||||
else:
|
||||
static.BUFFER_OVERFLOW_COUNTER[2] += 1
|
||||
|
||||
# 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:
|
||||
self.fsk_ldpc_buffer_0.push(x)
|
||||
else:
|
||||
static.BUFFER_OVERFLOW_COUNTER[3] += 1
|
||||
|
||||
# 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:
|
||||
self.fsk_ldpc_buffer_1.push(x)
|
||||
else:
|
||||
static.BUFFER_OVERFLOW_COUNTER[4] += 1
|
||||
|
||||
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)
|
||||
self.fft_data = x
|
||||
|
||||
|
@ -302,7 +402,7 @@ class RF():
|
|||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
#return (data_out48k, audio.pyaudio.paContinue)
|
||||
# return (data_out48k, audio.pyaudio.paContinue)
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -321,77 +421,112 @@ class RF():
|
|||
static.TRANSMITTING = True
|
||||
# toggle ptt early to save some time and send ptt state via socket
|
||||
static.PTT_STATE = self.hamlib.set_ptt(True)
|
||||
jsondata = {"ptt":"True"}
|
||||
jsondata = {"ptt": "True"}
|
||||
data_out = json.dumps(jsondata)
|
||||
sock.SOCKET_QUEUE.put(data_out)
|
||||
|
||||
|
||||
# open codec2 instance
|
||||
self.MODE = mode
|
||||
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)
|
||||
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)
|
||||
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,
|
||||
)
|
||||
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:
|
||||
freedv = cast(codec2.api.freedv_open(self.MODE), c_void_p)
|
||||
|
||||
|
||||
# get number of bytes per frame for mode
|
||||
bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(freedv)/8)
|
||||
payload_bytes_per_frame = bytes_per_frame -2
|
||||
bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
payload_bytes_per_frame = bytes_per_frame - 2
|
||||
# init buffer for data
|
||||
n_tx_modem_samples = codec2.api.freedv_get_n_tx_modem_samples(freedv)
|
||||
mod_out = create_string_buffer(n_tx_modem_samples * 2)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# add empty data to handle ptt toggle time
|
||||
data_delay_mseconds = 0 #miliseconds
|
||||
data_delay = int(self.MODEM_SAMPLE_RATE*(data_delay_mseconds/1000))
|
||||
mod_out_silence = create_string_buffer(data_delay*2)
|
||||
data_delay_mseconds = 0 # miliseconds
|
||||
data_delay = int(self.MODEM_SAMPLE_RATE * (data_delay_mseconds / 1000))
|
||||
mod_out_silence = create_string_buffer(data_delay * 2)
|
||||
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
|
||||
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
|
||||
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
txbuffer += bytes(mod_out_preamble)
|
||||
# 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
|
||||
buffer = bytearray(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
|
||||
buffer = bytearray(
|
||||
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
|
||||
# crc algorithm incompatibilities
|
||||
crc = ctypes.c_ushort(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
|
||||
crc = ctypes.c_ushort(
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
|
||||
# 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
|
||||
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
txbuffer += bytes(mod_out_postamble)
|
||||
# append postamble to txbuffer
|
||||
# add delay to end of frames
|
||||
samples_delay = int(self.MODEM_SAMPLE_RATE*(repeat_delay/1000))
|
||||
mod_out_silence = create_string_buffer(samples_delay*2)
|
||||
samples_delay = int(self.MODEM_SAMPLE_RATE * (repeat_delay / 1000))
|
||||
mod_out_silence = create_string_buffer(samples_delay * 2)
|
||||
txbuffer += bytes(mod_out_silence)
|
||||
|
||||
# resample up to 48k (resampler works on np.int16)
|
||||
|
@ -404,9 +539,11 @@ class RF():
|
|||
# deaktivated for testing purposes
|
||||
self.mod_out_locked = False
|
||||
|
||||
|
||||
chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX #4800
|
||||
chunk = [txbuffer_48k[i:i+chunk_length] for i in range(0, len(txbuffer_48k), chunk_length)]
|
||||
chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX # 4800
|
||||
chunk = [
|
||||
txbuffer_48k[i : i + chunk_length]
|
||||
for i in range(0, len(txbuffer_48k), chunk_length)
|
||||
]
|
||||
for c in chunk:
|
||||
|
||||
if len(c) < chunk_length:
|
||||
|
@ -414,11 +551,9 @@ class RF():
|
|||
delta_zeros = np.zeros(delta, dtype=np.int16)
|
||||
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)
|
||||
|
||||
|
||||
|
||||
# Release our mod_out_lock so we can use the queue
|
||||
self.mod_out_locked = False
|
||||
|
||||
|
@ -428,7 +563,7 @@ class RF():
|
|||
static.PTT_STATE = self.hamlib.set_ptt(False)
|
||||
|
||||
# push ptt state to socket stream
|
||||
jsondata = {"ptt":"False"}
|
||||
jsondata = {"ptt": "False"}
|
||||
data_out = json.dumps(jsondata)
|
||||
sock.SOCKET_QUEUE.put(data_out)
|
||||
|
||||
|
@ -447,12 +582,22 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac0_buffer.nbuffer >= self.datac0_nin:
|
||||
# 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_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
||||
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.get_scatter(self.datac0_freedv)
|
||||
self.modem_received_queue.put(
|
||||
[
|
||||
self.datac0_bytes_out,
|
||||
self.datac0_freedv,
|
||||
self.datac0_bytes_per_frame,
|
||||
]
|
||||
)
|
||||
# self.get_scatter(self.datac0_freedv)
|
||||
self.calculate_snr(self.datac0_freedv)
|
||||
|
||||
def audio_datac1(self):
|
||||
|
@ -462,12 +607,22 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
||||
# 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_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||
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.get_scatter(self.datac1_freedv)
|
||||
self.modem_received_queue.put(
|
||||
[
|
||||
self.datac1_bytes_out,
|
||||
self.datac1_freedv,
|
||||
self.datac1_bytes_per_frame,
|
||||
]
|
||||
)
|
||||
# self.get_scatter(self.datac1_freedv)
|
||||
self.calculate_snr(self.datac1_freedv)
|
||||
|
||||
def audio_datac3(self):
|
||||
|
@ -477,12 +632,22 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac3_buffer.nbuffer >= self.datac3_nin:
|
||||
# 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_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||
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.get_scatter(self.datac3_freedv)
|
||||
self.modem_received_queue.put(
|
||||
[
|
||||
self.datac3_bytes_out,
|
||||
self.datac3_freedv,
|
||||
self.datac3_bytes_per_frame,
|
||||
]
|
||||
)
|
||||
# self.get_scatter(self.datac3_freedv)
|
||||
self.calculate_snr(self.datac3_freedv)
|
||||
|
||||
def audio_fsk_ldpc_0(self):
|
||||
|
@ -492,12 +657,22 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0:
|
||||
# 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_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_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.get_scatter(self.fsk_ldpc_freedv_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.get_scatter(self.fsk_ldpc_freedv_0)
|
||||
self.calculate_snr(self.fsk_ldpc_freedv_0)
|
||||
|
||||
def audio_fsk_ldpc_1(self):
|
||||
|
@ -507,26 +682,34 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1:
|
||||
# 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_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_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.get_scatter(self.fsk_ldpc_freedv_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.get_scatter(self.fsk_ldpc_freedv_1)
|
||||
self.calculate_snr(self.fsk_ldpc_freedv_1)
|
||||
|
||||
|
||||
|
||||
# worker for FIFO queue for processing received frames
|
||||
def worker_transmit(self):
|
||||
""" """
|
||||
while True:
|
||||
data = self.modem_transmit_queue.get()
|
||||
|
||||
self.transmit(mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3])
|
||||
#self.modem_transmit_queue.task_done()
|
||||
|
||||
|
||||
self.transmit(
|
||||
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
|
||||
def worker_received(self):
|
||||
|
@ -539,7 +722,6 @@ class RF():
|
|||
data_handler.DATA_QUEUE_RECEIVED.put([data[0], data[1], data[2]])
|
||||
self.modem_received_queue.task_done()
|
||||
|
||||
|
||||
def get_frequency_offset(self, freedv):
|
||||
"""
|
||||
|
||||
|
@ -556,7 +738,6 @@ class RF():
|
|||
static.FREQ_OFFSET = offset
|
||||
return offset
|
||||
|
||||
|
||||
def get_scatter(self, freedv):
|
||||
"""
|
||||
|
||||
|
@ -577,8 +758,8 @@ class RF():
|
|||
for j in range(codec2.MODEM_STATS_NR_MAX):
|
||||
# check if odd or not to get every 2nd item for x
|
||||
if (j % 2) == 0:
|
||||
xsymbols = round(modemStats.rx_symbols[i][j]/1000)
|
||||
ysymbols = round(modemStats.rx_symbols[i][j+1]/1000)
|
||||
xsymbols = round(modemStats.rx_symbols[i][j] / 1000)
|
||||
ysymbols = round(modemStats.rx_symbols[i][j + 1] / 1000)
|
||||
# check if value 0.0 or has real data
|
||||
if xsymbols != 0.0 and ysymbols != 0.0:
|
||||
scatterdata.append({"x": xsymbols, "y": ysymbols})
|
||||
|
@ -591,7 +772,6 @@ class RF():
|
|||
scatterdata_small = scatterdata[::10]
|
||||
static.SCATTER = scatterdata_small
|
||||
|
||||
|
||||
def calculate_snr(self, freedv):
|
||||
"""
|
||||
|
||||
|
@ -606,13 +786,15 @@ class RF():
|
|||
modem_stats_snr = c_float()
|
||||
modem_stats_sync = c_int()
|
||||
|
||||
self.c_lib.freedv_get_modem_stats(freedv, byref(modem_stats_sync), byref(modem_stats_snr))
|
||||
self.c_lib.freedv_get_modem_stats(
|
||||
freedv, byref(modem_stats_sync), byref(modem_stats_snr)
|
||||
)
|
||||
modem_stats_snr = modem_stats_snr.value
|
||||
modem_stats_sync = modem_stats_sync.value
|
||||
|
||||
snr = round(modem_stats_snr, 1)
|
||||
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
|
||||
except:
|
||||
static.SNR = 0
|
||||
|
@ -621,21 +803,20 @@ class RF():
|
|||
def update_rig_data(self):
|
||||
""" """
|
||||
while True:
|
||||
#time.sleep(1.5)
|
||||
# time.sleep(1.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_MODE = self.hamlib.get_mode()
|
||||
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith()
|
||||
|
||||
|
||||
def calculate_fft(self):
|
||||
""" """
|
||||
# channel_busy_delay counter
|
||||
channel_busy_delay = 0
|
||||
|
||||
while True:
|
||||
#time.sleep(0.01)
|
||||
# time.sleep(0.01)
|
||||
threading.Event().wait(0.01)
|
||||
# WE NEED TO OPTIMIZE THIS!
|
||||
|
||||
|
@ -650,26 +831,24 @@ class RF():
|
|||
|
||||
# set value 0 to 1 to avoid division by zero
|
||||
fftarray[fftarray == 0] = 1
|
||||
dfft = 10.*np.log10(abs(fftarray))
|
||||
dfft = 10.0 * np.log10(abs(fftarray))
|
||||
|
||||
# get average of dfft
|
||||
avg = np.mean(dfft)
|
||||
|
||||
|
||||
# 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
|
||||
# have to do this when we are not transmittig so our own sending data will not affect this too much
|
||||
if not static.TRANSMITTING:
|
||||
dfft[dfft>avg+10] = 100
|
||||
dfft[dfft > avg + 10] = 100
|
||||
|
||||
# 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"
|
||||
# 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
|
||||
channel_busy_delay += 5
|
||||
# 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)
|
||||
dfftlist = dfft.tolist()
|
||||
|
||||
static.FFT = dfftlist[0:320] #200 --> bandwith 3000
|
||||
static.FFT = dfftlist[0:320] # 200 --> bandwith 3000
|
||||
|
||||
except:
|
||||
|
||||
|
@ -707,10 +886,11 @@ class RF():
|
|||
Returns:
|
||||
|
||||
"""
|
||||
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.fsk_ldpc_freedv_0,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.fsk_ldpc_freedv_0, n_frames_per_burst
|
||||
)
|
||||
|
||||
|
||||
def get_bytes_per_frame(mode):
|
||||
|
@ -724,18 +904,28 @@ def get_bytes_per_frame(mode):
|
|||
|
||||
"""
|
||||
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:
|
||||
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:
|
||||
freedv = cast(codec2.api.freedv_open(mode), c_void_p)
|
||||
|
||||
# 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):
|
||||
data = np.fromstring(datalist, np.int16) * (volume / 100.)
|
||||
data = np.fromstring(datalist, np.int16) * (volume / 100.0)
|
||||
return data.astype(np.int16)
|
||||
|
||||
|
||||
|
|
162
tnc/rig.py
162
tnc/rig.py
|
@ -26,23 +26,23 @@ try:
|
|||
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
||||
|
||||
# installation path for Ubuntu 20.04 LTS python modules
|
||||
#sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
||||
# sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
||||
|
||||
# installation path for Ubuntu 20.10 +
|
||||
sys.path.append('/usr/local/lib/')
|
||||
sys.path.append("/usr/local/lib/")
|
||||
|
||||
# installation path for Suse
|
||||
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages')
|
||||
sys.path.append("/usr/local/lib64/python" + python_version + "/site-packages")
|
||||
|
||||
# everything else... not nice, but an attempt to see how its running within app bundle
|
||||
# this is not needed as python will be shipped with app bundle
|
||||
sys.path.append('/usr/local/lib/python3.6/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.7/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.8/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.9/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.10/site-packages')
|
||||
sys.path.append("/usr/local/lib/python3.6/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.7/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.8/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.9/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.10/site-packages")
|
||||
|
||||
sys.path.append('lib/hamlib/linux/python3.8/site-packages')
|
||||
sys.path.append("lib/hamlib/linux/python3.8/site-packages")
|
||||
import Hamlib
|
||||
|
||||
# https://stackoverflow.com/a/4703409
|
||||
|
@ -51,44 +51,73 @@ try:
|
|||
|
||||
min_hamlib_version = 4.1
|
||||
if hamlib_version > min_hamlib_version:
|
||||
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[RIG] Hamlib found", version=hamlib_version
|
||||
)
|
||||
else:
|
||||
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version
|
||||
)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIG] Python Hamlib binding not found", error=e
|
||||
)
|
||||
try:
|
||||
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl")
|
||||
rigctl = subprocess.Popen("rigctl -V",shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
||||
rigctl = subprocess.Popen(
|
||||
"rigctl -V",
|
||||
shell=True,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
hamlib_version = rigctl.stdout.readline()
|
||||
hamlib_version = hamlib_version.split(' ')
|
||||
hamlib_version = hamlib_version.split(" ")
|
||||
|
||||
if hamlib_version[1] == 'Hamlib':
|
||||
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
|
||||
if hamlib_version[1] == "Hamlib":
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIG] Rigctl found! Please try using this", version=hamlib_version[2]
|
||||
)
|
||||
sys.exit()
|
||||
else:
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=e)
|
||||
structlog.get_logger("structlog").critical(
|
||||
"[RIG] HAMLIB NOT INSTALLED", error=e
|
||||
)
|
||||
hamlib_version = 0
|
||||
sys.exit()
|
||||
|
||||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.devicename = ''
|
||||
self.devicenumber = ''
|
||||
self.deviceport = ''
|
||||
self.serialspeed = ''
|
||||
self.hamlib_ptt_type = ''
|
||||
self.my_rig = ''
|
||||
self.pttport = ''
|
||||
self.data_bits = ''
|
||||
self.stop_bits = ''
|
||||
self.handshake = ''
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
self.deviceport = ""
|
||||
self.serialspeed = ""
|
||||
self.hamlib_ptt_type = ""
|
||||
self.my_rig = ""
|
||||
self.pttport = ""
|
||||
self.data_bits = ""
|
||||
self.stop_bits = ""
|
||||
self.handshake = ""
|
||||
|
||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip):
|
||||
def open_rig(
|
||||
self,
|
||||
devicename,
|
||||
deviceport,
|
||||
hamlib_ptt_type,
|
||||
serialspeed,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
rigctld_port,
|
||||
rigctld_ip,
|
||||
):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
@ -109,14 +138,15 @@ class radio:
|
|||
|
||||
self.devicename = devicename
|
||||
self.deviceport = str(deviceport)
|
||||
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||
self.serialspeed = str(
|
||||
serialspeed
|
||||
) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||
self.hamlib_ptt_type = str(hamlib_ptt_type)
|
||||
self.pttport = str(pttport)
|
||||
self.data_bits = str(data_bits)
|
||||
self.stop_bits = str(stop_bits)
|
||||
self.handshake = str(handshake)
|
||||
|
||||
|
||||
# try to init hamlib
|
||||
try:
|
||||
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
|
||||
|
@ -125,10 +155,11 @@ class radio:
|
|||
try:
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
|
||||
structlog.get_logger("structlog").error(
|
||||
"[RIG] Hamlib: rig not supported..."
|
||||
)
|
||||
self.devicenumber = 0
|
||||
|
||||
|
||||
self.my_rig = Hamlib.Rig(self.devicenumber)
|
||||
self.my_rig.set_conf("rig_pathname", self.deviceport)
|
||||
self.my_rig.set_conf("retry", "5")
|
||||
|
@ -138,50 +169,54 @@ class radio:
|
|||
self.my_rig.set_conf("data_bits", self.data_bits)
|
||||
self.my_rig.set_conf("ptt_pathname", self.pttport)
|
||||
|
||||
|
||||
|
||||
|
||||
if self.hamlib_ptt_type == 'RIG':
|
||||
if self.hamlib_ptt_type == "RIG":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
||||
self.my_rig.set_conf("ptt_type", 'RIG')
|
||||
self.my_rig.set_conf("ptt_type", "RIG")
|
||||
|
||||
elif self.hamlib_ptt_type == 'USB':
|
||||
elif self.hamlib_ptt_type == "USB":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
|
||||
self.my_rig.set_conf("ptt_type", 'USB')
|
||||
self.my_rig.set_conf("ptt_type", "USB")
|
||||
|
||||
|
||||
elif self.hamlib_ptt_type == 'DTR-H':
|
||||
elif self.hamlib_ptt_type == "DTR-H":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "HIGH")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
elif self.hamlib_ptt_type == 'DTR-L':
|
||||
elif self.hamlib_ptt_type == "DTR-L":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "LOW")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
elif self.hamlib_ptt_type == 'RTS':
|
||||
elif self.hamlib_ptt_type == "RTS":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
||||
self.my_rig.set_conf("dtr_state", "OFF")
|
||||
self.my_rig.set_conf("ptt_type", "RTS")
|
||||
|
||||
elif self.hamlib_ptt_type == 'PARALLEL':
|
||||
elif self.hamlib_ptt_type == "PARALLEL":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
||||
|
||||
elif self.hamlib_ptt_type == 'MICDATA':
|
||||
elif self.hamlib_ptt_type == "MICDATA":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
||||
|
||||
elif self.hamlib_ptt_type == 'CM108':
|
||||
elif self.hamlib_ptt_type == "CM108":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
||||
|
||||
elif self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
||||
elif self.hamlib_ptt_type == "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
|
||||
|
||||
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()
|
||||
atexit.register(self.my_rig.close)
|
||||
|
@ -189,28 +224,35 @@ class radio:
|
|||
try:
|
||||
# lets determine the error message when opening rig
|
||||
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
|
||||
error = error[1].split('err=')
|
||||
error = error[1].split("err=")
|
||||
error = error[1]
|
||||
|
||||
if error == 'Permission denied':
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error)
|
||||
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions'
|
||||
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url)
|
||||
if error == "Permission denied":
|
||||
structlog.get_logger("structlog").error(
|
||||
"[RIG] Hamlib has no permissions", e=error
|
||||
)
|
||||
help_url = "https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions"
|
||||
structlog.get_logger("structlog").error(
|
||||
"[RIG] HELP:", check=help_url
|
||||
)
|
||||
except:
|
||||
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS')
|
||||
|
||||
structlog.get_logger("structlog").info(
|
||||
"[RIG] Hamlib device opened", status="SUCCESS"
|
||||
)
|
||||
|
||||
# set ptt to false if ptt is stuck for some reason
|
||||
self.set_ptt(False)
|
||||
|
||||
# set rig mode to USB
|
||||
# temporarly outcommented because of possible problems.
|
||||
#self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
||||
# self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
||||
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0])
|
||||
structlog.get_logger("structlog").error(
|
||||
"[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0]
|
||||
)
|
||||
return False
|
||||
|
||||
def get_frequency(self):
|
||||
|
@ -228,7 +270,7 @@ class radio:
|
|||
return bandwith
|
||||
|
||||
# not needed yet beacuse of some possible problems
|
||||
#def set_mode(self, mode):
|
||||
# def set_mode(self, mode):
|
||||
# return 0
|
||||
|
||||
def get_ptt(self):
|
||||
|
|
106
tnc/rigctl.py
106
tnc/rigctl.py
|
@ -13,27 +13,42 @@ import structlog
|
|||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
# for rig_model -> rig_number only
|
||||
|
||||
# set global hamlib version
|
||||
hamlib_version = 0
|
||||
|
||||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.devicename = ''
|
||||
self.devicenumber = ''
|
||||
self.deviceport = ''
|
||||
self.serialspeed = ''
|
||||
self.hamlib_ptt_type = ''
|
||||
self.my_rig = ''
|
||||
self.pttport = ''
|
||||
self.data_bits = ''
|
||||
self.stop_bits = ''
|
||||
self.handshake = ''
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
self.deviceport = ""
|
||||
self.serialspeed = ""
|
||||
self.hamlib_ptt_type = ""
|
||||
self.my_rig = ""
|
||||
self.pttport = ""
|
||||
self.data_bits = ""
|
||||
self.stop_bits = ""
|
||||
self.handshake = ""
|
||||
|
||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
|
||||
def open_rig(
|
||||
self,
|
||||
devicename,
|
||||
deviceport,
|
||||
hamlib_ptt_type,
|
||||
serialspeed,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
@ -54,14 +69,15 @@ class radio:
|
|||
|
||||
self.devicename = devicename
|
||||
self.deviceport = deviceport
|
||||
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||
self.serialspeed = str(
|
||||
serialspeed
|
||||
) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||
self.hamlib_ptt_type = hamlib_ptt_type
|
||||
self.pttport = pttport
|
||||
self.data_bits = data_bits
|
||||
self.stop_bits = stop_bits
|
||||
self.handshake = handshake
|
||||
|
||||
|
||||
# check if we are running in a pyinstaller environment
|
||||
try:
|
||||
app_path = sys._MEIPASS
|
||||
|
@ -72,30 +88,40 @@ class radio:
|
|||
# get devicenumber by looking for deviceobject in Hamlib module
|
||||
try:
|
||||
import Hamlib
|
||||
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except:
|
||||
if int(self.devicename):
|
||||
self.devicenumber = int(self.devicename)
|
||||
else:
|
||||
self.devicenumber = 6 #dummy
|
||||
structlog.get_logger("structlog").warning("[RIGCTL] RADIO NOT FOUND USING DUMMY!", error=e)
|
||||
self.devicenumber = 6 # dummy
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIGCTL] RADIO NOT FOUND USING DUMMY!", error=e
|
||||
)
|
||||
|
||||
# set deviceport to dummy port, if we selected dummy model
|
||||
if self.devicenumber == 1 or self.devicenumber == 6:
|
||||
self.deviceport = '/dev/ttyUSB0'
|
||||
self.deviceport = "/dev/ttyUSB0"
|
||||
|
||||
print(self.devicenumber, self.deviceport, self.serialspeed)
|
||||
|
||||
|
||||
|
||||
|
||||
# select precompiled executable for win32/win64 rigctl
|
||||
# this is really a hack...somewhen we need a native hamlib integration for windows
|
||||
if sys.platform == 'win32' or sys.platform == 'win64':
|
||||
self.cmd = app_path + 'lib\\hamlib\\'+sys.platform+'\\rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
||||
if sys.platform == "win32" or sys.platform == "win64":
|
||||
self.cmd = (
|
||||
app_path
|
||||
+ "lib\\hamlib\\"
|
||||
+ sys.platform
|
||||
+ "\\rigctl -m %d -r %s -s %d "
|
||||
% (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
||||
)
|
||||
|
||||
else:
|
||||
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
||||
self.cmd = "rigctl -m %d -r %s -s %d " % (
|
||||
int(self.devicenumber),
|
||||
self.deviceport,
|
||||
int(self.serialspeed),
|
||||
)
|
||||
|
||||
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
|
||||
# il set e t per il get
|
||||
|
@ -106,30 +132,30 @@ class radio:
|
|||
|
||||
def get_frequency(self):
|
||||
""" """
|
||||
cmd = self.cmd + ' f'
|
||||
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
||||
cmd = self.cmd + " f"
|
||||
sw_proc = subprocess.Popen(
|
||||
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
|
||||
)
|
||||
time.sleep(0.5)
|
||||
freq = sw_proc.communicate()[0]
|
||||
#print('get_frequency', freq, sw_proc.communicate())
|
||||
# print('get_frequency', freq, sw_proc.communicate())
|
||||
try:
|
||||
return int(freq)
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def get_mode(self):
|
||||
""" """
|
||||
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
#return Hamlib.rig_strrmode(hamlib_mode)
|
||||
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
# return Hamlib.rig_strrmode(hamlib_mode)
|
||||
try:
|
||||
return 'PKTUSB'
|
||||
return "PKTUSB"
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def get_bandwith(self):
|
||||
""" """
|
||||
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
bandwith = 2700
|
||||
|
||||
try:
|
||||
|
@ -151,8 +177,10 @@ class radio:
|
|||
|
||||
def get_ptt(self):
|
||||
""" """
|
||||
cmd = self.cmd + ' t'
|
||||
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
||||
cmd = self.cmd + " t"
|
||||
sw_proc = subprocess.Popen(
|
||||
cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True
|
||||
)
|
||||
time.sleep(0.5)
|
||||
status = sw_proc.communicate()[0]
|
||||
|
||||
|
@ -170,13 +198,13 @@ class radio:
|
|||
Returns:
|
||||
|
||||
"""
|
||||
cmd = self.cmd + ' T '
|
||||
print('set_ptt', state)
|
||||
cmd = self.cmd + " T "
|
||||
print("set_ptt", state)
|
||||
if state:
|
||||
cmd = cmd + '1'
|
||||
cmd = cmd + "1"
|
||||
else:
|
||||
cmd = cmd + '0'
|
||||
print('set_ptt', cmd)
|
||||
cmd = cmd + "0"
|
||||
print("set_ptt", cmd)
|
||||
|
||||
sw_proc = subprocess.Popen(cmd, shell=True, text=True)
|
||||
try:
|
||||
|
@ -186,5 +214,5 @@ class radio:
|
|||
|
||||
def close_rig(self):
|
||||
""" """
|
||||
#self.my_rig.close()
|
||||
# self.my_rig.close()
|
||||
return
|
||||
|
|
|
@ -5,6 +5,7 @@ import log_handler
|
|||
import logging
|
||||
import time
|
||||
import static
|
||||
|
||||
# class taken from darsidelemm
|
||||
# rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35
|
||||
#
|
||||
|
@ -13,21 +14,35 @@ import static
|
|||
# set global hamlib version
|
||||
hamlib_version = 0
|
||||
|
||||
class radio():
|
||||
|
||||
class radio:
|
||||
"""rotctld (hamlib) communication class"""
|
||||
|
||||
# Note: This is a massive hack.
|
||||
|
||||
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
||||
""" Open a connection to rotctld, and test it for validity """
|
||||
"""Open a connection to rotctld, and test it for validity"""
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
#self.sock.settimeout(timeout)
|
||||
# self.sock.settimeout(timeout)
|
||||
|
||||
self.connected = False
|
||||
self.hostname = hostname
|
||||
self.port = port
|
||||
self.connection_attempts = 5
|
||||
|
||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
|
||||
def open_rig(
|
||||
self,
|
||||
devicename,
|
||||
deviceport,
|
||||
hamlib_ptt_type,
|
||||
serialspeed,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
@ -48,26 +63,34 @@ class radio():
|
|||
self.hostname = rigctld_ip
|
||||
self.port = int(rigctld_port)
|
||||
|
||||
|
||||
if self.connect():
|
||||
logging.debug(f"Rigctl intialized")
|
||||
return True
|
||||
else:
|
||||
structlog.get_logger("structlog").error("[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port)
|
||||
structlog.get_logger("structlog").error(
|
||||
"[RIGCTLD] Can't connect to rigctld!", ip=self.hostname, port=self.port
|
||||
)
|
||||
return False
|
||||
|
||||
def connect(self):
|
||||
"""Connect to rigctld instance"""
|
||||
if not self.connected:
|
||||
try:
|
||||
self.connection = socket.create_connection((self.hostname,self.port))
|
||||
self.connection = socket.create_connection((self.hostname, self.port))
|
||||
self.connected = True
|
||||
structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
# ConnectionRefusedError: [Errno 111] Connection refused
|
||||
self.close_rig()
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=e)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIGCTLD] Connection to rigctld refused! Reconnect...",
|
||||
ip=self.hostname,
|
||||
port=self.port,
|
||||
e=e,
|
||||
)
|
||||
return False
|
||||
|
||||
def close_rig(self):
|
||||
|
@ -75,7 +98,6 @@ class radio():
|
|||
self.sock.close()
|
||||
self.connected = False
|
||||
|
||||
|
||||
def send_command(self, command):
|
||||
"""Send a command to the connected rotctld instance,
|
||||
and return the return value.
|
||||
|
@ -88,15 +110,25 @@ class radio():
|
|||
"""
|
||||
if self.connected:
|
||||
try:
|
||||
self.connection.sendall(command+b'\n')
|
||||
self.connection.sendall(command + b"\n")
|
||||
except:
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIGCTLD] Command not executed!",
|
||||
command=command,
|
||||
ip=self.hostname,
|
||||
port=self.port,
|
||||
)
|
||||
self.connected = False
|
||||
|
||||
try:
|
||||
return self.connection.recv(1024)
|
||||
except:
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[RIGCTLD] No command response!",
|
||||
command=command,
|
||||
ip=self.hostname,
|
||||
port=self.port,
|
||||
)
|
||||
self.connected = False
|
||||
else:
|
||||
|
||||
|
@ -104,21 +136,21 @@ class radio():
|
|||
time.sleep(0.5)
|
||||
self.connect()
|
||||
|
||||
|
||||
def get_mode(self):
|
||||
""" """
|
||||
try:
|
||||
data = self.send_command(b"m")
|
||||
data = data.split(b'\n')
|
||||
data = data.split(b"\n")
|
||||
mode = data[0]
|
||||
return mode.decode("utf-8")
|
||||
except:
|
||||
0
|
||||
|
||||
def get_bandwith(self):
|
||||
""" """
|
||||
try:
|
||||
data = self.send_command(b"m")
|
||||
data = data.split(b'\n')
|
||||
data = data.split(b"\n")
|
||||
bandwith = data[1]
|
||||
return bandwith.decode("utf-8")
|
||||
except:
|
||||
|
|
|
@ -4,12 +4,13 @@ import structlog
|
|||
|
||||
hamlib_version = 0
|
||||
|
||||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def open_rig(self, **kwargs):
|
||||
"""
|
||||
|
||||
|
@ -62,4 +63,3 @@ class radio:
|
|||
def close_rig(self):
|
||||
""" """
|
||||
return
|
||||
|
||||
|
|
385
tnc/sock.py
385
tnc/sock.py
|
@ -42,29 +42,24 @@ CONNECTED_CLIENTS = set()
|
|||
CLOSE_SIGNAL = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
"""
|
||||
the socket handler base class
|
||||
"""
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||
""" """
|
||||
|
||||
|
||||
def send_to_client(self):
|
||||
"""
|
||||
function called by socket handler
|
||||
send data to a network client if available
|
||||
|
||||
"""
|
||||
tempdata = b''
|
||||
tempdata = b""
|
||||
while self.connection_alive and not CLOSE_SIGNAL:
|
||||
|
||||
# send tnc state as network stream
|
||||
|
@ -82,14 +77,13 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
SOCKET_QUEUE.put(data)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
while not SOCKET_QUEUE.empty():
|
||||
data = SOCKET_QUEUE.get()
|
||||
sock_data = bytes(data, 'utf-8')
|
||||
sock_data += b'\n' # append line limiter
|
||||
sock_data = bytes(data, "utf-8")
|
||||
sock_data += b"\n" # append line limiter
|
||||
|
||||
# send data to all clients
|
||||
#try:
|
||||
# try:
|
||||
for client in CONNECTED_CLIENTS:
|
||||
try:
|
||||
client.send(sock_data)
|
||||
|
@ -102,7 +96,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
static.SCATTER = []
|
||||
# we want to display INFO messages only once
|
||||
static.INFO = []
|
||||
#self.request.sendall(sock_data)
|
||||
# self.request.sendall(sock_data)
|
||||
time.sleep(0.15)
|
||||
|
||||
def receive_from_client(self):
|
||||
|
@ -116,16 +110,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
chunk = self.request.recv(1024)
|
||||
data += chunk
|
||||
|
||||
if chunk == b'':
|
||||
#print("connection broken. Closing...")
|
||||
if chunk == b"":
|
||||
# print("connection broken. Closing...")
|
||||
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
|
||||
data = data.split(b'\n')
|
||||
data = data.split(b"\n")
|
||||
# remove empty data
|
||||
data.remove(b'')
|
||||
data.remove(b"")
|
||||
|
||||
# iterate thorugh data list
|
||||
for commands in data:
|
||||
|
@ -141,14 +134,17 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
# and which one can be processed during a running transmission
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
# finally delete our rx buffer to be ready for new commands
|
||||
data = bytes()
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[SCK] Connection closed",
|
||||
ip=self.client_address[0],
|
||||
port=self.client_address[1],
|
||||
e=e,
|
||||
)
|
||||
self.connection_alive = False
|
||||
|
||||
|
||||
def handle(self):
|
||||
"""
|
||||
socket handler
|
||||
|
@ -156,25 +152,38 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
CONNECTED_CLIENTS.add(self.request)
|
||||
|
||||
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1])
|
||||
structlog.get_logger("structlog").debug(
|
||||
"[SCK] Client connected",
|
||||
ip=self.client_address[0],
|
||||
port=self.client_address[1],
|
||||
)
|
||||
self.connection_alive = True
|
||||
|
||||
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start()
|
||||
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start()
|
||||
self.sendThread = threading.Thread(
|
||||
target=self.send_to_client, args=[], daemon=True
|
||||
).start()
|
||||
self.receiveThread = threading.Thread(
|
||||
target=self.receive_from_client, args=[], daemon=True
|
||||
).start()
|
||||
|
||||
# keep connection alive until we close it
|
||||
while self.connection_alive and not CLOSE_SIGNAL:
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
|
||||
def finish(self):
|
||||
""" """
|
||||
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1])
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] Closing client socket",
|
||||
ip=self.client_address[0],
|
||||
port=self.client_address[1],
|
||||
)
|
||||
try:
|
||||
CONNECTED_CLIENTS.remove(self.request)
|
||||
except:
|
||||
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] client connection already removed from client list",
|
||||
client=self.request,
|
||||
)
|
||||
|
||||
|
||||
def process_tnc_commands(data):
|
||||
|
@ -194,58 +203,73 @@ def process_tnc_commands(data):
|
|||
received_json = json.loads(data)
|
||||
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
|
||||
# SET TX AUDIO LEVEL -----------------------------------------------------
|
||||
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level":
|
||||
if (
|
||||
received_json["type"] == "set"
|
||||
and received_json["command"] == "tx_audio_level"
|
||||
):
|
||||
try:
|
||||
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
||||
command_response("tx_audio_level", True)
|
||||
|
||||
except Exception as e:
|
||||
command_response("tx_audio_level", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# TRANSMIT SINE WAVE -----------------------------------------------------
|
||||
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
|
||||
if (
|
||||
received_json["type"] == "set"
|
||||
and received_json["command"] == "send_test_frame"
|
||||
):
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
||||
command_response("send_test_frame", True)
|
||||
except Exception as e:
|
||||
command_response("send_test_frame", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# CQ CQ CQ -----------------------------------------------------
|
||||
if received_json["command"] == "cqcqcq":
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
|
||||
command_response("cqcqcq", True)
|
||||
|
||||
except Exception as e:
|
||||
command_response("cqcqcq", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
# START_BEACON -----------------------------------------------------
|
||||
if received_json["command"] == "start_beacon":
|
||||
try:
|
||||
static.BEACON_STATE = True
|
||||
interval = int(received_json["parameter"])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
||||
command_response("start_beacon", True)
|
||||
except Exception as e:
|
||||
command_response("start_beacon", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# STOP_BEACON -----------------------------------------------------
|
||||
if received_json["command"] == "stop_beacon":
|
||||
try:
|
||||
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
|
||||
static.BEACON_STATE = False
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
||||
command_response("stop_beacon", True)
|
||||
except Exception as e:
|
||||
command_response("stop_beacon", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# PING ----------------------------------------------------------
|
||||
if received_json["type"] == 'ping' and received_json["command"] == "ping":
|
||||
if received_json["type"] == "ping" and received_json["command"] == "ping":
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
dxcallsign = received_json["dxcallsign"]
|
||||
|
@ -256,15 +280,16 @@ def process_tnc_commands(data):
|
|||
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["PING", dxcallsign])
|
||||
command_response("ping", True)
|
||||
except Exception as e:
|
||||
command_response("ping", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# CONNECT ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "connect":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "connect":
|
||||
static.BEACON_PAUSE = True
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
|
@ -279,24 +304,28 @@ def process_tnc_commands(data):
|
|||
static.DXCALLSIGN = dxcallsign
|
||||
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['CONNECT', dxcallsign])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["CONNECT", dxcallsign])
|
||||
command_response("connect", True)
|
||||
except Exception as e:
|
||||
command_response("connect", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# DISCONNECT ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "disconnect":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "disconnect":
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
||||
command_response("disconnect", True)
|
||||
except Exception as e:
|
||||
command_response("disconnect", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# TRANSMIT RAW DATA -------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "send_raw":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "send_raw":
|
||||
|
||||
static.BEACON_PAUSE = True
|
||||
try:
|
||||
|
@ -314,7 +343,6 @@ def process_tnc_commands(data):
|
|||
dxcallsign = static.DXCALLSIGN
|
||||
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
|
||||
|
||||
|
||||
mode = int(received_json["parameter"][0]["mode"])
|
||||
n_frames = int(received_json["parameter"][0]["n_frames"])
|
||||
base64data = received_json["parameter"][0]["data"]
|
||||
|
@ -329,36 +357,44 @@ def process_tnc_commands(data):
|
|||
try:
|
||||
arq_uuid = received_json["uuid"]
|
||||
except:
|
||||
arq_uuid = 'no-uuid'
|
||||
arq_uuid = "no-uuid"
|
||||
|
||||
if not len(base64data) % 4:
|
||||
binarydata = base64.b64decode(base64data)
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', binarydata, mode, n_frames, arq_uuid, mycallsign])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(
|
||||
["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign]
|
||||
)
|
||||
|
||||
else:
|
||||
raise TypeError
|
||||
except Exception as e:
|
||||
command_response("send_raw", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# STOP TRANSMISSION ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission":
|
||||
if (
|
||||
received_json["type"] == "arq"
|
||||
and received_json["command"] == "stop_transmission"
|
||||
):
|
||||
try:
|
||||
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP'])
|
||||
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
|
||||
static.TNC_STATE = 'IDLE'
|
||||
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[TNC] Stopping transmission!"
|
||||
)
|
||||
static.TNC_STATE = "IDLE"
|
||||
static.ARQ_STATE = False
|
||||
command_response("stop_transmission", True)
|
||||
except Exception as e:
|
||||
command_response("stop_transmission", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
|
||||
if received_json["type"] == 'get' and received_json["command"] == 'rx_buffer':
|
||||
if received_json["type"] == "get" and received_json["command"] == "rx_buffer":
|
||||
try:
|
||||
output = {
|
||||
"command": "rx_buffer",
|
||||
|
@ -366,39 +402,54 @@ def process_tnc_commands(data):
|
|||
}
|
||||
|
||||
for i in range(0, len(static.RX_BUFFER)):
|
||||
#print(static.RX_BUFFER[i][4])
|
||||
#rawdata = json.loads(static.RX_BUFFER[i][4])
|
||||
# print(static.RX_BUFFER[i][4])
|
||||
# rawdata = json.loads(static.RX_BUFFER[i][4])
|
||||
base64_data = static.RX_BUFFER[i][4]
|
||||
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data})
|
||||
output["data-array"].append(
|
||||
{
|
||||
"uuid": static.RX_BUFFER[i][0],
|
||||
"timestamp": static.RX_BUFFER[i][1],
|
||||
"dxcallsign": str(static.RX_BUFFER[i][2], "utf-8"),
|
||||
"dxgrid": str(static.RX_BUFFER[i][3], "utf-8"),
|
||||
"data": base64_data,
|
||||
}
|
||||
)
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
#self.request.sendall(bytes(jsondata, encoding))
|
||||
# self.request.sendall(bytes(jsondata, encoding))
|
||||
SOCKET_QUEUE.put(jsondata)
|
||||
command_response("rx_buffer", True)
|
||||
|
||||
except Exception as e:
|
||||
command_response("rx_buffer", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
|
||||
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer':
|
||||
if (
|
||||
received_json["type"] == "set"
|
||||
and received_json["command"] == "del_rx_buffer"
|
||||
):
|
||||
try:
|
||||
static.RX_BUFFER = []
|
||||
command_response("del_rx_buffer", True)
|
||||
except Exception as e:
|
||||
command_response("del_rx_buffer", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
# exception, if JSON cant be decoded
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
|
||||
|
||||
|
||||
def send_tnc_state():
|
||||
"""
|
||||
send the tnc state to network
|
||||
"""
|
||||
|
||||
encoding = 'utf-8'
|
||||
encoding = "utf-8"
|
||||
|
||||
output = {
|
||||
"command": "tnc_state",
|
||||
|
@ -423,8 +474,8 @@ def send_tnc_state():
|
|||
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
|
||||
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
|
||||
"total_bytes": str(static.TOTAL_BYTES),
|
||||
"info" : static.INFO,
|
||||
"beacon_state" : str(static.BEACON_STATE),
|
||||
"info": static.INFO,
|
||||
"beacon_state": str(static.BEACON_STATE),
|
||||
"stations": [],
|
||||
"mycallsign": str(static.MYCALLSIGN, encoding),
|
||||
"dxcallsign": str(static.DXCALLSIGN, encoding),
|
||||
|
@ -433,7 +484,17 @@ def send_tnc_state():
|
|||
|
||||
# add heard stations to heard stations object
|
||||
for i in range(0, len(static.HEARD_STATIONS)):
|
||||
output["stations"].append({"dxcallsign": str(static.HEARD_STATIONS[i][0], 'utf-8'), "dxgrid": str(static.HEARD_STATIONS[i][1], 'utf-8'),"timestamp": static.HEARD_STATIONS[i][2], "datatype": static.HEARD_STATIONS[i][3], "snr": static.HEARD_STATIONS[i][4], "offset": static.HEARD_STATIONS[i][5], "frequency": static.HEARD_STATIONS[i][6]})
|
||||
output["stations"].append(
|
||||
{
|
||||
"dxcallsign": str(static.HEARD_STATIONS[i][0], "utf-8"),
|
||||
"dxgrid": str(static.HEARD_STATIONS[i][1], "utf-8"),
|
||||
"timestamp": static.HEARD_STATIONS[i][2],
|
||||
"datatype": static.HEARD_STATIONS[i][3],
|
||||
"snr": static.HEARD_STATIONS[i][4],
|
||||
"offset": static.HEARD_STATIONS[i][5],
|
||||
"frequency": static.HEARD_STATIONS[i][6],
|
||||
}
|
||||
)
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
return jsondata
|
||||
|
@ -452,40 +513,56 @@ def process_daemon_commands(data):
|
|||
# convert data to json object
|
||||
received_json = json.loads(data)
|
||||
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
|
||||
if received_json["type"] == 'set' and received_json["command"] == 'mycallsign':
|
||||
if received_json["type"] == "set" and received_json["command"] == "mycallsign":
|
||||
try:
|
||||
callsign = received_json["parameter"]
|
||||
|
||||
if bytes(callsign, 'utf-8') == b'':
|
||||
self.request.sendall(b'INVALID CALLSIGN')
|
||||
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
||||
if bytes(callsign, "utf-8") == b"":
|
||||
self.request.sendall(b"INVALID CALLSIGN")
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[DMN] SET MYCALL FAILED",
|
||||
call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC,
|
||||
)
|
||||
else:
|
||||
static.MYCALLSIGN = bytes(callsign, 'utf-8')
|
||||
static.MYCALLSIGN = bytes(callsign, "utf-8")
|
||||
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
|
||||
|
||||
command_response("mycallsign", True)
|
||||
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
||||
structlog.get_logger("structlog").info(
|
||||
"[DMN] SET MYCALL",
|
||||
call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC,
|
||||
)
|
||||
except Exception as e:
|
||||
command_response("mycallsign", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
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:
|
||||
mygrid = received_json["parameter"]
|
||||
|
||||
if bytes(mygrid, 'utf-8') == b'':
|
||||
self.request.sendall(b'INVALID GRID')
|
||||
if bytes(mygrid, "utf-8") == b"":
|
||||
self.request.sendall(b"INVALID GRID")
|
||||
else:
|
||||
static.MYGRID = bytes(mygrid, 'utf-8')
|
||||
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID)
|
||||
static.MYGRID = bytes(mygrid, "utf-8")
|
||||
structlog.get_logger("structlog").info(
|
||||
"[SCK] SET MYGRID", grid=static.MYGRID
|
||||
)
|
||||
command_response("mygrid", True)
|
||||
except Exception as e:
|
||||
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 received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED:
|
||||
if (
|
||||
received_json["type"] == "set"
|
||||
and received_json["command"] == "start_tnc"
|
||||
and not static.TNCSTARTED
|
||||
):
|
||||
|
||||
try:
|
||||
mycall = str(received_json["parameter"][0]["mycall"])
|
||||
|
@ -513,39 +590,47 @@ def process_daemon_commands(data):
|
|||
|
||||
# print some debugging parameters
|
||||
for item in received_json["parameter"][0]:
|
||||
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item])
|
||||
structlog.get_logger("structlog").debug(
|
||||
"[DMN] TNC Startup Config : " + item,
|
||||
value=received_json["parameter"][0][item],
|
||||
)
|
||||
|
||||
DAEMON_QUEUE.put(['STARTTNC', \
|
||||
mycall, \
|
||||
mygrid, \
|
||||
rx_audio, \
|
||||
tx_audio, \
|
||||
devicename, \
|
||||
deviceport, \
|
||||
serialspeed, \
|
||||
pttprotocol, \
|
||||
pttport, \
|
||||
data_bits, \
|
||||
stop_bits, \
|
||||
handshake, \
|
||||
radiocontrol, \
|
||||
rigctld_ip, \
|
||||
rigctld_port, \
|
||||
enable_scatter, \
|
||||
enable_fft, \
|
||||
low_bandwith_mode, \
|
||||
tuning_range_fmin, \
|
||||
tuning_range_fmax, \
|
||||
enable_fsk, \
|
||||
tx_audio_level \
|
||||
])
|
||||
DAEMON_QUEUE.put(
|
||||
[
|
||||
"STARTTNC",
|
||||
mycall,
|
||||
mygrid,
|
||||
rx_audio,
|
||||
tx_audio,
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
enable_scatter,
|
||||
enable_fft,
|
||||
low_bandwith_mode,
|
||||
tuning_range_fmin,
|
||||
tuning_range_fmax,
|
||||
enable_fsk,
|
||||
tx_audio_level,
|
||||
]
|
||||
)
|
||||
command_response("start_tnc", True)
|
||||
|
||||
except Exception as e:
|
||||
command_response("start_tnc", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
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:
|
||||
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_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||
|
||||
DAEMON_QUEUE.put(['TEST_HAMLIB', \
|
||||
devicename, \
|
||||
deviceport, \
|
||||
serialspeed, \
|
||||
pttprotocol, \
|
||||
pttport, \
|
||||
data_bits, \
|
||||
stop_bits, \
|
||||
handshake, \
|
||||
radiocontrol, \
|
||||
rigctld_ip, \
|
||||
rigctld_port \
|
||||
])
|
||||
DAEMON_QUEUE.put(
|
||||
[
|
||||
"TEST_HAMLIB",
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
pttprotocol,
|
||||
pttport,
|
||||
data_bits,
|
||||
stop_bits,
|
||||
handshake,
|
||||
radiocontrol,
|
||||
rigctld_ip,
|
||||
rigctld_port,
|
||||
]
|
||||
)
|
||||
command_response("test_hamlib", True)
|
||||
except Exception as e:
|
||||
command_response("test_hamlib", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
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:
|
||||
static.TNCPROCESS.kill()
|
||||
# unregister process from atexit to avoid process zombies
|
||||
|
@ -589,7 +679,10 @@ def process_daemon_commands(data):
|
|||
command_response("stop_tnc", True)
|
||||
except Exception as e:
|
||||
command_response("stop_tnc", False)
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
structlog.get_logger("structlog").warning(
|
||||
"[SCK] command execution error", e=e, command=received_json
|
||||
)
|
||||
|
||||
|
||||
def send_daemon_state():
|
||||
"""
|
||||
|
@ -599,16 +692,16 @@ def send_daemon_state():
|
|||
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
||||
|
||||
output = {
|
||||
'command': 'daemon_state',
|
||||
'daemon_state': [],
|
||||
'python_version': str(python_version),
|
||||
'hamlib_version': static.HAMLIB_VERSION,
|
||||
'input_devices': static.AUDIO_INPUT_DEVICES,
|
||||
'output_devices': static.AUDIO_OUTPUT_DEVICES,
|
||||
'serial_devices': static.SERIAL_DEVICES,
|
||||
"command": "daemon_state",
|
||||
"daemon_state": [],
|
||||
"python_version": str(python_version),
|
||||
"hamlib_version": static.HAMLIB_VERSION,
|
||||
"input_devices": static.AUDIO_INPUT_DEVICES,
|
||||
"output_devices": static.AUDIO_OUTPUT_DEVICES,
|
||||
"serial_devices": static.SERIAL_DEVICES,
|
||||
#'cpu': str(psutil.cpu_percent()),
|
||||
#'ram': str(psutil.virtual_memory().percent),
|
||||
'version': '0.1'
|
||||
"version": "0.1",
|
||||
}
|
||||
|
||||
if static.TNCSTARTED:
|
||||
|
@ -616,7 +709,6 @@ def send_daemon_state():
|
|||
else:
|
||||
output["daemon_state"].append({"status": "stopped"})
|
||||
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
|
||||
return jsondata
|
||||
|
@ -624,12 +716,13 @@ def send_daemon_state():
|
|||
structlog.get_logger("structlog").warning("[SCK] error", e=e)
|
||||
return None
|
||||
|
||||
|
||||
def command_response(command, status):
|
||||
if status:
|
||||
status = "OK"
|
||||
else:
|
||||
status = "Failed"
|
||||
|
||||
jsondata = {"command_response": command, "status" : status}
|
||||
jsondata = {"command_response": command, "status": status}
|
||||
data_out = json.dumps(jsondata)
|
||||
SOCKET_QUEUE.put(data_out)
|
||||
|
|
|
@ -8,7 +8,7 @@ Here we are saving application wide variables and stats, which have to be access
|
|||
Not nice, suggestions are appreciated :-)
|
||||
"""
|
||||
|
||||
VERSION = '0.3.3-alpha'
|
||||
VERSION = "0.3.3-alpha"
|
||||
|
||||
# DAEMON
|
||||
DAEMONPORT = 3001
|
||||
|
@ -17,14 +17,14 @@ TNCPROCESS = 0
|
|||
|
||||
|
||||
# Operator Defaults
|
||||
MYCALLSIGN = b'AA0AA'
|
||||
MYCALLSIGN_CRC = b'A'
|
||||
MYCALLSIGN = b"AA0AA"
|
||||
MYCALLSIGN_CRC = b"A"
|
||||
|
||||
DXCALLSIGN = b'AA0AA'
|
||||
DXCALLSIGN_CRC = b'A'
|
||||
DXCALLSIGN = b"AA0AA"
|
||||
DXCALLSIGN_CRC = b"A"
|
||||
|
||||
MYGRID = b''
|
||||
DXGRID = b''
|
||||
MYGRID = b""
|
||||
DXGRID = b""
|
||||
|
||||
SSID_LIST = [] # ssid list we are responding to
|
||||
|
||||
|
@ -43,21 +43,21 @@ SERIAL_DEVICES = []
|
|||
PTT_STATE = False
|
||||
TRANSMITTING = False
|
||||
|
||||
HAMLIB_VERSION = '0'
|
||||
HAMLIB_PTT_TYPE = 'RTS'
|
||||
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
|
||||
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
|
||||
HAMLIB_SERIAL_SPEED = '9600'
|
||||
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
|
||||
HAMLIB_STOP_BITS = '1'
|
||||
HAMLIB_DATA_BITS = '8'
|
||||
HAMLIB_HANDSHAKE = 'None'
|
||||
HAMLIB_RADIOCONTROL = 'direct'
|
||||
HAMLIB_RIGCTLD_IP = '127.0.0.1'
|
||||
HAMLIB_RIGCTLD_PORT = '4532'
|
||||
HAMLIB_VERSION = "0"
|
||||
HAMLIB_PTT_TYPE = "RTS"
|
||||
HAMLIB_DEVICE_NAME = "RIG_MODEL_DUMMY_NOVFO"
|
||||
HAMLIB_DEVICE_PORT = "/dev/ttyUSB0"
|
||||
HAMLIB_SERIAL_SPEED = "9600"
|
||||
HAMLIB_PTT_PORT = "/dev/ttyUSB0"
|
||||
HAMLIB_STOP_BITS = "1"
|
||||
HAMLIB_DATA_BITS = "8"
|
||||
HAMLIB_HANDSHAKE = "None"
|
||||
HAMLIB_RADIOCONTROL = "direct"
|
||||
HAMLIB_RIGCTLD_IP = "127.0.0.1"
|
||||
HAMLIB_RIGCTLD_PORT = "4532"
|
||||
|
||||
HAMLIB_FREQUENCY = 0
|
||||
HAMLIB_MODE = ''
|
||||
HAMLIB_MODE = ""
|
||||
HAMLIB_BANDWITH = 0
|
||||
# -------------------------
|
||||
# FreeDV Defaults
|
||||
|
@ -75,7 +75,7 @@ AUDIO_INPUT_DEVICES = []
|
|||
AUDIO_OUTPUT_DEVICES = []
|
||||
AUDIO_INPUT_DEVICE = -2
|
||||
AUDIO_OUTPUT_DEVICE = -2
|
||||
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0]
|
||||
BUFFER_OVERFLOW_COUNTER = [0, 0, 0, 0, 0]
|
||||
|
||||
AUDIO_RMS = 0
|
||||
FFT = [0]
|
||||
|
@ -96,11 +96,13 @@ ARQ_SPEED_LEVEL = 0
|
|||
TOTAL_BYTES = 0
|
||||
|
||||
|
||||
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
TNC_STATE = 'IDLE'
|
||||
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
TNC_STATE = "IDLE"
|
||||
ARQ_STATE = False
|
||||
ARQ_SESSION = False
|
||||
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed
|
||||
ARQ_SESSION_STATE = (
|
||||
"disconnected" # disconnected, connecting, connected, disconnecting, failed
|
||||
)
|
||||
|
||||
# BEACON STATE
|
||||
BEACON_STATE = False
|
||||
|
@ -110,8 +112,8 @@ BEACON_PAUSE = False
|
|||
RX_BUFFER = []
|
||||
RX_MSG_BUFFER = []
|
||||
RX_BURST_BUFFER = []
|
||||
RX_FRAME_BUFFER = b''
|
||||
#RX_BUFFER_SIZE = 0
|
||||
RX_FRAME_BUFFER = b""
|
||||
# RX_BUFFER_SIZE = 0
|
||||
|
||||
# ------- HEARD STATIOS BUFFER
|
||||
HEARD_STATIONS = []
|
||||
|
|
Loading…
Reference in a new issue