Second run reducing number of problems

This commit is contained in:
DJ2LS 2022-05-23 13:11:16 +02:00
parent b6face744b
commit d992fd8dc0
8 changed files with 211 additions and 162 deletions

View file

@ -80,9 +80,13 @@ def get_crc_24(data) -> bytes:
Returns: Returns:
CRC-24 (OpenPGP) of the provided data as bytes CRC-24 (OpenPGP) of the provided data as bytes
""" """
crc_algorithm = crcengine.create(0x864cfb, 24, 0xb704ce, ref_in=False, crc_algorithm = crcengine.create(0x864cfb,
ref_out=False, xor_out=0, 24,
name='crc-24-openpgp') 0xb704ce,
ref_in=False,
ref_out=False,
xor_out=0,
name='crc-24-openpgp')
crc_data = crc_algorithm(data) crc_data = crc_algorithm(data)
crc_data = crc_data.to_bytes(3, byteorder='big') crc_data = crc_data.to_bytes(3, byteorder='big')
return crc_data return crc_data
@ -136,6 +140,7 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency]) static.HEARD_STATIONS.append([dxcallsign, dxgrid, int(time.time()), datatype, snr, offset, frequency])
break break
# for idx, item in enumerate(static.HEARD_STATIONS): # for idx, item in enumerate(static.HEARD_STATIONS):
# if dxcallsign in item: # if dxcallsign in item:
# item = [dxcallsign, int(time.time())] # item = [dxcallsign, int(time.time())]
@ -174,7 +179,6 @@ def callsign_to_bytes(callsign) -> bytes:
callsign = bytes(callsign, 'utf-8') callsign = bytes(callsign, 'utf-8')
except TypeError as e: except TypeError as e:
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=e) structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=e)
pass
# Need this step to reduce the needed payload by the callsign (stripping "-" out of the callsign) # Need this step to reduce the needed payload by the callsign (stripping "-" out of the callsign)
callsign = callsign.split(b'-') callsign = callsign.split(b'-')
@ -195,6 +199,7 @@ def callsign_to_bytes(callsign) -> bytes:
return encode_call(callsign + ssid) return encode_call(callsign + ssid)
# return bytes(bytestring) # return bytes(bytestring)
def bytes_to_callsign(bytestring: bytes) -> bytes: def bytes_to_callsign(bytestring: bytes) -> bytes:
""" """
Convert our callsign, received by a frame to a callsign in a human readable format Convert our callsign, received by a frame to a callsign in a human readable format
@ -242,7 +247,7 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
return bytes(f"{callsign}-{ssid}", "utf-8") return bytes(f"{callsign}-{ssid}", "utf-8")
def check_callsign(callsign:bytes, crc_to_check:bytes): def check_callsign(callsign: bytes, crc_to_check: bytes):
""" """
Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it
@ -288,30 +293,31 @@ def encode_grid(grid):
""" """
out_code_word = 0 out_code_word = 0
grid = grid.upper() # upper case to be save grid = grid.upper() # upper case to be save
int_first = ord(grid[0]) - 65 # -65 offset for 'A' become zero, utf8 table int_first = ord(grid[0]) - 65 # -65 offset for 'A' become zero, utf8 table
int_sec = ord(grid[1]) - 65 # -65 offset for 'A' become zero, utf8 table int_sec = ord(grid[1]) - 65 # -65 offset for 'A' become zero, utf8 table
int_val = (int_first * 18) + int_sec # encode for modulo devision, 2 numbers in 1 int_val = (int_first * 18) + int_sec # encode for modulo devision, 2 numbers in 1
out_code_word = (int_val & 0b111111111) # only 9 bit LSB A - R * A - R is needed out_code_word = (int_val & 0b111111111) # only 9 bit LSB A - R * A - R is needed
out_code_word <<= 9 # shift 9 bit left having space next bits, letter A-R * A-R out_code_word <<= 9 # shift 9 bit left having space next bits, letter A-R * A-R
int_val = int(grid[2:4]) # number string to number int, highest value 99 int_val = int(grid[2:4]) # number string to number int, highest value 99
out_code_word |= (int_val & 0b1111111) # using bit OR to add new value out_code_word |= (int_val & 0b1111111) # using bit OR to add new value
out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X
int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table
out_code_word |= (int_val & 0b11111) # using bit OR to add new value out_code_word |= (int_val & 0b11111) # using bit OR to add new value
out_code_word <<= 5 # shift 5 bit left having space next bits, letter A-X out_code_word <<= 5 # shift 5 bit left having space next bits, letter A-X
int_val = ord(grid[5]) - 65 # -65 offset for 'A' become zero, utf8 table int_val = ord(grid[5]) - 65 # -65 offset for 'A' become zero, utf8 table
out_code_word |= (int_val & 0b11111) # using bit OR to add new value out_code_word |= (int_val & 0b11111) # using bit OR to add new value
return out_code_word.to_bytes(length=4, byteorder='big') return out_code_word.to_bytes(length=4, byteorder='big')
def decode_grid(b_code_word:bytes):
def decode_grid(b_code_word: bytes):
""" """
@author: DB1UJ @author: DB1UJ
Args: Args:
@ -340,6 +346,7 @@ def decode_grid(b_code_word:bytes):
return grid return grid
def encode_call(call): def encode_call(call):
""" """
@author: DB1UJ @author: DB1UJ
@ -351,7 +358,7 @@ def encode_call(call):
""" """
out_code_word = 0 out_code_word = 0
call = call.upper() # upper case to be save call = call.upper() # upper case to be save
for x in call: for x in call:
int_val = ord(x) - 48 # -48 reduce bits, begin with first number utf8 table int_val = ord(x) - 48 # -48 reduce bits, begin with first number utf8 table
@ -364,7 +371,7 @@ def encode_call(call):
return out_code_word.to_bytes(length=6, byteorder='big') return out_code_word.to_bytes(length=6, byteorder='big')
def decode_call(b_code_word:bytes): def decode_call(b_code_word: bytes):
""" """
@author: DB1UJ @author: DB1UJ
Args: Args:
@ -378,7 +385,7 @@ def decode_call(b_code_word:bytes):
call = str() call = str()
while code_word != 0: while code_word != 0:
call = chr((code_word & 0b111111)+48) + call call = chr((code_word & 0b111111) + 48) + call
code_word >>= 6 code_word >>= 6
call = call[:-1] + ssid # remove the last char from call and replace with SSID call = call[:-1] + ssid # remove the last char from call and replace with SSID

