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:
CRC-24 (OpenPGP) of the provided data as bytes
"""
crc_algorithm = crcengine.create(0x864cfb, 24, 0xb704ce, ref_in=False,
ref_out=False, xor_out=0,
name='crc-24-openpgp')
crc_algorithm = crcengine.create(0x864cfb,
24,
0xb704ce,
ref_in=False,
ref_out=False,
xor_out=0,
name='crc-24-openpgp')
crc_data = crc_algorithm(data)
crc_data = crc_data.to_bytes(3, byteorder='big')
return crc_data
@ -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])
break
# for idx, item in enumerate(static.HEARD_STATIONS):
# if dxcallsign in item:
# item = [dxcallsign, int(time.time())]
@ -174,7 +179,6 @@ def callsign_to_bytes(callsign) -> bytes:
callsign = bytes(callsign, 'utf-8')
except TypeError as 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)
callsign = callsign.split(b'-')
@ -195,6 +199,7 @@ def callsign_to_bytes(callsign) -> bytes:
return encode_call(callsign + ssid)
# return bytes(bytestring)
def bytes_to_callsign(bytestring: bytes) -> bytes:
"""
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")
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
@ -288,30 +293,31 @@ def encode_grid(grid):
"""
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_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
int_val = int(grid[2:4]) # number string to number int, highest value 99
out_code_word |= (int_val & 0b1111111) # using bit OR to add new value
out_code_word |= (int_val & 0b1111111) # using bit OR to add new value
out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X
int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
out_code_word <<= 5 # shift 5 bit left having space next bits, letter A-X
int_val = ord(grid[5]) - 65 # -65 offset for 'A' become zero, utf8 table
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
out_code_word |= (int_val & 0b11111) # using bit OR to add new value
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
Args:
@ -340,6 +346,7 @@ def decode_grid(b_code_word:bytes):
return grid
def encode_call(call):
"""
@author: DB1UJ
@ -351,7 +358,7 @@ def encode_call(call):
"""
out_code_word = 0
call = call.upper() # upper case to be save
call = call.upper() # upper case to be save
for x in call:
int_val = ord(x) - 48 # -48 reduce bits, begin with first number utf8 table
@ -364,7 +371,7 @@ def encode_call(call):
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
Args:
@ -378,7 +385,7 @@ def decode_call(b_code_word:bytes):
call = str()
while code_word != 0:
call = chr((code_word & 0b111111)+48) + call
call = chr((code_word & 0b111111) + 48) + call
code_word >>= 6
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 static
# signal handler for closing aplication
def signal_handler(sig, frame):
"""
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
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
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()
# --------------------------------------------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('--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)

View file