View file

@ -24,7 +24,7 @@ import log_handler
import modem import modem
import static import static
# signal handler for closing aplication
def signal_handler(sig, frame): def signal_handler(sig, frame):
""" """
a signal handler, which closes the network/socket when closing the application a signal handler, which closes the network/socket when closing the application
@ -39,15 +39,16 @@ def signal_handler(sig, frame):
sock.CLOSE_SIGNAL = True sock.CLOSE_SIGNAL = True
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
if __name__ == '__main__': if __name__ == '__main__':
# we need to run this on windows for multiprocessing support # we need to run this on Windows for multiprocessing support
multiprocessing.freeze_support() multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='FreeDATA TNC') PARSER = argparse.ArgumentParser(description='FreeDATA TNC')
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str) PARSER.add_argument('--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('--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('--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('--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('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)

View file

@ -10,11 +10,8 @@ Created on Wed Dec 23 07:04:24 2020
import atexit import atexit
import ctypes import ctypes
import logging
import os import os
import pathlib
import queue import queue
import re
import sys import sys
import threading import threading
import time import time
@ -25,11 +22,9 @@ import sounddevice as sd
import structlog import structlog
import ujson as json import ujson as json
import audio # import audio
import codec2 import codec2
import data_handler import data_handler
import helpers
import log_handler
import sock import sock
import static import static
@ -47,8 +42,10 @@ RECEIVE_DATAC1 = False
RECEIVE_DATAC3 = False RECEIVE_DATAC3 = False
RECEIVE_FSK_LDPC_1 = False RECEIVE_FSK_LDPC_1 = False
class RF():
class RF:
""" """ """ """
def __init__(self): def __init__(self):
self.sampler_avg = 0 self.sampler_avg = 0
@ -86,41 +83,51 @@ class RF():
# Open codec2 instances # Open codec2 instances
self.datac0_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p) self.datac0_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p)
self.c_lib.freedv_set_tuning_range(self.datac0_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX)) self.c_lib.freedv_set_tuning_range(self.datac0_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
ctypes.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_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_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_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_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_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_n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(
self.datac0_freedv)
self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame) self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac0_freedv, 1) codec2.api.freedv_set_frames_per_burst(self.datac0_freedv, 1)
self.datac0_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.datac1_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p) self.datac1_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p)
self.c_lib.freedv_set_tuning_range(self.datac1_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX)) self.c_lib.freedv_set_tuning_range(self.datac1_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
ctypes.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_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8)
self.datac1_bytes_out = ctypes.create_string_buffer(self.datac1_bytes_per_frame) self.datac1_bytes_out = ctypes.create_string_buffer(self.datac1_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, 1) codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, 1)
self.datac1_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.datac3_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p) self.datac3_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p)
self.c_lib.freedv_set_tuning_range(self.datac3_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX)) self.c_lib.freedv_set_tuning_range(self.datac3_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
ctypes.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_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8)
self.datac3_bytes_out = ctypes.create_string_buffer(self.datac3_bytes_per_frame) self.datac3_bytes_out = ctypes.create_string_buffer(self.datac3_bytes_per_frame)
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, 1) codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, 1)
self.datac3_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX) self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
self.fsk_ldpc_freedv_0 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), ctypes.c_void_p) self.fsk_ldpc_freedv_0 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(
codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)),
ctypes.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_per_frame_0 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_0) / 8)
self.fsk_ldpc_bytes_out_0 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_0) self.fsk_ldpc_bytes_out_0 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_0)
#codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1) # codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1)
self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX)
self.fsk_ldpc_freedv_1 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), ctypes.c_void_p) self.fsk_ldpc_freedv_1 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(
codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)),
ctypes.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_per_frame_1 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_1) / 8)
self.fsk_ldpc_bytes_out_1 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_1) self.fsk_ldpc_bytes_out_1 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_1)
#codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1) # codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1)
self.fsk_ldpc_buffer_1 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) self.fsk_ldpc_buffer_1 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX)
# initial nin values # initial nin values
@ -132,7 +139,9 @@ class RF():
# --------------------------------------------CREATE PYAUDIO INSTANCE # --------------------------------------------CREATE PYAUDIO INSTANCE
if not TESTMODE: if not TESTMODE:
try: try:
self.stream = sd.RawStream(channels=1, dtype='int16', callback=self.callback, device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE), samplerate = self.AUDIO_SAMPLE_RATE_RX, blocksize=4800) self.stream = sd.RawStream(channels=1, dtype='int16', callback=self.callback,
device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE),
samplerate=self.AUDIO_SAMPLE_RATE_RX, blocksize=4800)
atexit.register(self.stream.stop) atexit.register(self.stream.stop)
structlog.get_logger("structlog").info("[MDM] init: opened audio devices") structlog.get_logger("structlog").info("[MDM] init: opened audio devices")
@ -142,7 +151,7 @@ class RF():
try: try:
structlog.get_logger("structlog").debug("[MDM] init: starting pyaudio callback") structlog.get_logger("structlog").debug("[MDM] init: starting pyaudio callback")
#self.audio_stream.start_stream() # self.audio_stream.start_stream()
self.stream.start() self.stream.start()
except Exception as e: except Exception as e:
@ -152,6 +161,7 @@ class RF():
# create a stream object for simulating audio stream # create a stream object for simulating audio stream
class Object(object): class Object(object):
pass pass
self.stream = Object() self.stream = Object()
self.stream.active = True self.stream.active = True
@ -161,12 +171,13 @@ class RF():
os.mkfifo(TXCHANNEL) os.mkfifo(TXCHANNEL)
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error(f"[MDM] init:mkfifo: Exception: {e}") structlog.get_logger("structlog").error(f"[MDM] init:mkfifo: Exception: {e}")
pass
mkfifo_write_callback_thread = threading.Thread(target=self.mkfifo_write_callback, name="MKFIFO WRITE CALLBACK THREAD",daemon=True) mkfifo_write_callback_thread = threading.Thread(target=self.mkfifo_write_callback,
name="MKFIFO WRITE CALLBACK THREAD", daemon=True)
mkfifo_write_callback_thread.start() mkfifo_write_callback_thread.start()
mkfifo_read_callback_thread = threading.Thread(target=self.mkfifo_read_callback, name="MKFIFO READ CALLBACK THREAD",daemon=True) mkfifo_read_callback_thread = threading.Thread(target=self.mkfifo_read_callback,
name="MKFIFO READ CALLBACK THREAD", daemon=True)
mkfifo_read_callback_thread.start() mkfifo_read_callback_thread.start()
# --------------------------------------------INIT AND OPEN HAMLIB # --------------------------------------------INIT AND OPEN HAMLIB
@ -183,7 +194,11 @@ class RF():
import rigdummy as rig import rigdummy as rig
self.hamlib = rig.radio() self.hamlib = rig.radio()
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT, hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED, pttport=static.HAMLIB_PTT_PORT, data_bits=static.HAMLIB_DATA_BITS, stop_bits=static.HAMLIB_STOP_BITS, handshake=static.HAMLIB_HANDSHAKE, rigctld_ip = static.HAMLIB_RIGCTLD_IP, rigctld_port = static.HAMLIB_RIGCTLD_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_RIGCTLD_IP, rigctld_port=static.HAMLIB_RIGCTLD_PORT)
# --------------------------------------------START DECODER THREAD # --------------------------------------------START DECODER THREAD
if static.ENABLE_FFT: if static.ENABLE_FFT:
@ -200,10 +215,12 @@ class RF():
audio_thread_datac3.start() audio_thread_datac3.start()
if static.ENABLE_FSK: if static.ENABLE_FSK:
audio_thread_fsk_ldpc0 = threading.Thread(target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0", daemon=True) audio_thread_fsk_ldpc0 = threading.Thread(target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0",
daemon=True)
audio_thread_fsk_ldpc0.start() audio_thread_fsk_ldpc0.start()
audio_thread_fsk_ldpc1 = threading.Thread(target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1", daemon=True) audio_thread_fsk_ldpc1 = threading.Thread(target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1",
daemon=True)
audio_thread_fsk_ldpc1.start() audio_thread_fsk_ldpc1.start()
hamlib_thread = threading.Thread(target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True) hamlib_thread = threading.Thread(target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True)
@ -235,10 +252,10 @@ class RF():
self.datac0_buffer.push(x) self.datac0_buffer.push(x)
if not self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size and RECEIVE_DATAC1: if not self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size and RECEIVE_DATAC1:
self.datac1_buffer.push(x) self.datac1_buffer.push(x)
if not self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size and RECEIVE_DATAC3: if not self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size and RECEIVE_DATAC3:
self.datac3_buffer.push(x) self.datac3_buffer.push(x)
def mkfifo_write_callback(self): def mkfifo_write_callback(self):
while 1: while 1:
@ -246,12 +263,11 @@ class RF():
# -----write # -----write
if len(self.modoutqueue) <= 0 or self.mod_out_locked: if len(self.modoutqueue) <= 0 or self.mod_out_locked:
#data_out48k = np.zeros(self.AUDIO_FRAMES_PER_BUFFER_RX, dtype=np.int16) # data_out48k = np.zeros(self.AUDIO_FRAMES_PER_BUFFER_RX, dtype=np.int16)
pass pass
else: else:
data_out48k = self.modoutqueue.popleft() data_out48k = self.modoutqueue.popleft()
#print(len(data_out48k))
fifo_write = open(TXCHANNEL, 'wb') fifo_write = open(TXCHANNEL, 'wb')
fifo_write.write(data_out48k) fifo_write.write(data_out48k)
@ -312,7 +328,7 @@ class RF():
static.BUFFER_OVERFLOW_COUNTER[4] += 1 static.BUFFER_OVERFLOW_COUNTER[4] += 1
if len(self.modoutqueue) <= 0 or self.mod_out_locked: if len(self.modoutqueue) <= 0 or self.mod_out_locked:
# if not self.modoutqueue or self.mod_out_locked:
data_out48k = np.zeros(frames, dtype=np.int16) data_out48k = np.zeros(frames, dtype=np.int16)
self.fft_data = x self.fft_data = x
else: else:
@ -343,7 +359,7 @@ class RF():
static.TRANSMITTING = True static.TRANSMITTING = True
# Toggle ptt early to save some time and send ptt state via socket # Toggle ptt early to save some time and send ptt state via socket
static.PTT_STATE = self.hamlib.set_ptt(True) static.PTT_STATE = self.hamlib.set_ptt(True)
jsondata = {"ptt":"True"} jsondata = {"ptt": "True"}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out) sock.SOCKET_QUEUE.put(data_out)
@ -390,12 +406,13 @@ class RF():
# Create crc for data frame - we are using the crc function shipped with codec2 to avoid # Create crc for data frame - we are using the crc function shipped with codec2 to avoid
# CRC algorithm incompatibilities # CRC algorithm incompatibilities
crc = ctypes.c_ushort(codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)) # Generate CRC16 crc = ctypes.c_ushort(
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 = crc.value.to_bytes(2, byteorder='big') # Convert crc to 2 byte hex string
buffer += crc # Append crc16 to buffer buffer += crc # Append crc16 to buffer
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer) data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer codec2.api.freedv_rawdatatx(freedv, mod_out, data) # modulate DATA and save it into mod_out pointer
txbuffer += bytes(mod_out) txbuffer += bytes(mod_out)
# codec2 fsk postamble may be broken - at least it sounds like that so we are disabling it for testing # codec2 fsk postamble may be broken - at least it sounds like that so we are disabling it for testing
@ -421,14 +438,14 @@ class RF():
self.mod_out_locked = False self.mod_out_locked = False
# ------------------------------- # -------------------------------
chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX #4800 chunk_length = self.AUDIO_FRAMES_PER_BUFFER_TX # 4800
chunk = [txbuffer_48k[i:i+chunk_length] for i in range(0, len(txbuffer_48k), chunk_length)] chunk = [txbuffer_48k[i:i + chunk_length] for i in range(0, len(txbuffer_48k), chunk_length)]
for c in chunk: for c in chunk:
if len(c) < chunk_length: if len(c) < chunk_length:
delta = chunk_length - len(c) delta = chunk_length - len(c)
delta_zeros = np.zeros(delta, dtype=np.int16) delta_zeros = np.zeros(delta, dtype=np.int16)
c = np.append(c, delta_zeros) c = np.append(c, delta_zeros)
#structlog.get_logger("structlog").debug("[MDM] mod out shorter than audio buffer", delta=delta) # structlog.get_logger("structlog").debug("[MDM] mod out shorter than audio buffer", delta=delta)
self.modoutqueue.append(c) self.modoutqueue.append(c)
@ -441,7 +458,7 @@ class RF():
static.PTT_STATE = self.hamlib.set_ptt(False) static.PTT_STATE = self.hamlib.set_ptt(False)
# Push ptt state to socket stream # Push ptt state to socket stream
jsondata = {"ptt":"False"} jsondata = {"ptt": "False"}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out) sock.SOCKET_QUEUE.put(data_out)
@ -460,12 +477,14 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac0_buffer.nbuffer >= self.datac0_nin: while self.datac0_buffer.nbuffer >= self.datac0_nin:
# demodulate audio # demodulate audio
nbytes_datac0 = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out, self.datac0_buffer.buffer.ctypes) nbytes_datac0 = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out,
self.datac0_buffer.buffer.ctypes)
self.datac0_buffer.pop(self.datac0_nin) self.datac0_buffer.pop(self.datac0_nin)
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv) self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
if nbytes_datac0 == self.datac0_bytes_per_frame: if nbytes_datac0 == self.datac0_bytes_per_frame:
self.modem_received_queue.put([self.datac0_bytes_out, self.datac0_freedv, self.datac0_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac0_freedv) [self.datac0_bytes_out, self.datac0_freedv, self.datac0_bytes_per_frame])
# self.get_scatter(self.datac0_freedv)
self.calculate_snr(self.datac0_freedv) self.calculate_snr(self.datac0_freedv)
def audio_datac1(self): def audio_datac1(self):
@ -475,12 +494,14 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac1_buffer.nbuffer >= self.datac1_nin: while self.datac1_buffer.nbuffer >= self.datac1_nin:
# demodulate audio # demodulate audio
nbytes_datac1 = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out, self.datac1_buffer.buffer.ctypes) nbytes_datac1 = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out,
self.datac1_buffer.buffer.ctypes)
self.datac1_buffer.pop(self.datac1_nin) self.datac1_buffer.pop(self.datac1_nin)
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv) self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
if nbytes_datac1 == self.datac1_bytes_per_frame: if nbytes_datac1 == self.datac1_bytes_per_frame:
self.modem_received_queue.put([self.datac1_bytes_out, self.datac1_freedv, self.datac1_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac1_freedv) [self.datac1_bytes_out, self.datac1_freedv, self.datac1_bytes_per_frame])
# self.get_scatter(self.datac1_freedv)
self.calculate_snr(self.datac1_freedv) self.calculate_snr(self.datac1_freedv)
def audio_datac3(self): def audio_datac3(self):
@ -490,12 +511,14 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.datac3_buffer.nbuffer >= self.datac3_nin: while self.datac3_buffer.nbuffer >= self.datac3_nin:
# demodulate audio # demodulate audio
nbytes_datac3 = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out, self.datac3_buffer.buffer.ctypes) nbytes_datac3 = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out,
self.datac3_buffer.buffer.ctypes)
self.datac3_buffer.pop(self.datac3_nin) self.datac3_buffer.pop(self.datac3_nin)
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv) self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
if nbytes_datac3 == self.datac3_bytes_per_frame: if nbytes_datac3 == self.datac3_bytes_per_frame:
self.modem_received_queue.put([self.datac3_bytes_out, self.datac3_freedv, self.datac3_bytes_per_frame]) self.modem_received_queue.put(
#self.get_scatter(self.datac3_freedv) [self.datac3_bytes_out, self.datac3_freedv, self.datac3_bytes_per_frame])
# self.get_scatter(self.datac3_freedv)
self.calculate_snr(self.datac3_freedv) self.calculate_snr(self.datac3_freedv)
def audio_fsk_ldpc_0(self): def audio_fsk_ldpc_0(self):
@ -505,12 +528,14 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0: while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0:
# demodulate audio # demodulate audio
nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_buffer_0.buffer.ctypes) nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_out_0,
self.fsk_ldpc_buffer_0.buffer.ctypes)
self.fsk_ldpc_buffer_0.pop(self.fsk_ldpc_nin_0) self.fsk_ldpc_buffer_0.pop(self.fsk_ldpc_nin_0)
self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0) self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0)
if nbytes_fsk_ldpc_0 == self.fsk_ldpc_bytes_per_frame_0: if nbytes_fsk_ldpc_0 == self.fsk_ldpc_bytes_per_frame_0:
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_per_frame_0]) self.modem_received_queue.put(
#self.get_scatter(self.fsk_ldpc_freedv_0) [self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_per_frame_0])
# self.get_scatter(self.fsk_ldpc_freedv_0)
self.calculate_snr(self.fsk_ldpc_freedv_0) self.calculate_snr(self.fsk_ldpc_freedv_0)
def audio_fsk_ldpc_1(self): def audio_fsk_ldpc_1(self):
@ -520,12 +545,14 @@ class RF():
threading.Event().wait(0.01) threading.Event().wait(0.01)
while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1: while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1:
# demodulate audio # demodulate audio
nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_buffer_1.buffer.ctypes) nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_out_1,
self.fsk_ldpc_buffer_1.buffer.ctypes)
self.fsk_ldpc_buffer_1.pop(self.fsk_ldpc_nin_1) self.fsk_ldpc_buffer_1.pop(self.fsk_ldpc_nin_1)
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1) self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
if nbytes_fsk_ldpc_1 == self.fsk_ldpc_bytes_per_frame_1: if nbytes_fsk_ldpc_1 == self.fsk_ldpc_bytes_per_frame_1:
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_per_frame_1]) self.modem_received_queue.put(
#self.get_scatter(self.fsk_ldpc_freedv_1) [self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_per_frame_1])
# self.get_scatter(self.fsk_ldpc_freedv_1)
self.calculate_snr(self.fsk_ldpc_freedv_1) self.calculate_snr(self.fsk_ldpc_freedv_1)
# worker for FIFO queue for processing received frames # worker for FIFO queue for processing received frames
@ -536,7 +563,7 @@ class RF():
structlog.get_logger("structlog").debug("[MDM] worker_transmit", mode=data[0]) structlog.get_logger("structlog").debug("[MDM] worker_transmit", mode=data[0])
self.transmit(mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3]) self.transmit(mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3])
#self.modem_transmit_queue.task_done() # self.modem_transmit_queue.task_done()
# worker for FIFO queue for processing received frames # worker for FIFO queue for processing received frames
def worker_received(self): def worker_received(self):
@ -644,7 +671,7 @@ class RF():
channel_busy_delay = 0 channel_busy_delay = 0
while True: while True:
#time.sleep(0.01) # time.sleep(0.01)
threading.Event().wait(0.01) threading.Event().wait(0.01)
# WE NEED TO OPTIMIZE THIS! # WE NEED TO OPTIMIZE THIS!
@ -657,7 +684,7 @@ class RF():
# set value 0 to 1 to avoid division by zero # set value 0 to 1 to avoid division by zero
fftarray[fftarray == 0] = 1 fftarray[fftarray == 0] = 1
dfft = 10.*np.log10(abs(fftarray)) dfft = 10. * np.log10(abs(fftarray))
# get average of dfft # get average of dfft
avg = np.mean(dfft) avg = np.mean(dfft)
@ -666,7 +693,7 @@ class RF():
# Data higher than the average must be a signal. Therefore we are setting it to 100 so it will be highlighted # Data higher than the average must be a signal. Therefore we are setting it to 100 so it will be highlighted
# Have to do this when we are not transmitting so our own sending data will not affect this too much # Have to do this when we are not transmitting so our own sending data will not affect this too much
if not static.TRANSMITTING: if not static.TRANSMITTING:
dfft[dfft>avg+10] = 100 dfft[dfft > avg + 10] = 100
# Calculate audio max value # Calculate audio max value
# static.AUDIO_RMS = np.amax(self.fft_data) # static.AUDIO_RMS = np.amax(self.fft_data)
@ -688,7 +715,7 @@ class RF():
dfft = np.around(dfft, 0) dfft = np.around(dfft, 0)
dfftlist = dfft.tolist() dfftlist = dfft.tolist()
static.FFT = dfftlist[:320] #320 --> bandwidth 3000 static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error(f"[MDM] calculate_fft: Exception: {e}") structlog.get_logger("structlog").error(f"[MDM] calculate_fft: Exception: {e}")
structlog.get_logger("structlog").debug("[MDM] Setting fft=0") structlog.get_logger("structlog").debug("[MDM] Setting fft=0")
@ -708,15 +735,18 @@ class RF():
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, n_frames_per_burst)
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, n_frames_per_burst)
def open_codec2_instance(mode): def open_codec2_instance(mode):
""" Return a codec2 instance """ """ Return a codec2 instance """
if mode in ['FSK_LDPC_0', 200]: if mode in ['FSK_LDPC_0', 200]:
return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), ctypes.c_void_p) ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)),
ctypes.c_void_p)
if mode in ['FSK_LDPC_1', 201]: if mode in ['FSK_LDPC_1', 201]:
return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), ctypes.c_void_p) ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)),
ctypes.c_void_p)
return ctypes.cast(codec2.api.freedv_open(mode), ctypes.c_void_p) return ctypes.cast(codec2.api.freedv_open(mode), ctypes.c_void_p)

View file

@ -23,13 +23,13 @@ try:
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
# installation path for Ubuntu 20.04 LTS python modules # installation path for Ubuntu 20.04 LTS python modules
#sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages') # sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
# installation path for Ubuntu 20.10 + # installation path for Ubuntu 20.10 +
sys.path.append('/usr/local/lib/') sys.path.append('/usr/local/lib/')
# installation path for Suse # installation path for Suse
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages') sys.path.append('/usr/local/lib64/python' + python_version + '/site-packages')
# everything else... not nice, but an attempt to see how its running within app bundle # everything else... not nice, but an attempt to see how its running within app bundle
# this is not needed as python will be shipped with app bundle # this is not needed as python will be shipped with app bundle
@ -55,7 +55,7 @@ except Exception as e:
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e) structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e)
try: try:
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl") structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl")
rigctl = subprocess.Popen("rigctl -V",shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) rigctl = subprocess.Popen("rigctl -V", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
hamlib_version = rigctl.stdout.readline() hamlib_version = rigctl.stdout.readline()
hamlib_version = hamlib_version.split(' ') hamlib_version = hamlib_version.split(' ')
@ -166,7 +166,7 @@ class radio:
elif self.hamlib_ptt_type == 'RIG_PTT_NONE': elif self.hamlib_ptt_type == 'RIG_PTT_NONE':
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE': else: # self.hamlib_ptt_type == 'RIG_PTT_NONE':
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname")) structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname"))
@ -192,7 +192,7 @@ class radio:
# set rig mode to USB # set rig mode to USB
# temporarly outcommented because of possible problems. # temporarly outcommented because of possible problems.
#self.my_rig.set_mode(Hamlib.RIG_MODE_USB) # self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB) # self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
return True return True
@ -215,7 +215,7 @@ class radio:
return bandwith return bandwith
# not needed yet beacuse of some possible problems # not needed yet beacuse of some possible problems
#def set_mode(self, mode): # def set_mode(self, mode):
# return 0 # return 0
def get_ptt(self): def get_ptt(self):