@ -10,11 +10,8 @@ Created on Wed Dec 23 07:04:24 2020
import atexit
import ctypes
import logging
import os
import pathlib
import queue
import re
import sys
import threading
import time
@ -25,11 +22,9 @@ import sounddevice as sd
import structlog
import ujson as json
import audio
# import audio
import codec2
import data_handler
import helpers
import log_handler
import sock
import static
@ -47,8 +42,10 @@ RECEIVE_DATAC1 = False
RECEIVE_DATAC3 = False
RECEIVE_FSK_LDPC_1 = False
class RF():
class RF:
""" """
def __init__(self):
self.sampler_avg = 0
@ -86,41 +83,51 @@ class RF():
# Open codec2 instances
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_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_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)
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.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_out = ctypes.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)
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.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_out = ctypes.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)
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_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_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_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)
# initial nin values
@ -132,7 +139,9 @@ class RF():
# --------------------------------------------CREATE PYAUDIO INSTANCE
if not TESTMODE:
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)
structlog.get_logger("structlog").info("[MDM] init: opened audio devices")
@ -142,7 +151,7 @@ class RF():
try:
structlog.get_logger("structlog").debug("[MDM] init: starting pyaudio callback")
#self.audio_stream.start_stream()
# self.audio_stream.start_stream()
self.stream.start()
except Exception as e:
@ -152,6 +161,7 @@ class RF():
# create a stream object for simulating audio stream
class Object(object):
pass
self.stream = Object()
self.stream.active = True
@ -161,12 +171,13 @@ class RF():
os.mkfifo(TXCHANNEL)
except Exception as 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_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()
# --------------------------------------------INIT AND OPEN HAMLIB
@ -183,7 +194,11 @@ class RF():
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_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
if static.ENABLE_FFT:
@ -200,10 +215,12 @@ class RF():
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)
@ -235,10 +252,10 @@ class RF():
self.datac0_buffer.push(x)
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:
self.datac3_buffer.push(x)
self.datac3_buffer.push(x)
def mkfifo_write_callback(self):
while 1:
@ -246,12 +263,11 @@ class RF():
# -----write
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
else:
data_out48k = self.modoutqueue.popleft()
#print(len(data_out48k))
fifo_write = open(TXCHANNEL, 'wb')
fifo_write.write(data_out48k)
@ -312,7 +328,7 @@ class RF():
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:
data_out48k = np.zeros(frames, dtype=np.int16)
self.fft_data = x
else:
@ -343,7 +359,7 @@ 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)
@ -390,12 +406,13 @@ class RF():
# 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 = 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 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
# -------------------------------
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:
delta = chunk_length - len(c)
delta_zeros = np.zeros(delta, dtype=np.int16)
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)
@ -441,7 +458,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)
@ -460,12 +477,14 @@ 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):
@ -475,12 +494,14 @@ 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):
@ -490,12 +511,14 @@ 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):
@ -505,12 +528,14 @@ 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):
@ -520,12 +545,14 @@ 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
@ -536,7 +563,7 @@ class RF():
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.modem_transmit_queue.task_done()
# self.modem_transmit_queue.task_done()
# worker for FIFO queue for processing received frames
def worker_received(self):
@ -644,7 +671,7 @@ class RF():
channel_busy_delay = 0
while True:
#time.sleep(0.01)
# time.sleep(0.01)
threading.Event().wait(0.01)
# WE NEED TO OPTIMIZE THIS!
@ -657,7 +684,7 @@ class RF():
# set value 0 to 1 to avoid division by zero
fftarray[fftarray == 0] = 1
dfft = 10.*np.log10(abs(fftarray))
dfft = 10. * np.log10(abs(fftarray))
# get average of 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
# Have to do this when we are not transmitting 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)
@ -688,7 +715,7 @@ class RF():
dfft = np.around(dfft, 0)
dfftlist = dfft.tolist()
static.FFT = dfftlist[:320] #320 --> bandwidth 3000
static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
except Exception as e:
structlog.get_logger("structlog").error(f"[MDM] calculate_fft: Exception: {e}")
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.fsk_ldpc_freedv_0, n_frames_per_burst)
def open_codec2_instance(mode):
""" Return a codec2 instance """
if mode in ['FSK_LDPC_0', 200]:
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]:
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)

View file

@ -23,13 +23,13 @@ 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/')
# 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
@ -55,7 +55,7 @@ except Exception as 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(' ')
@ -166,7 +166,7 @@ class radio:
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"))
@ -192,7 +192,7 @@ class radio:
# 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
@ -215,7 +215,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):

View file

@ -54,14 +54,14 @@ 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
# check if we are running in a pyinstaller environment
if hasattr(sys, "_MEIPASS"):
sys.path.append(getattr(sys, "_MEIPASS"))
else:
@ -75,7 +75,7 @@ class radio:
if int(self.devicename):
self.devicenumber = int(self.devicename)
else:
self.devicenumber = 6 #dummy
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
@ -179,5 +179,5 @@ class radio:
def close_rig(self):
""" """
#self.my_rig.close()
# self.my_rig.close()
return

View file

@ -24,7 +24,7 @@ class radio():
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
""" 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
@ -63,7 +63,7 @@ class radio():
"""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)
return True

View file