View file

@ -54,14 +54,14 @@ class radio:
""" """
self.devicename = devicename self.devicename = devicename
self.deviceport = deviceport self.deviceport = deviceport
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = hamlib_ptt_type self.hamlib_ptt_type = hamlib_ptt_type
self.pttport = pttport self.pttport = pttport
self.data_bits = data_bits self.data_bits = data_bits
self.stop_bits = stop_bits self.stop_bits = stop_bits
self.handshake = handshake self.handshake = handshake
# check if we are running in a pyinstaller environment # check if we are running in a pyinstaller environment
if hasattr(sys, "_MEIPASS"): if hasattr(sys, "_MEIPASS"):
sys.path.append(getattr(sys, "_MEIPASS")) sys.path.append(getattr(sys, "_MEIPASS"))
else: else:
@ -75,7 +75,7 @@ class radio:
if int(self.devicename): if int(self.devicename):
self.devicenumber = int(self.devicename) self.devicenumber = int(self.devicename)
else: else:
self.devicenumber = 6 #dummy self.devicenumber = 6 # dummy
structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=e) structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=e)
# set deviceport to dummy port, if we selected dummy model # set deviceport to dummy port, if we selected dummy model
@ -179,5 +179,5 @@ class radio:
def close_rig(self): def close_rig(self):
""" """ """ """
#self.my_rig.close() # self.my_rig.close()
return return