@ -21,22 +21,19 @@ Created on Fri Dec 25 21:25:14 2020
"""
import atexit
import base64
import logging
import os
import queue
import socketserver
import sys
import threading
import time
import psutil
import structlog
import ujson as json
import audio
import data_handler
import helpers
import log_handler
import static
SOCKET_QUEUE = queue.Queue()
@ -81,10 +78,10 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
while not SOCKET_QUEUE.empty():
data = SOCKET_QUEUE.get()
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
#try:
# try:
for client in CONNECTED_CLIENTS:
try:
client.send(sock_data)
@ -97,7 +94,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):
@ -112,7 +109,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
data += chunk
if chunk == b'':
#print("connection broken. Closing...")
# print("connection broken. Closing...")
self.connection_alive = False
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
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):
@ -147,11 +145,12 @@ 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:
@ -159,11 +158,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
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):
"""
@ -346,13 +348,15 @@ def process_tnc_commands(data):
}
for i in range(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)
@ -368,10 +372,11 @@ def process_tnc_commands(data):
command_response("del_rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# exception, if JSON cant be decoded
# exception, if JSON can't 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
@ -401,8 +406,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),
@ -422,6 +427,7 @@ def send_tnc_state():
return json.dumps(output)
def process_daemon_commands(data):
"""
process daemon commands
@ -441,13 +447,15 @@ def process_daemon_commands(data):
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)
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_CRC = helpers.get_crc_24(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)
@ -494,33 +502,34 @@ 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,
respond_to_cq,
])
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,
respond_to_cq,
])
command_response("start_tnc", True)
except Exception as e:
@ -542,18 +551,18 @@ def process_daemon_commands(data):
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,
])
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)
@ -572,6 +581,7 @@ def process_daemon_commands(data):
command_response("stop_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
def send_daemon_state():
"""
send the daemon state to network
@ -587,10 +597,10 @@ def send_daemon_state():
'input_devices': static.AUDIO_INPUT_DEVICES,
'output_devices': static.AUDIO_OUTPUT_DEVICES,
'serial_devices': static.SERIAL_DEVICES,
#'cpu': str(psutil.cpu_percent()),
#'ram': str(psutil.virtual_memory().percent),
# 'cpu': str(psutil.cpu_percent()),
# 'ram': str(psutil.virtual_memory().percent),
'version': '0.1'
}
}
if static.TNCSTARTED:
output["daemon_state"].append({"status": "running"})
@ -604,8 +614,9 @@ def send_daemon_state():
structlog.get_logger("structlog").warning("[SCK] error", e=e)
return None
def command_response(command, status):
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)
SOCKET_QUEUE.put(data_out)

View file

@ -25,7 +25,7 @@ DXCALLSIGN_CRC = b'A'
MYGRID = b''
DXGRID = b''
SSID_LIST = [] # ssid list we are responding to
SSID_LIST = [] # ssid list we are responding to
LOW_BANDWITH_MODE = False
# ---------------------------------
@ -33,7 +33,7 @@ LOW_BANDWITH_MODE = False
# Server Defaults
HOST = "0.0.0.0"
PORT = 3000
SOCKET_TIMEOUT = 1 # seconds
SOCKET_TIMEOUT = 1 # seconds
# ---------------------------------
SERIAL_DEVICES = []
# ---------------------------------
@ -74,7 +74,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]
@ -94,11 +94,11 @@ ARQ_TRANSMISSION_PERCENT = 0
ARQ_SPEED_LEVEL = 0
TOTAL_BYTES = 0
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
# 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
@ -109,9 +109,9 @@ RX_BUFFER = []
RX_MSG_BUFFER = []
RX_BURST_BUFFER = []
RX_FRAME_BUFFER = b''
#RX_BUFFER_SIZE = 0
# RX_BUFFER_SIZE = 0
# ------- HEARD STATIOS BUFFER
# ------- HEARD STATIONS BUFFER
HEARD_STATIONS = []
# ------- INFO MESSAGE BUFFER