View file

@ -24,7 +24,7 @@ class radio():
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5): def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
""" Open a connection to rotctld, and test it for validity """ """ Open a connection to rotctld, and test it for validity """
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#self.sock.settimeout(timeout) # self.sock.settimeout(timeout)
self.connected = False self.connected = False
self.hostname = hostname self.hostname = hostname
@ -63,7 +63,7 @@ class radio():
"""Connect to rigctld instance""" """Connect to rigctld instance"""
if not self.connected: if not self.connected:
try: try:
self.connection = socket.create_connection((self.hostname,self.port)) self.connection = socket.create_connection((self.hostname, self.port))
self.connected = True self.connected = True
structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port) structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port)
return True return True

View file

@ -21,22 +21,19 @@ Created on Fri Dec 25 21:25:14 2020
""" """
import atexit import atexit
import base64 import base64
import logging
import os
import queue import queue
import socketserver import socketserver
import sys import sys
import threading import threading
import time import time
import psutil
import structlog import structlog
import ujson as json import ujson as json
import audio
import data_handler import data_handler
import helpers import helpers
import log_handler
import static import static
SOCKET_QUEUE = queue.Queue() SOCKET_QUEUE = queue.Queue()
@ -81,10 +78,10 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
while not SOCKET_QUEUE.empty(): while not SOCKET_QUEUE.empty():
data = SOCKET_QUEUE.get() data = SOCKET_QUEUE.get()
sock_data = bytes(data, 'utf-8') sock_data = bytes(data, 'utf-8')
sock_data += b'\n' # append line limiter sock_data += b'\n' # append line limiter
# send data to all clients # send data to all clients
#try: # try:
for client in CONNECTED_CLIENTS: for client in CONNECTED_CLIENTS:
try: try:
client.send(sock_data) client.send(sock_data)
@ -97,7 +94,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
static.SCATTER = [] static.SCATTER = []
# we want to display INFO messages only once # we want to display INFO messages only once
static.INFO = [] static.INFO = []
#self.request.sendall(sock_data) # self.request.sendall(sock_data)
time.sleep(0.15) time.sleep(0.15)
def receive_from_client(self): def receive_from_client(self):
@ -112,7 +109,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
data += chunk data += chunk
if chunk == b'': if chunk == b'':
#print("connection broken. Closing...") # print("connection broken. Closing...")
self.connection_alive = False self.connection_alive = False
if data.startswith(b'{') and data.endswith(b'}\n'): if data.startswith(b'{') and data.endswith(b'}\n'):
@ -138,7 +135,8 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
# finally delete our rx buffer to be ready for new commands # finally delete our rx buffer to be ready for new commands
data = bytes() data = bytes()
except Exception as e: except Exception as e:
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e) structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0],
port=self.client_address[1], e=e)
self.connection_alive = False self.connection_alive = False
def handle(self): def handle(self):
@ -147,11 +145,12 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
""" """
CONNECTED_CLIENTS.add(self.request) CONNECTED_CLIENTS.add(self.request)
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1]) structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0],
port=self.client_address[1])
self.connection_alive = True self.connection_alive = True
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start() self.sendThread = threading.Thread(target=self.send_to_client, args=[], daemon=True).start()
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start() self.receiveThread = threading.Thread(target=self.receive_from_client, args=[], daemon=True).start()
# keep connection alive until we close it # keep connection alive until we close it
while self.connection_alive and not CLOSE_SIGNAL: while self.connection_alive and not CLOSE_SIGNAL:
@ -159,11 +158,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
def finish(self): def finish(self):
""" """ """ """
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1]) structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0],
port=self.client_address[1])
try: try:
CONNECTED_CLIENTS.remove(self.request) CONNECTED_CLIENTS.remove(self.request)
except: except:
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request) structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list",
client=self.request)
def process_tnc_commands(data): def process_tnc_commands(data):
""" """
@ -346,13 +348,15 @@ def process_tnc_commands(data):
} }
for i in range(len(static.RX_BUFFER)): for i in range(len(static.RX_BUFFER)):
#print(static.RX_BUFFER[i][4]) # print(static.RX_BUFFER[i][4])
#rawdata = json.loads(static.RX_BUFFER[i][4]) # rawdata = json.loads(static.RX_BUFFER[i][4])
base64_data = static.RX_BUFFER[i][4] base64_data = static.RX_BUFFER[i][4]
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data}) output["data-array"].append({"uuid": static.RX_BUFFER[i][0], "timestamp": static.RX_BUFFER[i][1],
"dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'),
"dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data})
jsondata = json.dumps(output) jsondata = json.dumps(output)
#self.request.sendall(bytes(jsondata, encoding)) # self.request.sendall(bytes(jsondata, encoding))
SOCKET_QUEUE.put(jsondata) SOCKET_QUEUE.put(jsondata)
command_response("rx_buffer", True) command_response("rx_buffer", True)
@ -368,10 +372,11 @@ def process_tnc_commands(data):
command_response("del_rx_buffer", False) command_response("del_rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# exception, if JSON cant be decoded # exception, if JSON can't be decoded
except Exception as e: except Exception as e:
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e) structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
def send_tnc_state(): def send_tnc_state():
""" """
send the tnc state to network send the tnc state to network
@ -401,8 +406,8 @@ def send_tnc_state():
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR), "arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT), "arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
"total_bytes": str(static.TOTAL_BYTES), "total_bytes": str(static.TOTAL_BYTES),
"info" : static.INFO, "info": static.INFO,
"beacon_state" : str(static.BEACON_STATE), "beacon_state": str(static.BEACON_STATE),
"stations": [], "stations": [],
"mycallsign": str(static.MYCALLSIGN, encoding), "mycallsign": str(static.MYCALLSIGN, encoding),
"dxcallsign": str(static.DXCALLSIGN, encoding), "dxcallsign": str(static.DXCALLSIGN, encoding),
@ -422,6 +427,7 @@ def send_tnc_state():
return json.dumps(output) return json.dumps(output)
def process_daemon_commands(data): def process_daemon_commands(data):
""" """
process daemon commands process daemon commands
@ -441,13 +447,15 @@ def process_daemon_commands(data):
if bytes(callsign, 'utf-8') == b'': if bytes(callsign, 'utf-8') == b'':
self.request.sendall(b'INVALID CALLSIGN') self.request.sendall(b'INVALID CALLSIGN')
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC) structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC)
else: else:
static.MYCALLSIGN = bytes(callsign, 'utf-8') static.MYCALLSIGN = bytes(callsign, 'utf-8')
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN) static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
command_response("mycallsign", True) command_response("mycallsign", True)
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC) structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN,
crc=static.MYCALLSIGN_CRC)
except Exception as e: except Exception as e:
command_response("mycallsign", False) command_response("mycallsign", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
@ -494,33 +502,34 @@ def process_daemon_commands(data):
# print some debugging parameters # print some debugging parameters
for item in received_json["parameter"][0]: for item in received_json["parameter"][0]:
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item]) structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item,
value=received_json["parameter"][0][item])
DAEMON_QUEUE.put(['STARTTNC', DAEMON_QUEUE.put(['STARTTNC',
mycall, mycall,
mygrid, mygrid,
rx_audio, rx_audio,
tx_audio, tx_audio,
devicename, devicename,
deviceport, deviceport,
serialspeed, serialspeed,
pttprotocol, pttprotocol,
pttport, pttport,
data_bits, data_bits,
stop_bits, stop_bits,
handshake, handshake,
radiocontrol, radiocontrol,
rigctld_ip, rigctld_ip,
rigctld_port, rigctld_port,
enable_scatter, enable_scatter,
enable_fft, enable_fft,
low_bandwith_mode, low_bandwith_mode,
tuning_range_fmin, tuning_range_fmin,
tuning_range_fmax, tuning_range_fmax,
enable_fsk, enable_fsk,
tx_audio_level, tx_audio_level,
respond_to_cq, respond_to_cq,
]) ])
command_response("start_tnc", True) command_response("start_tnc", True)
except Exception as e: except Exception as e:
@ -542,18 +551,18 @@ def process_daemon_commands(data):
rigctld_port = str(received_json["parameter"][0]["rigctld_port"]) rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
DAEMON_QUEUE.put(['TEST_HAMLIB', DAEMON_QUEUE.put(['TEST_HAMLIB',
devicename, devicename,
deviceport, deviceport,
serialspeed, serialspeed,
pttprotocol, pttprotocol,
pttport, pttport,
data_bits, data_bits,
stop_bits, stop_bits,
handshake, handshake,
radiocontrol, radiocontrol,
rigctld_ip, rigctld_ip,
rigctld_port, rigctld_port,
]) ])
command_response("test_hamlib", True) command_response("test_hamlib", True)
except Exception as e: except Exception as e:
command_response("test_hamlib", False) command_response("test_hamlib", False)
@ -572,6 +581,7 @@ def process_daemon_commands(data):
command_response("stop_tnc", False) command_response("stop_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
def send_daemon_state(): def send_daemon_state():
""" """
send the daemon state to network send the daemon state to network
@ -587,10 +597,10 @@ def send_daemon_state():
'input_devices': static.AUDIO_INPUT_DEVICES, 'input_devices': static.AUDIO_INPUT_DEVICES,
'output_devices': static.AUDIO_OUTPUT_DEVICES, 'output_devices': static.AUDIO_OUTPUT_DEVICES,
'serial_devices': static.SERIAL_DEVICES, 'serial_devices': static.SERIAL_DEVICES,
#'cpu': str(psutil.cpu_percent()), # 'cpu': str(psutil.cpu_percent()),
#'ram': str(psutil.virtual_memory().percent), # 'ram': str(psutil.virtual_memory().percent),
'version': '0.1' 'version': '0.1'
} }
if static.TNCSTARTED: if static.TNCSTARTED:
output["daemon_state"].append({"status": "running"}) output["daemon_state"].append({"status": "running"})
@ -604,8 +614,9 @@ def send_daemon_state():
structlog.get_logger("structlog").warning("[SCK] error", e=e) structlog.get_logger("structlog").warning("[SCK] error", e=e)
return None return None
def command_response(command, status): def command_response(command, status):
s_status = "OK" if status else "Failed" s_status = "OK" if status else "Failed"
jsondata = {"command_response": command, "status" : s_status} jsondata = {"command_response": command, "status": s_status}
data_out = json.dumps(jsondata) data_out = json.dumps(jsondata)
SOCKET_QUEUE.put(data_out) SOCKET_QUEUE.put(data_out)

View file

@ -25,7 +25,7 @@ DXCALLSIGN_CRC = b'A'
MYGRID = b'' MYGRID = b''
DXGRID = b'' DXGRID = b''
SSID_LIST = [] # ssid list we are responding to SSID_LIST = [] # ssid list we are responding to
LOW_BANDWITH_MODE = False LOW_BANDWITH_MODE = False
# --------------------------------- # ---------------------------------
@ -33,7 +33,7 @@ LOW_BANDWITH_MODE = False
# Server Defaults # Server Defaults
HOST = "0.0.0.0" HOST = "0.0.0.0"
PORT = 3000 PORT = 3000
SOCKET_TIMEOUT = 1 # seconds SOCKET_TIMEOUT = 1 # seconds
# --------------------------------- # ---------------------------------
SERIAL_DEVICES = [] SERIAL_DEVICES = []
# --------------------------------- # ---------------------------------
@ -74,7 +74,7 @@ AUDIO_INPUT_DEVICES = []
AUDIO_OUTPUT_DEVICES = [] AUDIO_OUTPUT_DEVICES = []
AUDIO_INPUT_DEVICE = -2 AUDIO_INPUT_DEVICE = -2
AUDIO_OUTPUT_DEVICE = -2 AUDIO_OUTPUT_DEVICE = -2
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0] BUFFER_OVERFLOW_COUNTER = [0, 0, 0, 0, 0]
AUDIO_RMS = 0 AUDIO_RMS = 0
FFT = [0] FFT = [0]
@ -94,11 +94,11 @@ ARQ_TRANSMISSION_PERCENT = 0
ARQ_SPEED_LEVEL = 0 ARQ_SPEED_LEVEL = 0
TOTAL_BYTES = 0 TOTAL_BYTES = 0
#CHANNEL_STATE = 'RECEIVING_SIGNALLING' # CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = 'IDLE' TNC_STATE = 'IDLE'
ARQ_STATE = False ARQ_STATE = False
ARQ_SESSION = False ARQ_SESSION = False
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed
# BEACON STATE # BEACON STATE
BEACON_STATE = False BEACON_STATE = False
@ -109,9 +109,9 @@ RX_BUFFER = []
RX_MSG_BUFFER = [] RX_MSG_BUFFER = []
RX_BURST_BUFFER = [] RX_BURST_BUFFER = []
RX_FRAME_BUFFER = b'' RX_FRAME_BUFFER = b''
#RX_BUFFER_SIZE = 0 # RX_BUFFER_SIZE = 0
# ------- HEARD STATIOS BUFFER # ------- HEARD STATIONS BUFFER
HEARD_STATIONS = [] HEARD_STATIONS = []
# ------- INFO MESSAGE BUFFER # ------- INFO MESSAGE BUFFER