Merge pull request #201 from DJ2LS/pep8_improvements

This commit is contained in:
DJ2LS 2022-05-28 15:28:13 +02:00 committed by GitHub
commit 8b9b54591f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 1334 additions and 1298 deletions

View file

@ -4,7 +4,7 @@ on: [push]
jobs: jobs:
build: build:
# The CMake configure and build commands are platform agnostic and should work equally # The CMake configure and build commands are platform-agnostic and should work equally
# well on Windows or Mac. You can convert this to a matrix build if you need # well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage. # cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix

View file

@ -12,7 +12,7 @@ My attempt to create a free and open-source TNC with a GUI for [codec2](https://
Please keep in mind, that this project is still a prototype with many issues which need to be solved. Please keep in mind, that this project is still a prototype with many issues which need to be solved.
Build steps for other OS than Ubuntu are provided, but not fully working, yet. Build steps for other OS than Ubuntu are provided, but not fully working, yet.
Please check the [Releases](https://github.com/DJ2LS/FreeDATA/releases) section for downloading nightly builds Please check the ['Releases'](https://github.com/DJ2LS/FreeDATA/releases) section for downloading nightly builds
## Preview ## Preview
![preview](https://github.com/DJ2LS/FreeDATA/blob/main/documentation/FreeDATA_preview.gif?raw=true "Preview") ![preview](https://github.com/DJ2LS/FreeDATA/blob/main/documentation/FreeDATA_preview.gif?raw=true "Preview")
@ -22,7 +22,7 @@ Please check the [Releases](https://github.com/DJ2LS/FreeDATA/releases) section
FreeDV Codec 2 : https://github.com/drowe67/codec2 FreeDV Codec 2 : https://github.com/drowe67/codec2
* xssfox, her repository helped me a lot in an early stage of development - * xssfox, her repository helped me a lot in an early stage of development -
xssfox : https://github.com/xssfox/freedv-tnc xssfox : https://github.com/xssfox/freedv-tnc
* Wolfgang, for lending me his radio so I'm able to do real hf tests * Wolfgang, for lending me his radio, so I'm able to do real hf tests
## Running the Ubuntu app bundle ## Running the Ubuntu app bundle
Download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies Download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies

View file

@ -217,7 +217,7 @@ exports.getDaemonState = function() {
// START TNC // START TNC
// ` `== multi line string // ` `== multi line string
exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwith_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq) { exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq) {
var json_command = JSON.stringify({ var json_command = JSON.stringify({
type: 'set', type: 'set',
command: 'start_tnc', command: 'start_tnc',
@ -240,7 +240,7 @@ exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, de
enable_scatter: enable_scatter, enable_scatter: enable_scatter,
enable_fft: enable_fft, enable_fft: enable_fft,
enable_fsk: enable_fsk, enable_fsk: enable_fsk,
low_bandwith_mode : low_bandwith_mode, low_bandwidth_mode : low_bandwidth_mode,
tuning_range_fmin : tuning_range_fmin, tuning_range_fmin : tuning_range_fmin,
tuning_range_fmax : tuning_range_fmax, tuning_range_fmax : tuning_range_fmax,
tx_audio_level : tx_audio_level, tx_audio_level : tx_audio_level,

View file

@ -68,7 +68,7 @@ const configDefaultSettings = '{\
"enable_scatter" : "False",\ "enable_scatter" : "False",\
"enable_fft" : "False",\ "enable_fft" : "False",\
"enable_fsk" : "False",\ "enable_fsk" : "False",\
"low_bandwith_mode" : "False",\ "low_bandwidth_mode" : "False",\
"theme" : "default",\ "theme" : "default",\
"screen_height" : 430,\ "screen_height" : 430,\
"screen_width" : 1050,\ "screen_width" : 1050,\

View file

@ -112,7 +112,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
document.getElementById("scatterSwitch").value = config.enable_scatter; document.getElementById("scatterSwitch").value = config.enable_scatter;
document.getElementById("fftSwitch").value = config.enable_fft; document.getElementById("fftSwitch").value = config.enable_fft;
//document.getElementById("500HzModeSwitch").value = config.low_bandwith_mode; //document.getElementById("500HzModeSwitch").value = config.low_bandwidth_mode;
//document.getElementById("fskModeSwitch").value = config.enable_fsk; //document.getElementById("fskModeSwitch").value = config.enable_fsk;
//document.getElementById("respondCQSwitch").value = config.respond_to_cq; //document.getElementById("respondCQSwitch").value = config.respond_to_cq;
@ -132,7 +132,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
document.getElementById("fftSwitch").checked = false; document.getElementById("fftSwitch").checked = false;
} }
if(config.low_bandwith_mode == 'True'){ if(config.low_bandwidth_mode == 'True'){
document.getElementById("500HzModeSwitch").checked = true; document.getElementById("500HzModeSwitch").checked = true;
} else { } else {
document.getElementById("500HzModeSwitch").checked = false; document.getElementById("500HzModeSwitch").checked = false;
@ -522,9 +522,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
// enable 500z Switch clicked // enable 500z Switch clicked
document.getElementById("500HzModeSwitch").addEventListener("click", () => { document.getElementById("500HzModeSwitch").addEventListener("click", () => {
if(document.getElementById("500HzModeSwitch").checked == true){ if(document.getElementById("500HzModeSwitch").checked == true){
config.low_bandwith_mode = "True"; config.low_bandwidth_mode = "True";
} else { } else {
config.low_bandwith_mode = "False"; config.low_bandwidth_mode = "False";
} }
fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
}); });
@ -650,9 +650,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
} }
if (document.getElementById("500HzModeSwitch").checked == true){ if (document.getElementById("500HzModeSwitch").checked == true){
var low_bandwith_mode = "True"; var low_bandwidth_mode = "True";
} else { } else {
var low_bandwith_mode = "False"; var low_bandwidth_mode = "False";
} }
if (document.getElementById("fskModeSwitch").checked == true){ if (document.getElementById("fskModeSwitch").checked == true){
@ -732,7 +732,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
config.enable_scatter = enable_scatter; config.enable_scatter = enable_scatter;
config.enable_fft = enable_fft; config.enable_fft = enable_fft;
config.enable_fsk = enable_fsk; config.enable_fsk = enable_fsk;
config.low_bandwith_mode = low_bandwith_mode; config.low_bandwidth_mode = low_bandwidth_mode;
config.tx_audio_level = tx_audio_level; config.tx_audio_level = tx_audio_level;
config.respond_to_cq = respond_to_cq; config.respond_to_cq = respond_to_cq;
@ -753,7 +753,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
*/ */
daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwith_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq); daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq);
}) })
@ -1152,8 +1152,8 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
// SET MODE // SET MODE
document.getElementById("mode").innerHTML = arg.mode; document.getElementById("mode").innerHTML = arg.mode;
// SET BANDWITH // SET bandwidth
document.getElementById("bandwith").innerHTML = arg.bandwith; document.getElementById("bandwidth").innerHTML = arg.bandwidth;
// SET BYTES PER MINUTE // SET BYTES PER MINUTE
if (typeof(arg.arq_bytes_per_minute) == 'undefined') { if (typeof(arg.arq_bytes_per_minute) == 'undefined') {

View file

@ -55,7 +55,7 @@ client.on('connect', function(data) {
//channel_state: "-", //channel_state: "-",
frequency: "-", frequency: "-",
mode: "-", mode: "-",
bandwith: "-", bandwidth: "-",
rms_level: 0 rms_level: 0
}; };
ipcRenderer.send('request-update-tnc-state', Data); ipcRenderer.send('request-update-tnc-state', Data);
@ -84,7 +84,7 @@ client.on('error', function(data) {
//channel_state: "-", //channel_state: "-",
frequency: "-", frequency: "-",
mode: "-", mode: "-",
bandwith: "-", bandwidth: "-",
rms_level: 0 rms_level: 0
}; };
@ -199,7 +199,7 @@ client.on('data', function(socketdata) {
frequency: data['frequency'], frequency: data['frequency'],
speed_level: data['speed_level'], speed_level: data['speed_level'],
mode: data['mode'], mode: data['mode'],
bandwith: data['bandwith'], bandwidth: data['bandwidth'],
rms_level: data['audio_rms'], rms_level: data['audio_rms'],
fft: data['fft'], fft: data['fft'],
channel_busy: data['channel_busy'], channel_busy: data['channel_busy'],

View file

@ -32,7 +32,7 @@
<! ------Chats area ----------------------------------------------------------------------> <! ------Chats area ---------------------------------------------------------------------->
<div class="container-fluid m-0 p-0"> <div class="container-fluid m-0 p-0">
<div class="input-group bottom-0 m-0 w-100"> <div class="input-group bottom-0 m-0 w-100">
<input class="form-control w-50" maxlength="9" style="text-transform:uppercase;" id="chatModuleNewDxCall" placeholder="DX CALL"></input> <input class="form-control w-50" maxlength="9" style="text-transform:uppercase;" id="chatModuleNewDxCall" placeholder="DX CALL">
<button class="btn btn-sm btn-success w-50" id="createNewChatButton" type="button"><i class="bi bi-pencil-square" style="font-size: 1.2rem;"></i></button> <button class="btn btn-sm btn-success w-50" id="createNewChatButton" type="button"><i class="bi bi-pencil-square" style="font-size: 1.2rem;"></i></button>
</div> </div>
</div> </div>
@ -61,7 +61,7 @@
<div class="container-fluid mt-2 p-0"> <div class="container-fluid mt-2 p-0">
<div class="input-group bottom-0 w-100"> <div class="input-group bottom-0 w-100">
<!--<input class="form-control" maxlength="8" style="max-width: 6rem; text-transform:uppercase; display:none" id="chatModuleDxCall" placeholder="DX CALL"></input>--> <!--<input class="form-control" maxlength="8" style="max-width: 6rem; text-transform:uppercase; display:none" id="chatModuleDxCall" placeholder="DX CALL"></input>-->
<!--<button class="btn btn-sm btn-primary me-2" id="emojipickerbutton" type="button">--><i id="emojipickerbutton" class="bi bi-emoji-smile m-1" style="font-size: 1.5rem; color: grey;"></i></button> <!--<button class="btn btn-sm btn-primary me-2" id="emojipickerbutton" type="button">--><i id="emojipickerbutton" class="bi bi-emoji-smile m-1" style="font-size: 1.5rem; color: grey;"></i><!--</button>-->
<!--<input class="form-control rounded-pill m-1 p-1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></input>--> <!--<input class="form-control rounded-pill m-1 p-1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></input>-->
<textarea class="form-control rounded-pill m-1 p-1" rows="1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></textarea> <textarea class="form-control rounded-pill m-1 p-1" rows="1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></textarea>

View file

@ -70,7 +70,7 @@
</button> </button>
</span> </span>
<span data-bs-placement="bottom" data-bs-toggle="tooltip" data-bs-html="false" title="Send files through HF. This is currently under development!"> <span data-bs-placement="bottom" data-bs-toggle="tooltip" data-bs-html="false" title="Send files through HF. This is currently under development!">
<button class="btn btn-sm btn-primary me-2" id="openDataModule" data-bs-toggle="offcanvas" data-bs-target="#transmitFileSidebar" type="button" style="display: None;" disabeld> <strong>TX File </strong> <button class="btn btn-sm btn-primary me-2" id="openDataModule" data-bs-toggle="offcanvas" data-bs-target="#transmitFileSidebar" type="button" style="display: None;"> <strong>TX File </strong>
<i class="bi bi-file-earmark-arrow-up-fill" style="font-size: 1rem; color: white;"></i> <i class="bi bi-file-earmark-arrow-up-fill" style="font-size: 1rem; color: white;"></i>
</button> </button>
</span> </span>
@ -1023,7 +1023,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!--end of blur div --> <!--end of blur div -->
<!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------> <!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------>
<nav class="navbar fixed-bottom navbar-light bg-light"> <nav class="navbar fixed-bottom navbar-light bg-light">
@ -1054,7 +1053,7 @@
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<!--<span class="input-group-text" id="basic-addon1"><strong>Freq</strong></span>--> <span class="input-group-text" id="frequency">---</span> <!--<span class="input-group-text" id="basic-addon1"><strong>Freq</strong></span>--> <span class="input-group-text" id="frequency">---</span>
<!--<span class="input-group-text" id="basic-addon1"><strong>Mode</strong></span>--> <span class="input-group-text" id="mode">---</span> <!--<span class="input-group-text" id="basic-addon1"><strong>Mode</strong></span>--> <span class="input-group-text" id="mode">---</span>
<!--<span class="input-group-text" id="basic-addon1"><strong>BW</strong></span>--> <span class="input-group-text" id="bandwith">---</span> <!--<span class="input-group-text" id="basic-addon1"><strong>BW</strong></span>--> <span class="input-group-text" id="bandwidth">---</span>
</div> </div>
</div> </div>
<div class="container-fluid p-0" style="width:12rem"> <div class="container-fluid p-0" style="width:12rem">

View file

@ -102,7 +102,7 @@ python3 test_tx.py --mode datac1 --delay 500 --frames 2 --bursts 1 | python3 tes
## AUDIO test via virtual audio devices ## AUDIO test via virtual audio devices
### Important: ### Important:
The virtual audio devices are great for testing, but they are also a little bit tricky to handle. So there's a high chance, the tests will fail, if you are running them via virtual audio devices. You should run the tests several times, while keeping this in mind. Most time the ctest is working even if it is failing. The virtual audio devices are great for testing, but they are also a little tricky to handle. So there's a high chance, the tests will fail, if you are running them via virtual audio devices. You should run the tests several times, while keeping this in mind. Most time the ctest is working even if it is failing.
1. Create virtual audio devices. Note: This command needs to be run again after every reboot 1. Create virtual audio devices. Note: This command needs to be run again after every reboot
``` ```

View file

@ -18,6 +18,7 @@ class DEBUGLEVEL(Enum):
RIG_DEBUG_TRACE = 5 RIG_DEBUG_TRACE = 5
RIG_DEBUG_CACHE = 6 RIG_DEBUG_CACHE = 6
class RETCODE(Enum): class RETCODE(Enum):
RIG_OK = 0 RIG_OK = 0
RIG_EINVAL = 1 RIG_EINVAL = 1
@ -38,13 +39,9 @@ class RETCODE(Enum):
RIG_EVFO = 16 RIG_EVFO = 16
RIG_EDOM = 17 RIG_EDOM = 17
libname = pathlib.Path("../tnc/lib/hamlib/linux/libhamlib.so") libname = pathlib.Path("../tnc/lib/hamlib/linux/libhamlib.so")
hamlib = ctypes.CDLL(libname) hamlib = ctypes.CDLL(libname)
class SERIAL(ctypes.Structure): class SERIAL(ctypes.Structure):
_fields_ = [ _fields_ = [
("data_bits", ctypes.c_int), ("data_bits", ctypes.c_int),
@ -53,17 +50,20 @@ class SERIAL(ctypes.Structure):
("parity", ctypes.c_int), ("parity", ctypes.c_int),
("handshake", ctypes.c_void_p), ("handshake", ctypes.c_void_p),
] ]
class PARM(ctypes.Structure): class PARM(ctypes.Structure):
_fields_ = [ _fields_ = [
("serial", SERIAL), ("serial", SERIAL),
] ]
class TYPE(ctypes.Structure): class TYPE(ctypes.Structure):
_fields_ = [ _fields_ = [
("rig", ctypes.c_void_p), ("rig", ctypes.c_void_p),
] ]
class MYPORT(ctypes.Structure): class MYPORT(ctypes.Structure):
_fields_ = [ _fields_ = [
("pathname", ctypes.c_char), ("pathname", ctypes.c_char),
@ -74,16 +74,14 @@ class MYPORT(ctypes.Structure):
] ]
hamlib.rig_set_debug(9) #6 hamlib.rig_set_debug(9) # 6
myrig_model = 3085 #3085 = ICOM 6 = DUMMY myrig_model = 3085 # 3085 = ICOM 6 = DUMMY
myport = MYPORT() myport = MYPORT()
myport.parm.serial.data_bits = 7 myport.parm.serial.data_bits = 7
myport.parm.serial.stop_bits = 2 myport.parm.serial.stop_bits = 2
myport.parm.serial.rate = 9600 myport.parm.serial.rate = 9600
rig = hamlib.rig_init(myrig_model) rig = hamlib.rig_init(myrig_model)
retcode = hamlib.rig_set_parm(rig, 'stop_bits', 5) retcode = hamlib.rig_set_parm(rig, 'stop_bits', 5)
@ -111,15 +109,11 @@ print(retcode)
''' '''
retcode = hamlib.rig_open(rig) retcode = hamlib.rig_open(rig)
print(retcode) print(retcode)
hamlib.rig_close(rig) hamlib.rig_close(rig)
''' '''
# riginfo = create_string_buffer(1024)
# retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
#riginfo = create_string_buffer(1024)
#retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
''' '''
char riginfo[1024]; char riginfo[1024];

View file

@ -188,7 +188,7 @@ for i in range(N_BURSTS):
) # use this if CRC16 checksum is required ( DATA1-3) ) # use this if CRC16 checksum is required ( DATA1-3)
buffer[ buffer[
: len(data_out) : len(data_out)
] = data_out # set buffersize to length of data which will be send ] = data_out # set buffer size to length of data which will be sent
crc = ctypes.c_ushort( crc = ctypes.c_ushort(
c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame) c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)

View file

@ -17,7 +17,7 @@ import threading
import sys import sys
import argparse import argparse
#--------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC') parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int) parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int)
parser.add_argument('--frames', dest="N_FRAMES_PER_BURST", default=0, type=int) parser.add_argument('--frames', dest="N_FRAMES_PER_BURST", default=0, type=int)
@ -44,23 +44,23 @@ DEBUGGING_MODE = args.DEBUGGING_MODE
AUDIO_FRAMES_PER_BUFFER = 2048 AUDIO_FRAMES_PER_BUFFER = 2048
MODEM_SAMPLE_RATE = 8000 MODEM_SAMPLE_RATE = 8000
#-------------------------------------------- LOAD FREEDV # -------------------------------------------- LOAD FREEDV
libname = pathlib.Path().absolute() / "codec2/build_linux/src/libcodec2.so" libname = pathlib.Path().absolute() / "codec2/build_linux/src/libcodec2.so"
c_lib = ctypes.CDLL(libname) c_lib = ctypes.CDLL(libname)
#--------------------------------------------CREATE PYAUDIO INSTANCE # --------------------------------------------CREATE PYAUDIO INSTANCE
p = pyaudio.PyAudio() p = pyaudio.PyAudio()
#--------------------------------------------GET SUPPORTED SAMPLE RATES FROM SOUND DEVICE # --------------------------------------------GET SUPPORTED SAMPLE RATES FROM SOUND DEVICE
#AUDIO_SAMPLE_RATE_TX = int(p.get_device_info_by_index(AUDIO_OUTPUT_DEVICE)['defaultSampleRate']) # AUDIO_SAMPLE_RATE_TX = int(p.get_device_info_by_index(AUDIO_OUTPUT_DEVICE)['defaultSampleRate'])
#AUDIO_SAMPLE_RATE_RX = int(p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['defaultSampleRate']) # AUDIO_SAMPLE_RATE_RX = int(p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['defaultSampleRate'])
AUDIO_SAMPLE_RATE_TX = 8000 AUDIO_SAMPLE_RATE_TX = 8000
AUDIO_SAMPLE_RATE_RX = 8000 AUDIO_SAMPLE_RATE_RX = 8000
#--------------------------------------------OPEN AUDIO CHANNEL RX # --------------------------------------------OPEN AUDIO CHANNEL RX
stream_tx = p.open(format=pyaudio.paInt16, stream_tx = p.open(format=pyaudio.paInt16,
channels=1, channels=1,
rate=AUDIO_SAMPLE_RATE_TX, rate=AUDIO_SAMPLE_RATE_TX,
frames_per_buffer=AUDIO_FRAMES_PER_BUFFER, #n_nom_modem_samples frames_per_buffer=AUDIO_FRAMES_PER_BUFFER, # n_nom_modem_samples
output=True, output=True,
output_device_index=AUDIO_OUTPUT_DEVICE, output_device_index=AUDIO_OUTPUT_DEVICE,
) )
@ -74,7 +74,7 @@ stream_rx = p.open(format=pyaudio.paInt16,
) )
# GENERAL PARAMETERS # GENERAL PARAMETERS
c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte) c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
@ -93,26 +93,26 @@ def send_pong(burst,n_total_burst,frame,n_total_frame):
bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8) bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8)
payload_per_frame = bytes_per_frame -2 payload_per_frame = bytes_per_frame -2
n_nom_modem_samples = c_lib.freedv_get_n_nom_modem_samples(freedv) n_nom_modem_samples = c_lib.freedv_get_n_nom_modem_samples(freedv)
n_tx_modem_samples = c_lib.freedv_get_n_tx_modem_samples(freedv) #get n_tx_modem_samples which defines the size of the modulation object # --> *2 n_tx_modem_samples = c_lib.freedv_get_n_tx_modem_samples(freedv) # get n_tx_modem_samples which defines the size of the modulation object # --> *2
mod_out = ctypes.c_short * n_tx_modem_samples mod_out = ctypes.c_short * n_tx_modem_samples
mod_out = mod_out() mod_out = mod_out()
mod_out_preamble = ctypes.c_short * (1760*2) #1760 for mode 10,11,12 #4000 for mode 9 mod_out_preamble = ctypes.c_short * (1760*2) # 1760 for mode 10,11,12 #4000 for mode 9
mod_out_preamble = mod_out_preamble() mod_out_preamble = mod_out_preamble()
buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3) buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
buffer[:len(data_out)] = data_out # set buffersize to length of data which will be send buffer[:len(data_out)] = data_out # set buffer size to length of data which will be sent
crc = ctypes.c_ushort(c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16 crc = ctypes.c_ushort(c_lib.freedv_gen_crc16(bytes(buffer), payload_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
c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble); c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble);
txbuffer = bytearray() txbuffer = bytearray()
txbuffer += bytes(mod_out_preamble) txbuffer += bytes(mod_out_preamble)
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer) data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
c_lib.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer c_lib.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer
txbuffer += bytes(mod_out) txbuffer += bytes(mod_out)
stream_tx.write(bytes(txbuffer)) stream_tx.write(bytes(txbuffer))
@ -126,30 +126,28 @@ def send_pong(burst,n_total_burst,frame,n_total_frame):
freedv = c_lib.freedv_open(FREEDV_RX_MODE) freedv = c_lib.freedv_open(FREEDV_RX_MODE)
bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8) bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8)
n_max_modem_samples = c_lib.freedv_get_n_max_modem_samples(freedv) n_max_modem_samples = c_lib.freedv_get_n_max_modem_samples(freedv)
bytes_out = (ctypes.c_ubyte * bytes_per_frame) #bytes_per_frame bytes_out = (ctypes.c_ubyte * bytes_per_frame) # bytes_per_frame
bytes_out = bytes_out() #get pointer from bytes_out bytes_out = bytes_out() # get pointer from bytes_out
receive = True receive = True
while receive == True: while receive:
time.sleep(0.01) time.sleep(0.01)
data_in = b'' data_in = b''
nin = c_lib.freedv_nin(freedv) nin = c_lib.freedv_nin(freedv)
nin_converted = int(nin*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE)) nin_converted = int(nin*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE))
if DEBUGGING_MODE == True: if DEBUGGING_MODE:
print("-----------------------------") print("-----------------------------")
print("NIN: " + str(nin) + " [ " + str(nin_converted) + " ]") print("NIN: " + str(nin) + " [ " + str(nin_converted) + " ]")
data_in = stream_rx.read(nin_converted, exception_on_overflow = False) data_in = stream_rx.read(nin_converted, exception_on_overflow = False)
data_in = data_in.rstrip(b'\x00') data_in = data_in.rstrip(b'\x00')
c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), bytes_out, data_in] # check if really neccessary c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), bytes_out, data_in] # check if really neccessary
nbytes = c_lib.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio nbytes = c_lib.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio
if DEBUGGING_MODE == True: if DEBUGGING_MODE:
print("SYNC: " + str(c_lib.freedv_get_rx_status(freedv))) print("SYNC: " + str(c_lib.freedv_get_rx_status(freedv)))
if nbytes == bytes_per_frame: if nbytes == bytes_per_frame:

View file

@ -61,6 +61,7 @@ def test_highsnr_arq_short(freedv_mode: str, n_frames_per_burst: int):
# This test isn't complete yet, or is obsolete. # This test isn't complete yet, or is obsolete.
assert False assert False
if __name__ == "__main__": if __name__ == "__main__":
# Run pytest with the current script as the filename. # Run pytest with the current script as the filename.
ecode = pytest.main(["-v", sys.argv[0]]) ecode = pytest.main(["-v", sys.argv[0]])

View file

@ -14,7 +14,7 @@ import numpy as np
import pytest import pytest
BUFFER_SZ = 1024 BUFFER_SZ = 1024
N_MAX = 100 # write a repeating sequence of 0..N_MAX-1 N_MAX = 100 # write a repeating sequence of 0....N_MAX-1
WRITE_SZ = 10 # different read and write sized buffers WRITE_SZ = 10 # different read and write sized buffers
READ_SZ = 8 READ_SZ = 8
NTESTS = 10000 NTESTS = 10000

View file

@ -72,7 +72,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48 ) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1: if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices

View file

@ -71,7 +71,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48 ) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1: if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices

View file

@ -77,7 +77,7 @@ class Test:
self.resampler = codec2.resampler() self.resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_OUTPUT_DEVICE != -1: if self.AUDIO_OUTPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices
@ -189,7 +189,7 @@ class Test:
payload_per_frame = bytes_per_frame - 2 payload_per_frame = bytes_per_frame - 2
buffer = bytearray(payload_per_frame) buffer = bytearray(payload_per_frame)
# set buffersize to length of data which will be send # set buffer size to length of data which will be sent
buffer[: len(self.data_out)] = self.data_out buffer[: len(self.data_out)] = self.data_out
crc = ctypes.c_ushort( crc = ctypes.c_ushort(

View file

@ -76,7 +76,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48 ) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1: if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices

View file

@ -76,7 +76,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48 ) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1: if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices

View file

@ -82,7 +82,7 @@ class Test:
self.resampler = codec2.resampler() self.resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if self.AUDIO_OUTPUT_DEVICE != -1: if self.AUDIO_OUTPUT_DEVICE != -1:
self.p = pyaudio.PyAudio() self.p = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices
@ -196,7 +196,7 @@ class Test:
) # use this if CRC16 checksum is required ( DATA1-3) ) # use this if CRC16 checksum is required ( DATA1-3)
buffer[ buffer[
: len(self.data_out) : len(self.data_out)
] = self.data_out # set buffersize to length of data which will be send ] = self.data_out # set buffer size to length of data which will be sent
# 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

View file

@ -67,7 +67,7 @@ def test_mm_rx():
resampler = codec2.resampler() resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if AUDIO_INPUT_DEVICE != -1: if AUDIO_INPUT_DEVICE != -1:
p_audio = pyaudio.PyAudio() p_audio = pyaudio.PyAudio()
# auto search for loopback devices # auto search for loopback devices

View file

@ -93,7 +93,7 @@ def test_mm_tx():
payload_per_frame = bytes_per_frame - 2 payload_per_frame = bytes_per_frame - 2
buffer = bytearray(payload_per_frame) buffer = bytearray(payload_per_frame)
# Set buffersize to length of data which will be send # Set buffer size to length of data which will be sent
buffer[: len(data_out)] = data_out buffer[: len(data_out)] = data_out
# Generate CRC16 # Generate CRC16

View file

@ -47,7 +47,7 @@ def test_rx():
# make sure our resampler will work # make sure our resampler will work
assert (AUDIO_SAMPLE_RATE_RX / MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48 assert (AUDIO_SAMPLE_RATE_RX / MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if AUDIO_INPUT_DEVICE != -1: if AUDIO_INPUT_DEVICE != -1:
# auto search for loopback devices # auto search for loopback devices
if AUDIO_INPUT_DEVICE == -2: if AUDIO_INPUT_DEVICE == -2:

View file

@ -107,7 +107,7 @@ def test_valid_disconnect(mycall: str, dxcall: str):
# Set the SSIDs we'll use for this test. # Set the SSIDs we'll use for this test.
static.SSID_LIST = [0, 1, 2, 3, 4] static.SSID_LIST = [0, 1, 2, 3, 4]
# Setup the static parameters for the connection. # set up the static parameters for the connection.
mycallsign_bytes = helpers.callsign_to_bytes(mycall) mycallsign_bytes = helpers.callsign_to_bytes(mycall)
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes) mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
static.MYCALLSIGN = mycallsign static.MYCALLSIGN = mycallsign
@ -160,7 +160,7 @@ def test_foreign_disconnect(mycall: str, dxcall: str):
:return: Bytearray of the requested frame :return: Bytearray of the requested frame
:rtype: bytearray :rtype: bytearray
""" """
# Setup the static parameters for the connection. # set up the static parameters for the connection.
mycallsign_bytes = helpers.callsign_to_bytes(mycall) mycallsign_bytes = helpers.callsign_to_bytes(mycall)
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes) mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
static.MYCALLSIGN = mycallsign static.MYCALLSIGN = mycallsign

View file

@ -37,7 +37,7 @@ def test_tx():
AUDIO_SAMPLE_RATE_TX = 48000 AUDIO_SAMPLE_RATE_TX = 48000
assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0 assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0
# check if we want to use an audio device then do an pyaudio init # check if we want to use an audio device then do a pyaudio init
if AUDIO_OUTPUT_DEVICE != -1: if AUDIO_OUTPUT_DEVICE != -1:
# auto search for loopback devices # auto search for loopback devices
if AUDIO_OUTPUT_DEVICE == -2: if AUDIO_OUTPUT_DEVICE == -2:
@ -109,7 +109,7 @@ def test_tx():
# Create buffer for data # Create buffer for data
# Use this if CRC16 checksum is required (DATA1-3) # Use this if CRC16 checksum is required (DATA1-3)
buffer = bytearray(payload_bytes_per_frame) buffer = bytearray(payload_bytes_per_frame)
# set buffersize to length of data which will be send # set buffer size to length of data which will be sent
buffer[: len(data_out)] = data_out buffer[: len(data_out)] = data_out
# 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

View file

@ -1,22 +1,23 @@
"""
Gather information about audio devices.
"""
import atexit import atexit
import json
import multiprocessing import multiprocessing
import sys
import sounddevice as sd import sounddevice as sd
atexit.register(sd._terminate) atexit.register(sd._terminate)
def get_audio_devices(): def get_audio_devices():
""" """
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
also uses a process data manager also uses a process data manager
""" """
# we need to run this on windows for multiprocessing support # we need to run this on Windows for multiprocessing support
# multiprocessing.freeze_support() # multiprocessing.freeze_support()
#multiprocessing.get_context('spawn') # multiprocessing.get_context("spawn")
# we need to reset and initialize sounddevice before running the multiprocessing part. # we need to reset and initialize sounddevice before running the multiprocessing part.
# If we are not doing this at this early point, not all devices will be displayed # If we are not doing this at this early point, not all devices will be displayed
@ -26,41 +27,41 @@ def get_audio_devices():
with multiprocessing.Manager() as manager: with multiprocessing.Manager() as manager:
proxy_input_devices = manager.list() proxy_input_devices = manager.list()
proxy_output_devices = manager.list() proxy_output_devices = manager.list()
#print(multiprocessing.get_start_method()) # print(multiprocessing.get_start_method())
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices)) proc = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
p.start() proc.start()
p.join() proc.join()
return list(proxy_input_devices), list(proxy_output_devices) return list(proxy_input_devices), list(proxy_output_devices)
def fetch_audio_devices(input_devices, output_devices): def fetch_audio_devices(input_devices, output_devices):
""" """
get audio devices from portaudio get audio devices from portaudio
Args: Args:
input_devices: proxy variable for input devices input_devices: proxy variable for input devices
output_devices: proxy variable for outout devices output_devices: proxy variable for output devices
Returns: Returns:
""" """
devices = sd.query_devices(device=None, kind=None) devices = sd.query_devices(device=None, kind=None)
for index, device in enumerate(devices): for index, device in enumerate(devices):
#for i in range(0, p.get_device_count()): # we need to do a try exception, because for windows there's no audio device range
# we need to do a try exception, beacuse for windows theres no audio device range
try: try:
name = device["name"] name = device["name"]
maxOutputChannels = device["max_output_channels"] max_output_channels = device["max_output_channels"]
maxInputChannels = device["max_input_channels"] max_input_channels = device["max_input_channels"]
except Exception as e: except Exception as err:
print(e) print(err)
maxInputChannels = 0 max_input_channels = 0
maxOutputChannels = 0 max_output_channels = 0
name = '' name = ""
if maxInputChannels > 0: if max_input_channels > 0:
input_devices.append({"id": index, "name": name}) input_devices.append({"id": index, "name": name})
if maxOutputChannels > 0: if max_output_channels > 0:
output_devices.append({"id": index, "name": name}) output_devices.append({"id": index, "name": name})

View file

@ -22,11 +22,11 @@ class FREEDV_MODE(Enum):
""" """
fsk_ldpc_0 = 200 fsk_ldpc_0 = 200
fsk_ldpc_1 = 201 fsk_ldpc_1 = 201
fsk_ldpc = 9 fsk_ldpc = 9
datac0 = 14 datac0 = 14
datac1 = 10 datac1 = 10
datac3 = 12 datac3 = 12
allmodes = 255 allmodes = 255
# Function for returning the mode value # Function for returning the mode value
@ -42,6 +42,7 @@ def freedv_get_mode_value_by_name(mode: str) -> int:
""" """
return FREEDV_MODE[mode].value return FREEDV_MODE[mode].value
# Function for returning the mode name # Function for returning the mode name
def freedv_get_mode_name_by_value(mode: int) -> str: def freedv_get_mode_name_by_value(mode: int) -> str:
""" """
@ -54,6 +55,7 @@ def freedv_get_mode_name_by_value(mode: int) -> str:
""" """
return FREEDV_MODE(mode).name return FREEDV_MODE(mode).name
# 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"))
@ -61,13 +63,13 @@ else:
sys.path.append(os.path.abspath(".")) sys.path.append(os.path.abspath("."))
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...") structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
if sys.platform == 'linux': if sys.platform == "linux":
files = glob.glob(r'**/*libcodec2*',recursive=True) files = glob.glob(r"**/*libcodec2*", recursive=True)
files.append('libcodec2.so') files.append("libcodec2.so")
elif sys.platform == 'darwin': elif sys.platform == "darwin":
files = glob.glob(r'**/*libcodec2*.dylib',recursive=True) files = glob.glob(r"**/*libcodec2*.dylib", recursive=True)
elif sys.platform in ['win32', 'win64']: elif sys.platform in ["win32", "win64"]:
files = glob.glob(r'**\*libcodec2*.dll',recursive=True) files = glob.glob(r"**\*libcodec2*.dll", recursive=True)
else: else:
files = [] files = []
@ -77,18 +79,18 @@ for file in files:
api = ctypes.CDLL(file) api = ctypes.CDLL(file)
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file) structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
break break
except Exception as e: except Exception as err:
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=e) structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=err)
# Quit module if codec2 cant be loaded # Quit module if codec2 cant be loaded
if api is None or 'api' not in locals(): if api is None or "api" not in locals():
structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded") structlog.get_logger("structlog").critical("[C2 ] Libcodec2 not loaded")
sys.exit(1) sys.exit(1)
# ctypes function init # ctypes function init
#api.freedv_set_tuning_range.restype = ctypes.c_int # api.freedv_set_tuning_range.restype = ctypes.c_int
#api.freedv_set_tuning_range.argype = [ctypes.c_void_p, ctypes.c_float, ctypes.c_float] # api.freedv_set_tuning_range.argype = [ctypes.c_void_p, ctypes.c_float, ctypes.c_float]
api.freedv_open.argype = [ctypes.c_int] api.freedv_open.argype = [ctypes.c_int]
api.freedv_open.restype = ctypes.c_void_p api.freedv_open.restype = ctypes.c_void_p
@ -138,12 +140,13 @@ api.freedv_get_n_tx_modem_samples.restype = ctypes.c_int
api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p] api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p]
api.freedv_get_n_max_modem_samples.restype = ctypes.c_int api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
api.FREEDV_FS_8000 = 8000 api.FREEDV_FS_8000 = 8000
api.FREEDV_MODE_DATAC1 = 10 api.FREEDV_MODE_DATAC1 = 10
api.FREEDV_MODE_DATAC3 = 12 api.FREEDV_MODE_DATAC3 = 12
api.FREEDV_MODE_DATAC0 = 14 api.FREEDV_MODE_DATAC0 = 14
api.FREEDV_MODE_FSK_LDPC = 9 api.FREEDV_MODE_FSK_LDPC = 9
# -------------------------------- FSK LDPC MODE SETTINGS # -------------------------------- FSK LDPC MODE SETTINGS
# Advanced structure for fsk modes # Advanced structure for fsk modes
@ -159,14 +162,15 @@ class ADVANCED(ctypes.Structure):
("codename", ctypes.c_char_p), ("codename", ctypes.c_char_p),
] ]
'''
"""
adv.interleave_frames = 0 # max amplitude adv.interleave_frames = 0 # max amplitude
adv.M = 2 # number of fsk tones 2/4 adv.M = 2 # number of fsk tones 2/4
adv.Rs = 100 # symbol rate adv.Rs = 100 # symbol rate
adv.Fs = 8000 # sample rate adv.Fs = 8000 # sample rate
adv.first_tone = 1500 # first tone freq adv.first_tone = 1500 # first tone freq
adv.tone_spacing = 200 # shift between tones adv.tone_spacing = 200 # shift between tones
adv.codename = 'H_128_256_5'.encode('utf-8') # code word adv.codename = "H_128_256_5".encode("utf-8") # code word
HRA_112_112 rate 0.50 (224,112) BPF: 14 not working HRA_112_112 rate 0.50 (224,112) BPF: 14 not working
HRA_56_56 rate 0.50 (112,56) BPF: 7 not working HRA_56_56 rate 0.50 (112,56) BPF: 7 not working
@ -179,16 +183,16 @@ H_128_256_5 rate 0.50 (256,128) BPF: 16 working
H_4096_8192_3d rate 0.50 (8192,4096) BPF: 512 not working H_4096_8192_3d rate 0.50 (8192,4096) BPF: 512 not working
H_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working H_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
''' """
# --------------- 2 FSK H_128_256_5, 16 bytes # --------------- 2 FSK H_128_256_5, 16 bytes
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED() api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED()
api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0 api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0
api.FREEDV_MODE_FSK_LDPC_0_ADV.M = 4 api.FREEDV_MODE_FSK_LDPC_0_ADV.M = 4
api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 100 api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 100
api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000 api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk
api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 #200 api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 # 200
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = 'H_128_256_5'.encode('utf-8') # code word api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = "H_128_256_5".encode("utf-8") # code word
# --------------- 4 H_256_512_4, 7 bytes # --------------- 4 H_256_512_4, 7 bytes
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED() api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED()
@ -196,18 +200,19 @@ api.FREEDV_MODE_FSK_LDPC_1_ADV.interleave_frames = 0
api.FREEDV_MODE_FSK_LDPC_1_ADV.M = 4 api.FREEDV_MODE_FSK_LDPC_1_ADV.M = 4
api.FREEDV_MODE_FSK_LDPC_1_ADV.Rs = 100 api.FREEDV_MODE_FSK_LDPC_1_ADV.Rs = 100
api.FREEDV_MODE_FSK_LDPC_1_ADV.Fs = 8000 api.FREEDV_MODE_FSK_LDPC_1_ADV.Fs = 8000
api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1250 # 1250 4fsk, 1500 2fsk api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1250 # 1250 4fsk, 1500 2fsk
api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200 api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = 'H_256_512_4'.encode('utf-8') # code word api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_256_512_4".encode("utf-8") # code word
# ------- MODEM STATS STRUCTURES # ------- MODEM STATS STRUCTURES
MODEM_STATS_NC_MAX = 50 + 1 MODEM_STATS_NC_MAX = 50 + 1
MODEM_STATS_NR_MAX = 160 MODEM_STATS_NR_MAX = 160
MODEM_STATS_ET_MAX = 8 MODEM_STATS_ET_MAX = 8
MODEM_STATS_EYE_IND_MAX = 160 MODEM_STATS_EYE_IND_MAX = 160
MODEM_STATS_NSPEC = 512 MODEM_STATS_NSPEC = 512
MODEM_STATS_MAX_F_HZ = 4000 MODEM_STATS_MAX_F_HZ = 4000
MODEM_STATS_MAX_F_EST = 4 MODEM_STATS_MAX_F_EST = 4
# Modem stats structure # Modem stats structure
class MODEMSTATS(ctypes.Structure): class MODEMSTATS(ctypes.Structure):
@ -215,7 +220,7 @@ class MODEMSTATS(ctypes.Structure):
_fields_ = [ _fields_ = [
("Nc", ctypes.c_int), ("Nc", ctypes.c_int),
("snr_est", ctypes.c_float), ("snr_est", ctypes.c_float),
("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX), ("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX) * MODEM_STATS_NC_MAX),
("nr", ctypes.c_int), ("nr", ctypes.c_int),
("sync", ctypes.c_int), ("sync", ctypes.c_int),
("foff", ctypes.c_float), ("foff", ctypes.c_float),
@ -225,17 +230,18 @@ class MODEMSTATS(ctypes.Structure):
("pre", ctypes.c_int), ("pre", ctypes.c_int),
("post", ctypes.c_int), ("post", ctypes.c_int),
("uw_fails", ctypes.c_int), ("uw_fails", ctypes.c_int),
("neyetr", ctypes.c_int), # How many eye traces are plotted ("neyetr", ctypes.c_int), # How many eye traces are plotted
("neyesamp", ctypes.c_int), # How many samples in the eye diagram ("neyesamp", ctypes.c_int), # How many samples in the eye diagram
("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), # How many samples in the eye diagram ("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), # How many samples in the eye diagram
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)), ("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
] ]
# Return code flags for freedv_get_rx_status() function # Return code flags for freedv_get_rx_status() function
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
api.FREEDV_RX_BITS = 0x4 # data bits have been returned api.FREEDV_RX_BITS = 0x4 # data bits have been returned
api.FREEDV_RX_BIT_ERRORS = 0x8 # FEC may not have corrected all bit errors (not all parity checks OK) api.FREEDV_RX_BIT_ERRORS = 0x8 # FEC may not have corrected all bit errors (not all parity checks OK)
api.rx_sync_flags_to_text = [ api.rx_sync_flags_to_text = [
"----", "----",
@ -255,13 +261,15 @@ api.rx_sync_flags_to_text = [
"EBS-", "EBS-",
"EBST"] "EBST"]
# Audio buffer --------------------------------------------------------- # Audio buffer ---------------------------------------------------------
class audio_buffer: class audio_buffer:
""" """
Thread safe audio buffer, which fits to needs of codec2 Thread safe audio buffer, which fits to need of codec2
made by David Rowe, VK5DGR made by David Rowe, VK5DGR
""" """
# A buffer of int16 samples, using a fixed length numpy array self.buffer for storage # A buffer of int16 samples, using a fixed length numpy array self.buffer for storage
# self.nbuffer is the current number of samples in the buffer # self.nbuffer is the current number of samples in the buffer
def __init__(self, size): def __init__(self, size):
@ -271,7 +279,7 @@ class audio_buffer:
self.nbuffer = 0 self.nbuffer = 0
self.mutex = Lock() self.mutex = Lock()
def push(self,samples): def push(self, samples):
""" """
Push new data to buffer Push new data to buffer
@ -283,12 +291,12 @@ class audio_buffer:
""" """
self.mutex.acquire() self.mutex.acquire()
# Add samples at the end of the buffer # Add samples at the end of the buffer
assert self.nbuffer+len(samples) <= self.size assert self.nbuffer + len(samples) <= self.size
self.buffer[self.nbuffer:self.nbuffer+len(samples)] = samples self.buffer[self.nbuffer:self.nbuffer + len(samples)] = samples
self.nbuffer += len(samples) self.nbuffer += len(samples)
self.mutex.release() self.mutex.release()
def pop(self,size): def pop(self, size):
""" """
get data from buffer in size of NIN get data from buffer in size of NIN
Args: Args:
@ -300,18 +308,20 @@ class audio_buffer:
self.mutex.acquire() self.mutex.acquire()
# Remove samples from the start of the buffer # Remove samples from the start of the buffer
self.nbuffer -= size self.nbuffer -= size
self.buffer[:self.nbuffer] = self.buffer[size:size+self.nbuffer] self.buffer[:self.nbuffer] = self.buffer[size:size + self.nbuffer]
assert self.nbuffer >= 0 assert self.nbuffer >= 0
self.mutex.release() self.mutex.release()
# Resampler --------------------------------------------------------- # Resampler ---------------------------------------------------------
api.FDMDV_OS_48 = int(6) # oversampling rate api.FDMDV_OS_48 = 6 # oversampling rate
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz api.FDMDV_OS_TAPS_48K = 48 # number of OS filter taps at 48kHz
api.FDMDV_OS_TAPS_48_8K = int(api.FDMDV_OS_TAPS_48K/api.FDMDV_OS_48) # number of OS filter taps at 8kHz api.FDMDV_OS_TAPS_48_8K = api.FDMDV_OS_TAPS_48K // api.FDMDV_OS_48 # number of OS filter taps at 8kHz
api.fdmdv_8_to_48_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] api.fdmdv_8_to_48_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
api.fdmdv_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] api.fdmdv_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
class resampler: class resampler:
""" """
Re-sampler class Re-sampler class
@ -340,7 +350,7 @@ class resampler:
assert len(in48) % api.FDMDV_OS_48 == 0 assert len(in48) % api.FDMDV_OS_48 == 0
# Concatenate filter memory and input samples # Concatenate filter memory and input samples
in48_mem = np.zeros(self.MEM48+len(in48), dtype=np.int16) in48_mem = np.zeros(self.MEM48 + len(in48), dtype=np.int16)
in48_mem[:self.MEM48] = self.filter_mem48 in48_mem[:self.MEM48] = self.filter_mem48
in48_mem[self.MEM48:] = in48 in48_mem[self.MEM48:] = in48
@ -368,14 +378,14 @@ class resampler:
assert in8.dtype == np.int16 assert in8.dtype == np.int16
# Concatenate filter memory and input samples # Concatenate filter memory and input samples
in8_mem = np.zeros(self.MEM8+len(in8), dtype=np.int16) in8_mem = np.zeros(self.MEM8 + len(in8), dtype=np.int16)
in8_mem[:self.MEM8] = self.filter_mem8 in8_mem[:self.MEM8] = self.filter_mem8
in8_mem[self.MEM8:] = in8 in8_mem[self.MEM8:] = in8
# In C: pin8=&in8_mem[MEM8] # In C: pin8=&in8_mem[MEM8]
pin8 = ctypes.byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8) pin8 = ctypes.byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8)
out48 = np.zeros(api.FDMDV_OS_48*len(in8), dtype=np.int16) out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16)
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8)); api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8))
# Store memory for next time # Store memory for next time
self.filter_mem8 = in8_mem[:self.MEM8] self.filter_mem8 = in8_mem[:self.MEM8]

View file

@ -15,8 +15,6 @@ import argparse
import atexit import atexit
import multiprocessing import multiprocessing
import os import os
import queue
import re
import signal import signal
import socketserver import socketserver
import subprocess import subprocess
@ -24,17 +22,14 @@ import sys
import threading import threading
import time import time
import crcengine
import psutil
import serial.tools.list_ports
import structlog
import ujson as json
import audio import audio
import helpers import crcengine
import log_handler import log_handler
import serial.tools.list_ports
import sock import sock
import static import static
import structlog
import ujson as json
# signal handler for closing aplication # signal handler for closing aplication
@ -47,20 +42,24 @@ def signal_handler(sig, frame):
Returns: system exit Returns: system exit
""" """
print('Closing daemon...') print("Closing daemon...")
sock.CLOSE_SIGNAL = True sock.CLOSE_SIGNAL = True
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
class DAEMON():
class DAEMON:
""" """
Daemon class Daemon class
""" """
log = structlog.get_logger("DAEMON")
def __init__(self): def __init__(self):
# load crc engine # load crc engine
self.crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc8 library self.crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library
self.daemon_queue = sock.DAEMON_QUEUE self.daemon_queue = sock.DAEMON_QUEUE
update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True) update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True)
@ -76,12 +75,12 @@ class DAEMON():
""" """
Update audio devices and set to static Update audio devices and set to static
""" """
while 1: while True:
try: try:
if not static.TNCSTARTED: if not static.TNCSTARTED:
static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices() static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices()
except Exception as e: except Exception as err1:
structlog.get_logger("structlog").error("[DMN] update_audio_devices: Exception gathering audio devices:", e=e) self.log.error("[DMN] update_audio_devices: Exception gathering audio devices:", e=err1)
# print(e) # print(e)
time.sleep(1) time.sleep(1)
@ -89,30 +88,29 @@ class DAEMON():
""" """
Update serial devices and set to static Update serial devices and set to static
""" """
while 1: while True:
try: try:
#print("update serial")
serial_devices = [] serial_devices = []
ports = serial.tools.list_ports.comports() ports = serial.tools.list_ports.comports()
for port, desc, hwid in ports: for port, desc, hwid in ports:
# calculate hex of hwid if we have unique names # calculate hex of hwid if we have unique names
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8')) crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
crc_hwid = crc_hwid.to_bytes(2, byteorder='big') crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
crc_hwid = crc_hwid.hex() crc_hwid = crc_hwid.hex()
description = f"{desc} [{crc_hwid}]" description = f"{desc} [{crc_hwid}]"
serial_devices.append({"port": str(port), "description": str(description) }) serial_devices.append({"port": str(port), "description": str(description)})
static.SERIAL_DEVICES = serial_devices static.SERIAL_DEVICES = serial_devices
time.sleep(1) time.sleep(1)
except Exception as e: except Exception as err1:
structlog.get_logger("structlog").error("[DMN] update_serial_devices: Exception gathering serial devices:", e=e) self.log.error("[DMN] update_serial_devices: Exception gathering serial devices:", e=err1)
# print(e) # print(e)
def worker(self): def worker(self):
""" """
Worker to handle the received commands Worker to handle the received commands
""" """
while 1: while True:
try: try:
data = self.daemon_queue.get() data = self.daemon_queue.get()
@ -133,138 +131,138 @@ class DAEMON():
# data[15] rigctld_port # data[15] rigctld_port
# data[16] send_scatter # data[16] send_scatter
# data[17] send_fft # data[17] send_fft
# data[18] low_bandwith_mode # data[18] low_bandwidth_mode
# data[19] tuning_range_fmin # data[19] tuning_range_fmin
# data[20] tuning_range_fmax # data[20] tuning_range_fmax
# data[21] enable FSK # data[21] enable FSK
# data[22] tx-audio-level # data[22] tx-audio-level
# data[23] respond_to_cq # data[23] respond_to_cq
if data[0] == 'STARTTNC': if data[0] == "STARTTNC":
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6]) self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6])
# list of parameters, necessary for running subprocess command as a list # list of parameters, necessary for running subprocess command as a list
options = [] options = []
options.append('--port') options.append("--port")
options.append(str(static.DAEMONPORT - 1)) options.append(str(static.DAEMONPORT - 1))
options.append('--mycall') options.append("--mycall")
options.append(data[1]) options.append(data[1])
options.append('--mygrid') options.append("--mygrid")
options.append(data[2]) options.append(data[2])
options.append('--rx') options.append("--rx")
options.append(data[3]) options.append(data[3])
options.append('--tx') options.append("--tx")
options.append(data[4]) options.append(data[4])
# if radiocontrol != disabled # if radiocontrol != disabled
# this should hopefully avoid a ton of problems if we are just running in # this should hopefully avoid a ton of problems if we are just running in
# disabled mode # disabled mode
if data[13] != 'disabled': if data[13] != "disabled":
options.append('--devicename') options.append("--devicename")
options.append(data[5]) options.append(data[5])
options.append('--deviceport') options.append("--deviceport")
options.append(data[6]) options.append(data[6])
options.append('--serialspeed') options.append("--serialspeed")
options.append(data[7]) options.append(data[7])
options.append('--pttprotocol') options.append("--pttprotocol")
options.append(data[8]) options.append(data[8])
options.append('--pttport') options.append("--pttport")
options.append(data[9]) options.append(data[9])
options.append('--data_bits') options.append("--data_bits")
options.append(data[10]) options.append(data[10])
options.append('--stop_bits') options.append("--stop_bits")
options.append(data[11]) options.append(data[11])
options.append('--handshake') options.append("--handshake")
options.append(data[12]) options.append(data[12])
options.append('--radiocontrol') options.append("--radiocontrol")
options.append(data[13]) options.append(data[13])
if data[13] == 'rigctld': if data[13] == "rigctld":
options.append('--rigctld_ip') options.append("--rigctld_ip")
options.append(data[14]) options.append(data[14])
options.append('--rigctld_port') options.append("--rigctld_port")
options.append(data[15]) options.append(data[15])
if data[16] == 'True': if data[16] == "True":
options.append('--scatter') options.append("--scatter")
if data[17] == 'True': if data[17] == "True":
options.append('--fft') options.append("--fft")
if data[18] == 'True': if data[18] == "True":
options.append('--500hz') options.append("--500hz")
options.append('--tuning_range_fmin') options.append("--tuning_range_fmin")
options.append(data[19]) options.append(data[19])
options.append('--tuning_range_fmax') options.append("--tuning_range_fmax")
options.append(data[20]) options.append(data[20])
# overriding FSK mode # overriding FSK mode
#if data[21] == 'True': # if data[21] == "True":
# options.append('--fsk') # options.append("--fsk")
options.append('--tx-audio-level') options.append("--tx-audio-level")
options.append(data[22]) options.append(data[22])
if data[23] == 'True': if data[23] == "True":
options.append('--qrv') options.append("--qrv")
# Try running tnc from binary, else run from source # Try running tnc from binary, else run from source
# This helps running the tnc in a developer environment # This helps running the tnc in a developer environment
try: try:
command = [] command = []
if sys.platform in ['linux', 'darwin']: if sys.platform in ["linux", "darwin"]:
command.append('./freedata-tnc') command.append("./freedata-tnc")
elif sys.platform in ['win32', 'win64']: elif sys.platform in ["win32", "win64"]:
command.append('freedata-tnc.exe') command.append("freedata-tnc.exe")
command += options command += options
p = subprocess.Popen(command) proc = subprocess.Popen(command)
atexit.register(p.kill) atexit.register(proc.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary") self.log.info("[DMN] TNC started", path="binary")
except FileNotFoundError as e: except FileNotFoundError as err1:
structlog.get_logger("structlog").error("[DMN] worker: Exception:", e=e) self.log.error("[DMN] worker: Exception:", e=err1)
command = [] command = []
if sys.platform in ['linux', 'darwin']: if sys.platform in ["linux", "darwin"]:
command.append('python3') command.append("python3")
elif sys.platform in ['win32', 'win64']: elif sys.platform in ["win32", "win64"]:
command.append('python') command.append("python")
command.append('main.py') command.append("main.py")
command += options command += options
p = subprocess.Popen(command) proc = subprocess.Popen(command)
atexit.register(p.kill) atexit.register(proc.kill)
structlog.get_logger("structlog").info("[DMN] TNC started", path="source") self.log.info("[DMN] TNC started", path="source")
static.TNCPROCESS = p # .pid static.TNCPROCESS = proc
static.TNCSTARTED = True static.TNCSTARTED = True
''' """
# WE HAVE THIS PART in SOCKET # WE HAVE THIS PART in SOCKET
if data[0] == 'STOPTNC': if data[0] == "STOPTNC":
static.TNCPROCESS.kill() static.TNCPROCESS.kill()
structlog.get_logger("structlog").warning("[DMN] Stopping TNC") self.log.warning("[DMN] Stopping TNC")
#os.kill(static.TNCPROCESS, signal.SIGKILL) #os.kill(static.TNCPROCESS, signal.SIGKILL)
static.TNCSTARTED = False static.TNCSTARTED = False
''' """
# data[1] devicename # data[1] devicename
# data[2] deviceport # data[2] deviceport
# data[3] serialspeed # data[3] serialspeed
@ -276,7 +274,7 @@ class DAEMON():
# data[9] radiocontrol # data[9] radiocontrol
# data[10] rigctld_ip # data[10] rigctld_ip
# data[11] rigctld_port # data[11] rigctld_port
if data[0] == 'TEST_HAMLIB': if data[0] == "TEST_HAMLIB":
devicename = data[1] devicename = data[1]
deviceport = data[2] deviceport = data[2]
serialspeed = data[3] serialspeed = data[3]
@ -290,11 +288,11 @@ class DAEMON():
rigctld_port = data[11] rigctld_port = data[11]
# check how we want to control the radio # check how we want to control the radio
if radiocontrol == 'direct': if radiocontrol == "direct":
import rig import rig
elif radiocontrol == 'rigctl': elif radiocontrol == "rigctl":
import rigctl as rig import rigctl as rig
elif radiocontrol == 'rigctld': elif radiocontrol == "rigctld":
import rigctld as rig import rigctld as rig
else: else:
import rigdummy as rig import rigdummy as rig
@ -304,20 +302,20 @@ class DAEMON():
serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits, serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits,
handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port) handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port)
hamlib_version = rig.hamlib_version # hamlib_version = rig.hamlib_version
hamlib.set_ptt(True) hamlib.set_ptt(True)
pttstate = hamlib.get_ptt() pttstate = hamlib.get_ptt()
if pttstate: if pttstate:
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status='SUCCESS') self.log.info("[DMN] Hamlib PTT", status="SUCCESS")
response = {'command': 'test_hamlib', 'result': 'SUCCESS'} response = {"command": "test_hamlib", "result": "SUCCESS"}
elif not pttstate: elif not pttstate:
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status='NO SUCCESS') self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS")
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'} response = {"command": "test_hamlib", "result": "NOSUCCESS"}
else: else:
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status='FAILED') self.log.error("[DMN] Hamlib PTT", status="FAILED")
response = {'command': 'test_hamlib', 'result': 'FAILED'} response = {"command": "test_hamlib", "result": "FAILED"}
hamlib.set_ptt(False) hamlib.set_ptt(False)
hamlib.close_rig() hamlib.close_rig()
@ -325,39 +323,40 @@ class DAEMON():
jsondata = json.dumps(response) jsondata = json.dumps(response)
sock.SOCKET_QUEUE.put(jsondata) sock.SOCKET_QUEUE.put(jsondata)
except Exception as e: except Exception as err1:
structlog.get_logger("structlog").error("[DMN] worker: Exception: ", e=e) self.log.error("[DMN] worker: Exception: ", e=err1)
# print(e)
if __name__ == '__main__':
# we need to run this on windows for multiprocessing support if __name__ == "__main__":
mainlog = structlog.get_logger(__file__)
# we need to run this on Windows for multiprocessing support
multiprocessing.freeze_support() multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='FreeDATA Daemon') PARSER = argparse.ArgumentParser(description="FreeDATA Daemon")
PARSER.add_argument('--port', dest="socket_port", default=3001, help="Socket port in the range of 1024-65536", type=int) PARSER.add_argument("--port", dest="socket_port", default=3001, help="Socket port in the range of 1024-65536", type=int)
ARGS = PARSER.parse_args() ARGS = PARSER.parse_args()
static.DAEMONPORT = ARGS.socket_port static.DAEMONPORT = ARGS.socket_port
try: try:
if sys.platform == 'linux': if sys.platform == "linux":
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon' logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
if sys.platform == 'darwin': if sys.platform == "darwin":
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon' logging_path = os.getenv("HOME") + "/Library/" + "Application Support/" + "FreeDATA/" + "daemon"
if sys.platform in ['win32', 'win64']: if sys.platform in ["win32", "win64"]:
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon' logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
if not os.path.exists(logging_path): if not os.path.exists(logging_path):
os.makedirs(logging_path) os.makedirs(logging_path)
log_handler.setup_logging(logging_path) log_handler.setup_logging(logging_path)
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e) mainlog.error("[DMN] logger init error", exception=err)
try: try:
structlog.get_logger("structlog").info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT) mainlog.info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
# https://stackoverflow.com/a/16641793 # https://stackoverflow.com/a/16641793
socketserver.TCPServer.allow_reuse_address = True socketserver.TCPServer.allow_reuse_address = True
cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler) cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler)
@ -365,11 +364,11 @@ if __name__ == '__main__':
server_thread.daemon = True server_thread.daemon = True
server_thread.start() server_thread.start()
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e) mainlog.error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err)
sys.exit(1) sys.exit(1)
daemon = DAEMON() daemon = DAEMON()
structlog.get_logger("structlog").info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION) mainlog.info("[DMN] Starting FreeDATA Daemon", author="DJ2LS", year="2022", version=static.VERSION)
while True: while True:
time.sleep(1) time.sleep(1)

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Fri Dec 25 21:25:14 2020 Created on Fri Dec 25 21:25:14 2020
@ -8,9 +7,8 @@ Created on Fri Dec 25 21:25:14 2020
import time import time
import crcengine import crcengine
import structlog
import static import static
import structlog
def wait(seconds: float) -> bool: def wait(seconds: float) -> bool:
@ -27,6 +25,7 @@ def wait(seconds: float) -> bool:
time.sleep(0.01) time.sleep(0.01)
return True return True
def get_crc_8(data) -> bytes: def get_crc_8(data) -> bytes:
"""Author: DJ2LS """Author: DJ2LS
@ -40,11 +39,12 @@ def get_crc_8(data) -> bytes:
Returns: Returns:
CRC-8 (CCITT) of the provided data as bytes CRC-8 (CCITT) of the provided data as bytes
""" """
crc_algorithm = crcengine.new('crc8-ccitt') # load crc8 library crc_algorithm = crcengine.new("crc8-ccitt") # load crc8 library
crc_data = crc_algorithm(data) crc_data = crc_algorithm(data)
crc_data = crc_data.to_bytes(1, byteorder='big') crc_data = crc_data.to_bytes(1, byteorder="big")
return crc_data return crc_data
def get_crc_16(data) -> bytes: def get_crc_16(data) -> bytes:
"""Author: DJ2LS """Author: DJ2LS
@ -58,11 +58,12 @@ def get_crc_16(data) -> bytes:
Returns: Returns:
CRC-16 (CCITT) of the provided data as bytes CRC-16 (CCITT) of the provided data as bytes
""" """
crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc16 library crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library
crc_data = crc_algorithm(data) crc_data = crc_algorithm(data)
crc_data = crc_data.to_bytes(2, byteorder='big') crc_data = crc_data.to_bytes(2, byteorder="big")
return crc_data return crc_data
def get_crc_24(data) -> bytes: def get_crc_24(data) -> bytes:
"""Author: DJ2LS """Author: DJ2LS
@ -77,13 +78,18 @@ 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
def get_crc_32(data: bytes) -> bytes: def get_crc_32(data: bytes) -> bytes:
"""Author: DJ2LS """Author: DJ2LS
@ -97,11 +103,12 @@ def get_crc_32(data: bytes) -> bytes:
Returns: Returns:
CRC-32 of the provided data as bytes CRC-32 of the provided data as bytes
""" """
crc_algorithm = crcengine.new('crc32') # load crc32 library crc_algorithm = crcengine.new("crc32") # load crc32 library
crc_data = crc_algorithm(data) crc_data = crc_algorithm(data)
crc_data = crc_data.to_bytes(4, byteorder='big') crc_data = crc_data.to_bytes(4, byteorder="big")
return crc_data return crc_data
def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency): def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
""" """
@ -131,11 +138,13 @@ 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())]
# static.HEARD_STATIONS[idx] = item # static.HEARD_STATIONS[idx] = item
def callsign_to_bytes(callsign) -> bytes: def callsign_to_bytes(callsign) -> bytes:
""" """
@ -146,48 +155,48 @@ def callsign_to_bytes(callsign) -> bytes:
""" """
# http://www.aprs.org/aprs11/SSIDs.txt # http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable # -0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc # -1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc # -2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc # -3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc # -4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc) # -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc # -6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable # -7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile # -8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable) # -9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc # -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc # -11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc # -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations # -13 Weather stations
#-14 Truckers or generally full time drivers # -14 Truckers or generally full time drivers
#-15 generic additional station, digi, mobile, wx, etc # -15 generic additional station, digi, mobile, wx, etc
# Try converting to bytestring if possible type string # Try converting to bytestring if possible type string
try: try:
callsign = bytes(callsign, 'utf-8') callsign = bytes(callsign, "utf-8")
except TypeError as e: except TypeError as err:
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=err)
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"-")
ssid = 0 ssid = 0
try: try:
ssid = int(callsign[1]) ssid = int(callsign[1])
except IndexError as e: except IndexError as err:
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=e) structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
#callsign = callsign[0] # callsign = callsign[0]
#bytestring = bytearray(8) # bytestring = bytearray(8)
#bytestring[:len(callsign)] = callsign # bytestring[:len(callsign)] = callsign
#bytestring[7:8] = bytes([ssid]) # bytestring[7:8] = bytes([ssid])
# ---- callsign with encoding always 6 bytes long # ---- callsign with encoding always 6 bytes long
callsign = callsign[0].decode("utf-8") callsign = callsign[0].decode("utf-8")
ssid = bytes([ssid]).decode("utf-8") ssid = bytes([ssid]).decode("utf-8")
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:
""" """
@ -200,42 +209,43 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
bytes bytes
""" """
# http://www.aprs.org/aprs11/SSIDs.txt # http://www.aprs.org/aprs11/SSIDs.txt
#-0 Your primary station usually fixed and message capable # -0 Your primary station usually fixed and message capable
#-1 generic additional station, digi, mobile, wx, etc # -1 generic additional station, digi, mobile, wx, etc
#-2 generic additional station, digi, mobile, wx, etc # -2 generic additional station, digi, mobile, wx, etc
#-3 generic additional station, digi, mobile, wx, etc # -3 generic additional station, digi, mobile, wx, etc
#-4 generic additional station, digi, mobile, wx, etc # -4 generic additional station, digi, mobile, wx, etc
#-5 Other networks (Dstar, Iphones, Androids, Blackberry's etc) # -5 Other networks (Dstar, Iphones, Androids, Blackberry's etc)
#-6 Special activity, Satellite ops, camping or 6 meters, etc # -6 Special activity, Satellite ops, camping or 6 meters, etc
#-7 walkie talkies, HT's or other human portable # -7 walkie talkies, HT's or other human portable
#-8 boats, sailboats, RV's or second main mobile # -8 boats, sailboats, RV's or second main mobile
#-9 Primary Mobile (usually message capable) # -9 Primary Mobile (usually message capable)
#-10 internet, Igates, echolink, winlink, AVRS, APRN, etc # -10 internet, Igates, echolink, winlink, AVRS, APRN, etc
#-11 balloons, aircraft, spacecraft, etc # -11 balloons, aircraft, spacecraft, etc
#-12 APRStt, DTMF, RFID, devices, one-way trackers*, etc # -12 APRStt, DTMF, RFID, devices, one-way trackers*, etc
#-13 Weather stations # -13 Weather stations
#-14 Truckers or generally full time drivers # -14 Truckers or generally full time drivers
#-15 generic additional station, digi, mobile, wx, etc # -15 generic additional station, digi, mobile, wx, etc
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign ) # we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
''' """
callsign = bytes(bytestring[:7]) callsign = bytes(bytestring[:7])
callsign = callsign.rstrip(b'\x00') callsign = callsign.rstrip(b"\x00")
ssid = int.from_bytes(bytes(bytestring[7:8]), "big") ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
callsign = callsign + b'-' callsign = callsign + b"-"
callsign = callsign.decode('utf-8') callsign = callsign.decode("utf-8")
callsign = callsign + str(ssid) callsign = callsign + str(ssid)
callsign = callsign.encode('utf-8') callsign = callsign.encode("utf-8")
return bytes(callsign) return bytes(callsign)
''' """
decoded = decode_call(bytestring) decoded = decode_call(bytestring)
callsign = decoded[:-1] callsign = decoded[:-1]
ssid = ord(bytes(decoded[-1], "utf-8")) ssid = ord(bytes(decoded[-1], "utf-8"))
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
@ -248,19 +258,18 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
False False
""" """
# print(callsign)
structlog.get_logger("structlog").debug("[HLP] check_callsign: Checking:", callsign=callsign) structlog.get_logger("structlog").debug("[HLP] check_callsign: Checking:", callsign=callsign)
try: try:
# We want the callsign without SSID # We want the callsign without SSID
callsign = callsign.split(b'-')[0] callsign = callsign.split(b"-")[0]
except Exception as e: except Exception as err:
structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=e) structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=err)
for ssid in static.SSID_LIST: for ssid in static.SSID_LIST:
call_with_ssid = bytearray(callsign) call_with_ssid = bytearray(callsign)
call_with_ssid.extend('-'.encode('utf-8')) call_with_ssid.extend("-".encode("utf-8"))
call_with_ssid.extend(str(ssid).encode('utf-8')) call_with_ssid.extend(str(ssid).encode("utf-8"))
callsign_crc = get_crc_24(call_with_ssid) callsign_crc = get_crc_24(call_with_ssid)
@ -270,9 +279,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
return [False, ""] return [False, ""]
def encode_grid(grid): def encode_grid(grid):
""" """
@auther: DB1UJ @author: DB1UJ
Args: Args:
grid:string: maidenhead QTH locater [a-r][a-r][0-9][0-9][a-x][a-x] grid:string: maidenhead QTH locater [a-r][a-r][0-9][0-9][a-x][a-x]
Returns: Returns:
@ -280,38 +290,39 @@ 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):
""" """
@auther: DB1UJ @author: DB1UJ
Args: Args:
b_code_word:bytes: 4 bytes with 26 bit valid data LSB b_code_word:bytes: 4 bytes with 26 bit valid data LSB
Returns: Returns:
grid:str: upper case maidenhead QTH locater [A-R][A-R][0-9][0-9][A-X][A-X] grid:str: upper case maidenhead QTH locater [A-R][A-R][0-9][0-9][A-X][A-X]
""" """
code_word = int.from_bytes(b_code_word, byteorder='big', signed=False) code_word = int.from_bytes(b_code_word, byteorder="big", signed=False)
grid = chr((code_word & 0b11111) + 65) grid = chr((code_word & 0b11111) + 65)
code_word >>= 5 code_word >>= 5
@ -321,7 +332,7 @@ def decode_grid(b_code_word:bytes):
grid = str(int(code_word & 0b1111111)) + grid grid = str(int(code_word & 0b1111111)) + grid
if (code_word & 0b1111111) < 10: if (code_word & 0b1111111) < 10:
grid = f'0{grid}' grid = f"0{grid}"
code_word >>= 9 code_word >>= 9
int_val = int(code_word & 0b111111111) int_val = int(code_word & 0b111111111)
@ -332,9 +343,10 @@ def decode_grid(b_code_word:bytes):
return grid return grid
def encode_call(call): def encode_call(call):
""" """
@auther: DB1UJ @author: DB1UJ
Args: Args:
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63 call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
@ -343,35 +355,37 @@ 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
out_code_word <<= 6 # shift left 6 bit, making space for a new char out_code_word <<= 6 # shift left 6 bit, making space for a new char
out_code_word |= (int_val & 0b111111) # bit OR adds the new char, masked with AND 0b111111 out_code_word |= (int_val & 0b111111) # bit OR adds the new char, masked with AND 0b111111
out_code_word >>= 6 # clean last char
out_code_word <<= 6 # make clean space
out_code_word |= (ord(call[-1]) & 0b111111) # add the SSID uncoded only 0 - 63
return out_code_word.to_bytes(length=6, byteorder='big') out_code_word >>= 6 # clean last char
out_code_word <<= 6 # make clean space
out_code_word |= (ord(call[-1]) & 0b111111) # add the SSID uncoded only 0 - 63
def decode_call(b_code_word:bytes): return out_code_word.to_bytes(length=6, byteorder="big")
def decode_call(b_code_word: bytes):
""" """
@auther: DB1UJ @author: DB1UJ
Args: Args:
b_code_word:bytes: 6 bytes with 6 bits/sign valid data char signs LSB b_code_word:bytes: 6 bytes with 6 bits/sign valid data char signs LSB
Returns: Returns:
call:str: upper case ham radio call sign [A-Z,0-9] + binary SSID call:str: upper case ham radio call sign [A-Z,0-9] + binary SSID
""" """
code_word = int.from_bytes(b_code_word, byteorder='big', signed=False) code_word = int.from_bytes(b_code_word, byteorder="big", signed=False)
ssid = chr(code_word & 0b111111) # save the uncoded binary SSID ssid = chr(code_word & 0b111111) # save the uncoded binary SSID
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
return call return call

View file

@ -1,3 +1,8 @@
import logging.config
import structlog
# https://www.structlog.org/en/stable/standard-library.html # https://www.structlog.org/en/stable/standard-library.html
def setup_logging(filename): def setup_logging(filename):
""" """
@ -8,8 +13,6 @@ def setup_logging(filename):
Returns: Returns:
""" """
import logging.config
import structlog
timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S")
pre_chain = [ pre_chain = [
@ -19,7 +22,8 @@ def setup_logging(filename):
timestamper, timestamper,
] ]
logging.config.dictConfig({ logging.config.dictConfig(
{
"version": 1, "version": 1,
"disable_existing_loggers": False, "disable_existing_loggers": False,
"formatters": { "formatters": {
@ -43,7 +47,7 @@ def setup_logging(filename):
"file": { "file": {
"level": "DEBUG", "level": "DEBUG",
"class": "logging.handlers.WatchedFileHandler", "class": "logging.handlers.WatchedFileHandler",
"filename": filename + '.log', "filename": f"{filename}.log",
"formatter": "plain", "formatter": "plain",
}, },
}, },
@ -53,8 +57,9 @@ def setup_logging(filename):
"level": "DEBUG", "level": "DEBUG",
"propagate": True, "propagate": True,
}, },
} },
}) }
)
structlog.configure( structlog.configure(
processors=[ processors=[
structlog.stdlib.add_log_level, structlog.stdlib.add_log_level,

View file

@ -16,15 +16,14 @@ import sys
import threading import threading
import time import time
import structlog
import data_handler import data_handler
import helpers import helpers
import log_handler import log_handler
import modem import modem
import static import static
import structlog
# 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
@ -35,56 +34,57 @@ def signal_handler(sig, frame):
Returns: system exit Returns: system exit
""" """
print('Closing TNC...') print("Closing TNC...")
sock.CLOSE_SIGNAL = True sock.CLOSE_SIGNAL = True
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
if __name__ == '__main__': if __name__ == "__main__":
# we need to run this on windows for multiprocessing support # we need to run this on Windows for multiprocessing support
multiprocessing.freeze_support() multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS # --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='FreeDATA TNC') PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str) PARSER.add_argument("--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)
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int) PARSER.add_argument("--port", dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int)
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str) PARSER.add_argument("--deviceport", dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
PARSER.add_argument('--devicename', dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str) PARSER.add_argument("--devicename", dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str)
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int) PARSER.add_argument("--serialspeed", dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int)
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", choices=['USB', 'RIG', 'RTS', 'DTR', 'CM108', 'MICDATA', 'PARALLEL', 'DTR-H', 'DTR-L', 'NONE'], default='USB', help="PTT Type", type=str) PARSER.add_argument("--pttprotocol", dest="hamlib_ptt_type", choices=["USB", "RIG", "RTS", "DTR", "CM108", "MICDATA", "PARALLEL", "DTR-H", "DTR-L", "NONE"], default="USB", help="PTT Type", type=str)
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str) PARSER.add_argument("--pttport", dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int) PARSER.add_argument("--data_bits", dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int)
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int) PARSER.add_argument("--stop_bits", dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int)
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str) PARSER.add_argument("--handshake", dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
PARSER.add_argument('--radiocontrol', dest="hamlib_radiocontrol", choices=['disabled', 'direct', 'rigctl', 'rigctld'], default="disabled", help="Set how you want to control your radio") PARSER.add_argument("--radiocontrol", dest="hamlib_radiocontrol", choices=["disabled", "direct", "rigctl", "rigctld"], default="disabled", help="Set how you want to control your radio")
PARSER.add_argument('--rigctld_port', dest="rigctld_port", default=4532, type=int, help="Set rigctld port") PARSER.add_argument("--rigctld_port", dest="rigctld_port", default=4532, type=int, help="Set rigctld port")
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="localhost", help="Set rigctld ip") PARSER.add_argument("--rigctld_ip", dest="rigctld_ip", default="localhost", help="Set rigctld ip")
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network") PARSER.add_argument("--scatter", dest="send_scatter", action="store_true", help="Send scatter information via network")
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network") PARSER.add_argument("--fft", dest="send_fft", action="store_true", help="Send fft information via network")
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )") PARSER.add_argument("--500hz", dest="low_bandwidth_mode", action="store_true", help="Enable low bandwidth mode ( 500 Hz only )")
PARSER.add_argument('--fsk', dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ") PARSER.add_argument("--fsk", dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ")
PARSER.add_argument('--qrv', dest="enable_respond_to_cq", action="store_true", help="Enable sending a QRV frame if CQ received") PARSER.add_argument("--qrv", dest="enable_respond_to_cq", action="store_true", help="Enable sending a QRV frame if CQ received")
PARSER.add_argument('--tuning_range_fmin', dest="tuning_range_fmin", choices=[-50.0, -100.0, -150.0, -200.0, -250.0], default=-50.0, help="Tuning range fmin", type=float) PARSER.add_argument("--tuning_range_fmin", dest="tuning_range_fmin", choices=[-50.0, -100.0, -150.0, -200.0, -250.0], default=-50.0, help="Tuning range fmin", type=float)
PARSER.add_argument('--tuning_range_fmax', dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float) PARSER.add_argument("--tuning_range_fmax", dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float)
PARSER.add_argument('--tx-audio-level', dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int) PARSER.add_argument("--tx-audio-level", dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int)
ARGS = PARSER.parse_args() ARGS = PARSER.parse_args()
# additional step for beeing sure our callsign is correctly # additional step for being sure our callsign is correctly
# in case we are not getting a station ssid # in case we are not getting a station ssid
# then we are forcing a station ssid = 0 # then we are forcing a station ssid = 0
mycallsign = bytes(ARGS.mycall.upper(), 'utf-8') mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
mycallsign = helpers.callsign_to_bytes(mycallsign) mycallsign = helpers.callsign_to_bytes(mycallsign)
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign) static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN) static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
static.SSID_LIST = ARGS.ssid_list static.SSID_LIST = ARGS.ssid_list
static.MYGRID = bytes(ARGS.mygrid, 'utf-8') static.MYGRID = bytes(ARGS.mygrid, "utf-8")
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
static.PORT = ARGS.socket_port static.PORT = ARGS.socket_port
@ -102,7 +102,7 @@ if __name__ == '__main__':
static.ENABLE_SCATTER = ARGS.send_scatter static.ENABLE_SCATTER = ARGS.send_scatter
static.ENABLE_FFT = ARGS.send_fft static.ENABLE_FFT = ARGS.send_fft
static.ENABLE_FSK = ARGS.enable_fsk static.ENABLE_FSK = ARGS.enable_fsk
static.LOW_BANDWITH_MODE = ARGS.low_bandwith_mode static.LOW_BANDWIDTH_MODE = ARGS.low_bandwidth_mode
static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
@ -113,20 +113,20 @@ if __name__ == '__main__':
# config logging # config logging
try: try:
if sys.platform == 'linux': if sys.platform == "linux":
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc' logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
if sys.platform == 'darwin': if sys.platform == "darwin":
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc' logging_path = os.getenv("HOME") + "/Library/" + "Application Support/" + "FreeDATA/" + "tnc"
if sys.platform in ['win32', 'win64']: if sys.platform in ["win32", "win64"]:
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc' logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
if not os.path.exists(logging_path): if not os.path.exists(logging_path):
os.makedirs(logging_path) os.makedirs(logging_path)
log_handler.setup_logging(logging_path) log_handler.setup_logging(logging_path)
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e) structlog.get_logger("structlog").error("[DMN] logger init error", exception=err)
structlog.get_logger("structlog").info("[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION) structlog.get_logger("structlog").info("[TNC] Starting FreeDATA", author="DJ2LS", year="2022", version=static.VERSION)
@ -147,8 +147,8 @@ if __name__ == '__main__':
server_thread.daemon = True server_thread.daemon = True
server_thread.start() server_thread.start()
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e) structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
sys.exit(1) sys.exit(1)
while 1: while True:
time.sleep(1) time.sleep(1)

View file

@ -10,32 +10,26 @@ 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
from collections import deque from collections import deque
# import audio
import codec2
import data_handler
import numpy as np import numpy as np
import sock
import sounddevice as sd import sounddevice as sd
import static
import structlog import structlog
import ujson as json import ujson as json
import audio
import codec2
import data_handler
import helpers
import log_handler
import sock
import static
TESTMODE = False TESTMODE = False
RXCHANNEL = '' RXCHANNEL = ""
TXCHANNEL = '' TXCHANNEL = ""
# Initialize FIFO queue to store received frames # Initialize FIFO queue to store received frames
MODEM_RECEIVED_QUEUE = queue.Queue() MODEM_RECEIVED_QUEUE = queue.Queue()
@ -47,8 +41,11 @@ RECEIVE_DATAC1 = False
RECEIVE_DATAC3 = False RECEIVE_DATAC3 = False
RECEIVE_FSK_LDPC_1 = False RECEIVE_FSK_LDPC_1 = False
class RF():
class RF:
""" """ """ """
log = structlog.get_logger("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,26 +139,29 @@ 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") self.log.info("[MDM] init: opened audio devices")
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error("[MDM] init: can't open audio device. Exit", e=e) self.log.error("[MDM] init: can't open audio device. Exit", e=err)
sys.exit(1) sys.exit(1)
try: try:
structlog.get_logger("structlog").debug("[MDM] init: starting pyaudio callback") self.log.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 err:
structlog.get_logger("structlog").error("[MDM] init: starting pyaudio callback failed", e=e) self.log.error("[MDM] init: starting pyaudio callback failed", e=err)
else: else:
# 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
@ -159,31 +169,36 @@ class RF():
try: try:
os.mkfifo(RXCHANNEL) os.mkfifo(RXCHANNEL)
os.mkfifo(TXCHANNEL) os.mkfifo(TXCHANNEL)
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error(f"[MDM] init:mkfifo: Exception: {e}") self.log.error(f"[MDM] init:mkfifo: Exception: {err}")
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
# Check how we want to control the radio # Check how we want to control the radio
if static.HAMLIB_RADIOCONTROL == 'direct': if static.HAMLIB_RADIOCONTROL == "direct":
import rig import rig
elif static.HAMLIB_RADIOCONTROL == 'rigctl': elif static.HAMLIB_RADIOCONTROL == "rigctl":
import rigctl as rig import rigctl as rig
elif static.HAMLIB_RADIOCONTROL == 'rigctld': elif static.HAMLIB_RADIOCONTROL == "rigctld":
import rigctld as rig import rigctld as rig
elif static.HAMLIB_RADIOCONTROL == 'disabled': elif static.HAMLIB_RADIOCONTROL == "disabled":
import rigdummy as rig import rigdummy as rig
else: else:
import rigdummy as rig import rigdummy as rig
self.hamlib = rig.radio() self.hamlib = rig.radio()
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT, hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED, pttport=static.HAMLIB_PTT_PORT, data_bits=static.HAMLIB_DATA_BITS, stop_bits=static.HAMLIB_STOP_BITS, handshake=static.HAMLIB_HANDSHAKE, rigctld_ip = static.HAMLIB_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)
@ -217,11 +234,11 @@ class RF():
# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
def mkfifo_read_callback(self): def mkfifo_read_callback(self):
while 1: while True:
time.sleep(0.01) time.sleep(0.01)
# -----read # -----read
data_in48k = bytes() data_in48k = bytes()
with open(RXCHANNEL, 'rb') as fifo: with open(RXCHANNEL, "rb") as fifo:
for line in fifo: for line in fifo:
data_in48k += line data_in48k += line
@ -235,25 +252,24 @@ 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 True:
time.sleep(0.01) time.sleep(0.01)
# -----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)
fifo_write.flush() fifo_write.flush()
@ -268,8 +284,6 @@ class RF():
time: time:
status: status:
Returns:
Nothing
""" """
x = np.frombuffer(data_in48k, dtype=np.int16) x = np.frombuffer(data_in48k, dtype=np.int16)
x = self.resampler.resample48_to_8(x) x = self.resampler.resample48_to_8(x)
@ -284,35 +298,31 @@ class RF():
static.BUFFER_OVERFLOW_COUNTER[0] += 1 static.BUFFER_OVERFLOW_COUNTER[0] += 1
# Avoid buffer overflow by filling only if buffer not full and selected datachannel mode # Avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size: if self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size:
if RECEIVE_DATAC1:
self.datac1_buffer.push(x)
else:
static.BUFFER_OVERFLOW_COUNTER[1] += 1 static.BUFFER_OVERFLOW_COUNTER[1] += 1
elif RECEIVE_DATAC1:
self.datac1_buffer.push(x)
# Avoid buffer overflow by filling only if buffer not full and selected datachannel mode # Avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size: if self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size:
if RECEIVE_DATAC3:
self.datac3_buffer.push(x)
else:
static.BUFFER_OVERFLOW_COUNTER[2] += 1 static.BUFFER_OVERFLOW_COUNTER[2] += 1
elif RECEIVE_DATAC3:
self.datac3_buffer.push(x)
# Avoid buffer overflow by filling only if buffer not full and selected datachannel mode # Avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.fsk_ldpc_buffer_0.nbuffer + length_x > self.fsk_ldpc_buffer_0.size: if self.fsk_ldpc_buffer_0.nbuffer + length_x > self.fsk_ldpc_buffer_0.size:
if static.ENABLE_FSK:
self.fsk_ldpc_buffer_0.push(x)
else:
static.BUFFER_OVERFLOW_COUNTER[3] += 1 static.BUFFER_OVERFLOW_COUNTER[3] += 1
elif static.ENABLE_FSK:
self.fsk_ldpc_buffer_0.push(x)
# Avoid buffer overflow by filling only if buffer not full and selected datachannel mode # Avoid buffer overflow by filling only if buffer not full and selected datachannel mode
if not self.fsk_ldpc_buffer_1.nbuffer + length_x > self.fsk_ldpc_buffer_1.size: if self.fsk_ldpc_buffer_1.nbuffer + length_x > self.fsk_ldpc_buffer_1.size:
if RECEIVE_FSK_LDPC_1 and static.ENABLE_FSK:
self.fsk_ldpc_buffer_1.push(x)
else:
static.BUFFER_OVERFLOW_COUNTER[4] += 1 static.BUFFER_OVERFLOW_COUNTER[4] += 1
elif RECEIVE_FSK_LDPC_1 and static.ENABLE_FSK:
self.fsk_ldpc_buffer_1.push(x)
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:
@ -322,7 +332,7 @@ class RF():
try: try:
outdata[:] = data_out48k[:frames] outdata[:] = data_out48k[:frames]
except IndexError as e: except IndexError as e:
structlog.get_logger("structlog").debug(f"[MDM] callback: IndexError: {e}") self.log.debug(f"[MDM] callback: IndexError: {e}")
# return (data_out48k, audio.pyaudio.paContinue) # return (data_out48k, audio.pyaudio.paContinue)
@ -336,14 +346,12 @@ class RF():
repeat_delay: repeat_delay:
frames: frames:
Returns:
""" """
structlog.get_logger("structlog").debug("[MDM] transmit", mode=mode) self.log.debug("[MDM] transmit", mode=mode)
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)
@ -373,11 +381,11 @@ class RF():
mod_out_silence = ctypes.create_string_buffer(data_delay * 2) mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
txbuffer = bytes(mod_out_silence) txbuffer = bytes(mod_out_silence)
structlog.get_logger("structlog").debug("[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame) self.log.debug("[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame)
for _ in range(repeats): for _ in range(repeats):
# codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing # codec2 fsk preamble may be broken - at least it sounds like that so we are disabling it for testing
if self.MODE not in ['FSK_LDPC_0', 'FSK_LDPC_1', 200, 201]: if self.MODE not in ["FSK_LDPC_0", "FSK_LDPC_1", 200, 201]:
# Write preamble to txbuffer # Write preamble to txbuffer
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble) codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
txbuffer += bytes(mod_out_preamble) txbuffer += bytes(mod_out_preamble)
@ -390,16 +398,17 @@ 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(
crc = crc.value.to_bytes(2, byteorder='big') # Convert crc to 2 byte hex string codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)) # Generate CRC16
crc = crc.value.to_bytes(2, byteorder="big") # Convert crc to 2 byte hex string
buffer += crc # Append crc16 to buffer buffer += crc # Append crc16 to buffer
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer) data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer codec2.api.freedv_rawdatatx(freedv, mod_out, data) # modulate DATA and save it into mod_out pointer
txbuffer += bytes(mod_out) txbuffer += bytes(mod_out)
# codec2 fsk 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
if self.MODE not in ['FSK_LDPC_0', 'FSK_LDPC_1', 200, 201]: if self.MODE not in ["FSK_LDPC_0", "FSK_LDPC_1", 200, 201]:
# Write postamble to txbuffer # Write postamble to txbuffer
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble) codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
# Append postamble to txbuffer # Append postamble to txbuffer
@ -421,14 +430,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) # self.log.debug("[MDM] mod out shorter than audio buffer", delta=delta)
self.modoutqueue.append(c) self.modoutqueue.append(c)
@ -441,7 +450,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 +469,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 +486,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 +503,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 +520,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 +537,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
@ -534,9 +553,9 @@ class RF():
while True: while True:
data = self.modem_transmit_queue.get() data = self.modem_transmit_queue.get()
structlog.get_logger("structlog").debug("[MDM] worker_transmit", mode=data[0]) self.log.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):
@ -555,8 +574,6 @@ class RF():
Args: Args:
freedv: freedv:
Returns:
""" """
modemStats = codec2.MODEMSTATS() modemStats = codec2.MODEMSTATS()
self.c_lib.freedv_get_modem_extended_stats.restype = None self.c_lib.freedv_get_modem_extended_stats.restype = None
@ -571,8 +588,6 @@ class RF():
Args: Args:
freedv: freedv:
Returns:
""" """
if not static.ENABLE_SCATTER: if not static.ENABLE_SCATTER:
return return
@ -607,8 +622,6 @@ class RF():
Args: Args:
freedv: freedv:
Returns:
""" """
try: try:
modem_stats_snr = ctypes.c_float() modem_stats_snr = ctypes.c_float()
@ -619,12 +632,12 @@ class RF():
modem_stats_sync = modem_stats_sync.value modem_stats_sync = modem_stats_sync.value
snr = round(modem_stats_snr, 1) snr = round(modem_stats_snr, 1)
structlog.get_logger("structlog").info("[MDM] calculate_snr: ", snr=snr) self.log.info("[MDM] calculate_snr: ", snr=snr)
# static.SNR = np.clip(snr, 0, 255) # limit to max value of 255 # static.SNR = np.clip(snr, 0, 255) # limit to max value of 255
static.SNR = np.clip(snr, -128, 128) # limit to max value of -128/128 as a possible fix of #188 static.SNR = np.clip(snr, -128, 128) # limit to max value of -128/128 as a possible fix of #188
return static.SNR return static.SNR
except Exception as e: except Exception as err:
structlog.get_logger("structlog").error(f"[MDM] calculate_snr: Exception: {e}") self.log.error(f"[MDM] calculate_snr: Exception: {err}")
static.SNR = 0 static.SNR = 0
return static.SNR return static.SNR
@ -633,10 +646,10 @@ class RF():
while True: while True:
# time.sleep(1.5) # time.sleep(1.5)
threading.Event().wait(0.5) threading.Event().wait(0.5)
# (static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data() # (static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWIDTH, static.PTT_STATE) = self.hamlib.get_rig_data()
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency() static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
static.HAMLIB_MODE = self.hamlib.get_mode() static.HAMLIB_MODE = self.hamlib.get_mode()
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith() static.HAMLIB_BANDWIDTH = self.hamlib.get_bandwidth()
def calculate_fft(self): def calculate_fft(self):
""" """ """ """
@ -644,7 +657,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 +670,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 +679,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,10 +701,10 @@ 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 err:
structlog.get_logger("structlog").error(f"[MDM] calculate_fft: Exception: {e}") self.log.error(f"[MDM] calculate_fft: Exception: {err}")
structlog.get_logger("structlog").debug("[MDM] Setting fft=0") self.log.debug("[MDM] Setting fft=0")
# else 0 # else 0
static.FFT = [0] static.FFT = [0]
@ -701,22 +714,23 @@ class RF():
Args: Args:
n_frames_per_burst: n_frames_per_burst:
Returns:
""" """
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, n_frames_per_burst)
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, n_frames_per_burst)
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, n_frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, n_frames_per_burst)
def 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)
@ -728,8 +742,6 @@ def get_bytes_per_frame(mode):
Args: Args:
mode: mode:
Returns:
""" """
freedv = open_codec2_instance(mode) freedv = open_codec2_instance(mode)

View file

@ -1,11 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
import re
import structlog
import atexit import atexit
import subprocess
import os import os
import re
import subprocess
import sys
import structlog
# set global hamlib version # set global hamlib version
hamlib_version = 0 hamlib_version = 0
@ -20,26 +21,26 @@ else:
# try importing hamlib # try importing hamlib
try: try:
# get python version # get python version
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) python_version = f"{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(f"/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 it's running within app bundle
# this is not needed as python will be shipped with app bundle # this is not needed as python will be shipped with app bundle
sys.path.append('/usr/local/lib/python3.6/site-packages') sys.path.append("/usr/local/lib/python3.6/site-packages")
sys.path.append('/usr/local/lib/python3.7/site-packages') sys.path.append("/usr/local/lib/python3.7/site-packages")
sys.path.append('/usr/local/lib/python3.8/site-packages') sys.path.append("/usr/local/lib/python3.8/site-packages")
sys.path.append('/usr/local/lib/python3.9/site-packages') sys.path.append("/usr/local/lib/python3.9/site-packages")
sys.path.append('/usr/local/lib/python3.10/site-packages') sys.path.append("/usr/local/lib/python3.10/site-packages")
sys.path.append('lib/hamlib/linux/python3.8/site-packages') sys.path.append("lib/hamlib/linux/python3.8/site-packages")
import Hamlib import Hamlib
# https://stackoverflow.com/a/4703409 # https://stackoverflow.com/a/4703409
@ -51,21 +52,23 @@ try:
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version) structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version)
else: else:
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version) structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
except Exception as e: except Exception as err:
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=err)
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 = hamlib_version.split(' ') hamlib_version = rigctl.stdout.readline()
hamlib_version = hamlib_version.split(" ")
if hamlib_version[1] != "Hamlib":
raise Exception from err
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
sys.exit()
except Exception as err1:
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=err1)
if hamlib_version[1] == 'Hamlib':
structlog.get_logger("structlog").warning("[RIG] Rigctl found! Please try using this", version=hamlib_version[2])
sys.exit()
else:
raise Exception
except Exception as e:
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=e)
hamlib_version = 0 hamlib_version = 0
sys.exit() sys.exit()
@ -73,16 +76,16 @@ except Exception as e:
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
self.devicename = '' self.devicename = ""
self.devicenumber = '' self.devicenumber = ""
self.deviceport = '' self.deviceport = ""
self.serialspeed = '' self.serialspeed = ""
self.hamlib_ptt_type = '' self.hamlib_ptt_type = ""
self.my_rig = '' self.my_rig = ""
self.pttport = '' self.pttport = ""
self.data_bits = '' self.data_bits = ""
self.stop_bits = '' self.stop_bits = ""
self.handshake = '' self.handshake = ""
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip): def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip):
""" """
@ -104,7 +107,7 @@ class radio:
""" """
self.devicename = devicename self.devicename = devicename
self.deviceport = str(deviceport) self.deviceport = str(deviceport)
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = str(hamlib_ptt_type) self.hamlib_ptt_type = str(hamlib_ptt_type)
self.pttport = str(pttport) self.pttport = str(pttport)
self.data_bits = str(data_bits) self.data_bits = str(data_bits)
@ -118,7 +121,7 @@ class radio:
# get devicenumber by looking for deviceobject in Hamlib module # get devicenumber by looking for deviceobject in Hamlib module
try: try:
self.devicenumber = int(getattr(Hamlib, self.devicename)) self.devicenumber = int(getattr(Hamlib, self.devicename))
except: except Exception:
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...") structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
self.devicenumber = 0 self.devicenumber = 0
@ -131,42 +134,42 @@ class radio:
self.my_rig.set_conf("data_bits", self.data_bits) self.my_rig.set_conf("data_bits", self.data_bits)
self.my_rig.set_conf("ptt_pathname", self.pttport) self.my_rig.set_conf("ptt_pathname", self.pttport)
if self.hamlib_ptt_type == 'RIG': if self.hamlib_ptt_type == "RIG":
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
self.my_rig.set_conf("ptt_type", 'RIG') self.my_rig.set_conf("ptt_type", "RIG")
elif self.hamlib_ptt_type == 'USB': elif self.hamlib_ptt_type == "USB":
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
self.my_rig.set_conf("ptt_type", 'USB') self.my_rig.set_conf("ptt_type", "USB")
elif self.hamlib_ptt_type == 'DTR-H': elif self.hamlib_ptt_type == "DTR-H":
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
self.my_rig.set_conf("dtr_state", "HIGH") self.my_rig.set_conf("dtr_state", "HIGH")
self.my_rig.set_conf("ptt_type", "DTR") self.my_rig.set_conf("ptt_type", "DTR")
elif self.hamlib_ptt_type == 'DTR-L': elif self.hamlib_ptt_type == "DTR-L":
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
self.my_rig.set_conf("dtr_state", "LOW") self.my_rig.set_conf("dtr_state", "LOW")
self.my_rig.set_conf("ptt_type", "DTR") self.my_rig.set_conf("ptt_type", "DTR")
elif self.hamlib_ptt_type == 'RTS': elif self.hamlib_ptt_type == "RTS":
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
self.my_rig.set_conf("dtr_state", "OFF") self.my_rig.set_conf("dtr_state", "OFF")
self.my_rig.set_conf("ptt_type", "RTS") self.my_rig.set_conf("ptt_type", "RTS")
elif self.hamlib_ptt_type == 'PARALLEL': elif self.hamlib_ptt_type == "PARALLEL":
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
elif self.hamlib_ptt_type == 'MICDATA': elif self.hamlib_ptt_type == "MICDATA":
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
elif self.hamlib_ptt_type == 'CM108': elif self.hamlib_ptt_type == "CM108":
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108 self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
elif self.hamlib_ptt_type == 'RIG_PTT_NONE': elif self.hamlib_ptt_type == "RIG_PTT_NONE":
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE': else: # self.hamlib_ptt_type == "RIG_PTT_NONE":
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname")) structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname"))
@ -176,28 +179,28 @@ class radio:
try: try:
# lets determine the error message when opening rig # lets determine the error message when opening rig
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines() error = str(Hamlib.rigerror(self.my_rig.error_status)).splitlines()
error = error[1].split('err=') error = error[1].split("err=")
error = error[1] error = error[1]
if error == 'Permission denied': if error == "Permission denied":
structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error) structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error)
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions' help_url = "https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions"
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url) structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url)
except: except Exception:
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS') structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status="SUCCESS")
# set ptt to false if ptt is stuck for some reason # set ptt to false if ptt is stuck for some reason
self.set_ptt(False) self.set_ptt(False)
# set rig mode to USB # set rig mode to USB
# temporarly outcommented because of possible problems. # temporarly outcommented because of possible problems.
#self.my_rig.set_mode(Hamlib.RIG_MODE_USB) # self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB) # self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
return True return True
except Exception as e: except Exception as err2:
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0]) structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0])
return False return False
def get_frequency(self): def get_frequency(self):
@ -206,16 +209,16 @@ class radio:
def get_mode(self): def get_mode(self):
""" """ """ """
(hamlib_mode, bandwith) = self.my_rig.get_mode() (hamlib_mode, bandwidth) = self.my_rig.get_mode()
return Hamlib.rig_strrmode(hamlib_mode) return Hamlib.rig_strrmode(hamlib_mode)
def get_bandwith(self): def get_bandwidth(self):
""" """ """ """
(hamlib_mode, bandwith) = self.my_rig.get_mode() (hamlib_mode, bandwidth) = self.my_rig.get_mode()
return bandwith return bandwidth
# 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

@ -23,16 +23,17 @@ hamlib_version = 0
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
self.devicename = '' self.devicename = ""
self.devicenumber = '' self.devicenumber = ""
self.deviceport = '' self.deviceport = ""
self.serialspeed = '' self.serialspeed = ""
self.hamlib_ptt_type = '' self.hamlib_ptt_type = ""
self.my_rig = '' self.my_rig = ""
self.pttport = '' self.pttport = ""
self.data_bits = '' self.data_bits = ""
self.stop_bits = '' self.stop_bits = ""
self.handshake = '' self.handshake = ""
self.cmd = ""
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port): def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
""" """
@ -54,14 +55,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:
@ -71,26 +72,26 @@ class radio:
try: try:
import Hamlib import Hamlib
self.devicenumber = int(getattr(Hamlib, self.devicename)) self.devicenumber = int(getattr(Hamlib, self.devicename))
except Exception as e: except Exception as err:
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=err)
# set deviceport to dummy port, if we selected dummy model # set deviceport to dummy port, if we selected dummy model
if self.devicenumber == 1 or self.devicenumber == 6: if self.devicenumber in {1, 6}:
self.deviceport = '/dev/ttyUSB0' self.deviceport = "/dev/ttyUSB0"
print(self.devicenumber, self.deviceport, self.serialspeed) print(self.devicenumber, self.deviceport, self.serialspeed)
# select precompiled executable for win32/win64 rigctl # select precompiled executable for win32/win64 rigctl
# this is really a hack...somewhen we need a native hamlib integration for windows # this is really a hack...somewhen we need a native hamlib integration for windows
if sys.platform in ['win32', 'win64']: if sys.platform in ["win32", "win64"]:
self.cmd = app_path + 'lib\\hamlib\\'+sys.platform+'\\rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed)) self.cmd = app_path + "lib\\hamlib\\" + sys.platform + "\\rigctl -m %d -r %s -s %d " % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
else: else:
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed)) self.cmd = "rigctl -m %d -r %s -s %d " % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per # eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
# il set e t per il get # il set e t per il get
@ -101,33 +102,33 @@ class radio:
def get_frequency(self): def get_frequency(self):
""" """ """ """
cmd = self.cmd + ' f' cmd = f"{self.cmd} f"
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
time.sleep(0.5) time.sleep(0.5)
freq = sw_proc.communicate()[0] freq = sw_proc.communicate()[0]
#print('get_frequency', freq, sw_proc.communicate()) # print("get_frequency", freq, sw_proc.communicate())
try: try:
return int(freq) return int(freq)
except: except Exception:
return False return False
def get_mode(self): def get_mode(self):
""" """ """ """
#(hamlib_mode, bandwith) = self.my_rig.get_mode() # (hamlib_mode, bandwidth) = self.my_rig.get_mode()
#return Hamlib.rig_strrmode(hamlib_mode) # return Hamlib.rig_strrmode(hamlib_mode)
try: try:
return 'PKTUSB' return "PKTUSB"
except: except Exception:
return False return False
def get_bandwith(self): def get_bandwidth(self):
""" """ """ """
#(hamlib_mode, bandwith) = self.my_rig.get_mode() # (hamlib_mode, bandwidth) = self.my_rig.get_mode()
bandwith = 2700 bandwidth = 2700
try: try:
return bandwith return bandwidth
except: except Exception:
return False return False
def set_mode(self, mode): def set_mode(self, mode):
@ -144,14 +145,14 @@ class radio:
def get_ptt(self): def get_ptt(self):
""" """ """ """
cmd = self.cmd + ' t' cmd = f"{self.cmd} t"
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
time.sleep(0.5) time.sleep(0.5)
status = sw_proc.communicate()[0] status = sw_proc.communicate()[0]
try: try:
return status return status
except: except Exception:
return False return False
def set_ptt(self, state): def set_ptt(self, state):
@ -163,21 +164,18 @@ class radio:
Returns: Returns:
""" """
cmd = self.cmd + ' T ' cmd = f"{self.cmd} T "
print('set_ptt', state) print("set_ptt", state)
if state: cmd = f"{cmd}1" if state else f"{cmd}0"
cmd = cmd + '1' print("set_ptt", cmd)
else:
cmd = cmd + '0'
print('set_ptt', cmd)
sw_proc = subprocess.Popen(cmd, shell=True, text=True) sw_proc = subprocess.Popen(cmd, shell=True, text=True)
try: try:
return state return state
except: except Exception:
return False return False
def close_rig(self): def close_rig(self):
""" """ """ """
#self.my_rig.close() # self.my_rig.close()
return return

View file

@ -10,9 +10,6 @@ import time
import structlog import structlog
import log_handler
import static
# set global hamlib version # set global hamlib version
hamlib_version = 0 hamlib_version = 0
@ -22,9 +19,9 @@ class radio():
# Note: This is a massive hack. # Note: This is a massive hack.
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5): def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
""" Open a connection to rotctld, and test it for validity """ """ Open a connection to rigctld, 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
@ -51,7 +48,7 @@ class radio():
""" """
self.hostname = rigctld_ip self.hostname = rigctld_ip
self.port = int(rigctld_port) self.port = int(rigctld_port)
if self.connect(): if self.connect():
logging.debug("Rigctl intialized") logging.debug("Rigctl intialized")
return True return True
@ -63,14 +60,14 @@ 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
except Exception as e: except Exception as err:
# ConnectionRefusedError: [Errno 111] Connection refused # ConnectionRefusedError: [Errno 111] Connection refused
self.close_rig() self.close_rig()
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=e) structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=err)
return False return False
def close_rig(self): def close_rig(self):
@ -78,7 +75,7 @@ class radio():
self.sock.close() self.sock.close()
self.connected = False self.connected = False
def send_command(self, command): def send_command(self, command) -> bytes:
"""Send a command to the connected rotctld instance, """Send a command to the connected rotctld instance,
and return the return value. and return the return value.
@ -90,14 +87,14 @@ class radio():
""" """
if self.connected: if self.connected:
try: try:
self.connection.sendall(command+b'\n') self.connection.sendall(command + b"\n")
except: except Exception:
structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port) structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port)
self.connected = False self.connected = False
try: try:
return self.connection.recv(1024) return self.connection.recv(1024)
except: except Exception:
structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port) structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port)
self.connected = False self.connected = False
else: else:
@ -106,24 +103,26 @@ class radio():
time.sleep(0.5) time.sleep(0.5)
self.connect() self.connect()
return b""
def get_mode(self): def get_mode(self):
""" """ """ """
try: try:
data = self.send_command(b"m") data = self.send_command(b"m")
data = data.split(b'\n') data = data.split(b"\n")
mode = data[0] mode = data[0]
return mode.decode("utf-8") return mode.decode("utf-8")
except: except Exception:
return 0 return 0
def get_bandwith(self): def get_bandwidth(self):
""" """ """ """
try: try:
data = self.send_command(b"m") data = self.send_command(b"m")
data = data.split(b'\n') data = data.split(b"\n")
bandwith = data[1] bandwidth = data[1]
return bandwith.decode("utf-8") return bandwidth.decode("utf-8")
except: except Exception:
return 0 return 0
def get_frequency(self): def get_frequency(self):
@ -131,14 +130,14 @@ class radio():
try: try:
frequency = self.send_command(b"f") frequency = self.send_command(b"f")
return frequency.decode("utf-8") return frequency.decode("utf-8")
except: except Exception:
return 0 return 0
def get_ptt(self): def get_ptt(self):
""" """ """ """
try: try:
return self.send_command(b"t") return self.send_command(b"t")
except: except Exception:
return False return False
def set_ptt(self, state): def set_ptt(self, state):
@ -152,9 +151,9 @@ class radio():
""" """
try: try:
if state: if state:
self.send_command(b"T 1") self.send_command(b"T 1")
else: else:
self.send_command(b"T 0") self.send_command(b"T 0")
return state return state
except: except Exception:
return False return False

View file

@ -1,12 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import structlog
hamlib_version = 0 hamlib_version = 0
class radio: class radio:
""" """ """ """
def __init__(self): def __init__(self):
pass pass
@ -29,7 +28,7 @@ class radio:
""" """ """ """
return None return None
def get_bandwith(self): def get_bandwidth(self):
""" """ """ """
return None return None

View file

@ -6,38 +6,31 @@ Created on Fri Dec 25 21:25:14 2020
@author: DJ2LS @author: DJ2LS
# GET COMMANDS # GET COMMANDS
# "command" : "..." # "command" : "..."
# SET COMMANDS # SET COMMANDS
# "command" : "..." # "command" : "..."
# "parameter" : " ..." # "parameter" : " ..."
# DATA COMMANDS
# "command" : "..."
# "type" : "..."
# "dxcallsign" : "..."
# "data" : "..."
# DATA COMMANDS
# "command" : "..."
# "type" : "..."
# "dxcallsign" : "..."
# "data" : "..."
""" """
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 ujson as json
import audio
import data_handler import data_handler
import helpers import helpers
import log_handler
import static import static
import structlog
import ujson as json
SOCKET_QUEUE = queue.Queue() SOCKET_QUEUE = queue.Queue()
DAEMON_QUEUE = queue.Queue() DAEMON_QUEUE = queue.Queue()
@ -45,6 +38,8 @@ DAEMON_QUEUE = queue.Queue()
CONNECTED_CLIENTS = set() CONNECTED_CLIENTS = set()
CLOSE_SIGNAL = False CLOSE_SIGNAL = False
log = structlog.get_logger("sock")
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
""" """
@ -62,7 +57,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
function called by socket handler function called by socket handler
send data to a network client if available send data to a network client if available
""" """
tempdata = b'' tempdata = b""
while self.connection_alive and not CLOSE_SIGNAL: while self.connection_alive and not CLOSE_SIGNAL:
# send tnc state as network stream # send tnc state as network stream
# check server port against daemon port and send corresponding data # check server port against daemon port and send corresponding data
@ -80,24 +75,23 @@ 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)
except Exception as e: except Exception as err:
# print("connection lost...") log.info("[SCK] Connection lost", e=err)
structlog.get_logger("structlog").info("[SCK] Connection lost", e=e)
self.connection_alive = False self.connection_alive = False
# we want to transmit scatter data only once to reduce network traffic # we want to transmit scatter data only once to reduce network traffic
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):
@ -111,15 +105,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
chunk = self.request.recv(1024) chunk = self.request.recv(1024)
data += chunk data += chunk
if chunk == b'': if chunk == b"":
#print("connection broken. Closing...") # print("connection broken. Closing...")
self.connection_alive = False self.connection_alive = False
if data.startswith(b'{') and data.endswith(b'}\n'): if data.startswith(b"{") and data.endswith(b"}\n"):
# split data by \n if we have multiple commands in socket buffer # split data by \n if we have multiple commands in socket buffer
data = data.split(b'\n') data = data.split(b"\n")
# remove empty data # remove empty data
data.remove(b'') data.remove(b"")
# iterate thorugh data list # iterate thorugh data list
for commands in data: for commands in data:
@ -137,8 +131,9 @@ 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 err:
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e) log.info("[SCK] Connection closed", ip=self.client_address[0],
port=self.client_address[1], e=err)
self.connection_alive = False self.connection_alive = False
def handle(self): def handle(self):
@ -147,11 +142,14 @@ 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]) log.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.send_thread = threading.Thread(target=self.send_to_client, args=[], daemon=True)
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start() self.send_thread.start()
self.receive_thread = threading.Thread(target=self.receive_from_client, args=[], daemon=True)
self.receive_thread.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 +157,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]) log.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 Exception as err:
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request) log.warning("[SCK] client connection already removed from client list",
client=self.request, e=err)
def process_tnc_commands(data): def process_tnc_commands(data):
""" """
@ -179,60 +180,60 @@ def process_tnc_commands(data):
try: try:
# convert data to json object # convert data to json object
received_json = json.loads(data) received_json = json.loads(data)
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json) log.debug("[SCK] CMD", command=received_json)
# SET TX AUDIO LEVEL ----------------------------------------------------- # SET TX AUDIO LEVEL -----------------------------------------------------
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level": if received_json["type"] == "set" and received_json["command"] == "tx_audio_level":
try: try:
static.TX_AUDIO_LEVEL = int(received_json["value"]) static.TX_AUDIO_LEVEL = int(received_json["value"])
command_response("tx_audio_level", True) command_response("tx_audio_level", True)
except Exception as e: except Exception as err:
command_response("tx_audio_level", False) command_response("tx_audio_level", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# TRANSMIT SINE WAVE ----------------------------------------------------- # TRANSMIT SINE WAVE -----------------------------------------------------
if received_json["type"] == "set" and received_json["command"] == "send_test_frame": if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME']) data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
command_response("send_test_frame", True) command_response("send_test_frame", True)
except Exception as e: except Exception as err:
command_response("send_test_frame", False) command_response("send_test_frame", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# CQ CQ CQ ----------------------------------------------------- # CQ CQ CQ -----------------------------------------------------
if received_json["command"] == "cqcqcq": if received_json["command"] == "cqcqcq":
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ']) data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
command_response("cqcqcq", True) command_response("cqcqcq", True)
except Exception as e: except Exception as err:
command_response("cqcqcq", False) command_response("cqcqcq", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# START_BEACON ----------------------------------------------------- # START_BEACON -----------------------------------------------------
if received_json["command"] == "start_beacon": if received_json["command"] == "start_beacon":
try: try:
static.BEACON_STATE = True static.BEACON_STATE = True
interval = int(received_json["parameter"]) interval = int(received_json["parameter"])
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True]) data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
command_response("start_beacon", True) command_response("start_beacon", True)
except Exception as e: except Exception as err:
command_response("start_beacon", False) command_response("start_beacon", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# STOP_BEACON ----------------------------------------------------- # STOP_BEACON -----------------------------------------------------
if received_json["command"] == "stop_beacon": if received_json["command"] == "stop_beacon":
try: try:
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!") log.warning("[TNC] Stopping beacon!")
static.BEACON_STATE = False static.BEACON_STATE = False
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False]) data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
command_response("stop_beacon", True) command_response("stop_beacon", True)
except Exception as e: except Exception as err:
command_response("stop_beacon", False) command_response("stop_beacon", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# PING ---------------------------------------------------------- # PING ----------------------------------------------------------
if received_json["type"] == 'ping' and received_json["command"] == "ping": if received_json["type"] == "ping" and received_json["command"] == "ping":
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
dxcallsign = received_json["dxcallsign"] dxcallsign = received_json["dxcallsign"]
@ -243,14 +244,14 @@ def process_tnc_commands(data):
dxcallsign = helpers.callsign_to_bytes(dxcallsign) dxcallsign = helpers.callsign_to_bytes(dxcallsign)
dxcallsign = helpers.bytes_to_callsign(dxcallsign) dxcallsign = helpers.bytes_to_callsign(dxcallsign)
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign]) data_handler.DATA_QUEUE_TRANSMIT.put(["PING", dxcallsign])
command_response("ping", True) command_response("ping", True)
except Exception as e: except Exception as err:
command_response("ping", False) command_response("ping", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# CONNECT ---------------------------------------------------------- # CONNECT ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "connect": if received_json["type"] == "arq" and received_json["command"] == "connect":
static.BEACON_PAUSE = True static.BEACON_PAUSE = True
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
@ -265,24 +266,24 @@ def process_tnc_commands(data):
static.DXCALLSIGN = dxcallsign static.DXCALLSIGN = dxcallsign
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN) static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
data_handler.DATA_QUEUE_TRANSMIT.put(['CONNECT', dxcallsign]) data_handler.DATA_QUEUE_TRANSMIT.put(["CONNECT", dxcallsign])
command_response("connect", True) command_response("connect", True)
except Exception as e: except Exception as err:
command_response("connect", False) command_response("connect", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# DISCONNECT ---------------------------------------------------------- # DISCONNECT ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "disconnect": if received_json["type"] == "arq" and received_json["command"] == "disconnect":
# send ping frame and wait for ACK # send ping frame and wait for ACK
try: try:
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT']) data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
command_response("disconnect", True) command_response("disconnect", True)
except Exception as e: except Exception as err:
command_response("disconnect", False) command_response("disconnect", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# TRANSMIT RAW DATA ------------------------------------------- # TRANSMIT RAW DATA -------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "send_raw": if received_json["type"] == "arq" and received_json["command"] == "send_raw":
static.BEACON_PAUSE = True static.BEACON_PAUSE = True
try: try:
if not static.ARQ_SESSION: if not static.ARQ_SESSION:
@ -306,39 +307,39 @@ def process_tnc_commands(data):
# check if specific callsign is set with different SSID than the TNC is initialized # check if specific callsign is set with different SSID than the TNC is initialized
try: try:
mycallsign = received_json["parameter"][0]["mycallsign"] mycallsign = received_json["parameter"][0]["mycallsign"]
except: except Exception:
mycallsign = static.MYCALLSIGN mycallsign = static.MYCALLSIGN
# check if transmission uuid provided else set no-uuid # check if transmission uuid provided else set no-uuid
try: try:
arq_uuid = received_json["uuid"] arq_uuid = received_json["uuid"]
except: except Exception:
arq_uuid = 'no-uuid' arq_uuid = "no-uuid"
if not len(base64data) % 4: if not len(base64data) % 4:
binarydata = base64.b64decode(base64data) binarydata = base64.b64decode(base64data)
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', binarydata, mode, n_frames, arq_uuid, mycallsign]) data_handler.DATA_QUEUE_TRANSMIT.put(["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign])
else: else:
raise TypeError raise TypeError
except Exception as e: except Exception as err:
command_response("send_raw", False) command_response("send_raw", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
# STOP TRANSMISSION ---------------------------------------------------------- # STOP TRANSMISSION ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission": if received_json["type"] == "arq" and received_json["command"] == "stop_transmission":
try: try:
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE: if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP']) data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!") log.warning("[TNC] Stopping transmission!")
static.TNC_STATE = 'IDLE' static.TNC_STATE = "IDLE"
static.ARQ_STATE = False static.ARQ_STATE = False
command_response("stop_transmission", True) command_response("stop_transmission", True)
except Exception as e: except Exception as err:
command_response("stop_transmission", False) command_response("stop_transmission", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'get' and received_json["command"] == 'rx_buffer': if received_json["type"] == "get" and received_json["command"] == "rx_buffer":
try: try:
output = { output = {
"command": "rx_buffer", "command": "rx_buffer",
@ -346,37 +347,40 @@ 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)
except Exception as e: except Exception as err:
command_response("rx_buffer", False) command_response("rx_buffer", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer': if received_json["type"] == "set" and received_json["command"] == "del_rx_buffer":
try: try:
static.RX_BUFFER = [] static.RX_BUFFER = []
command_response("del_rx_buffer", True) command_response("del_rx_buffer", True)
except Exception as e: except Exception as err:
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) log.warning("[SCK] command execution error", e=err, command=received_json)
# exception, if JSON can't be decoded
except Exception as err:
log.error("[TNC] JSON decoding error", e=err)
# exception, if JSON cant be decoded
except Exception as e:
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
def send_tnc_state(): def send_tnc_state():
""" """
send the tnc state to network send the tnc state to network
""" """
encoding = 'utf-8' encoding = "utf-8"
output = { output = {
"command": "tnc_state", "command": "tnc_state",
@ -390,7 +394,7 @@ def send_tnc_state():
"frequency": str(static.HAMLIB_FREQUENCY), "frequency": str(static.HAMLIB_FREQUENCY),
"speed_level": str(static.ARQ_SPEED_LEVEL), "speed_level": str(static.ARQ_SPEED_LEVEL),
"mode": str(static.HAMLIB_MODE), "mode": str(static.HAMLIB_MODE),
"bandwith": str(static.HAMLIB_BANDWITH), "bandwidth": str(static.HAMLIB_BANDWIDTH),
"fft": str(static.FFT), "fft": str(static.FFT),
"channel_busy": str(static.CHANNEL_BUSY), "channel_busy": str(static.CHANNEL_BUSY),
"scatter": static.SCATTER, "scatter": static.SCATTER,
@ -401,8 +405,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),
@ -412,8 +416,8 @@ def send_tnc_state():
# add heard stations to heard stations object # add heard stations to heard stations object
for heard in static.HEARD_STATIONS: for heard in static.HEARD_STATIONS:
output["stations"].append({ output["stations"].append({
"dxcallsign": str(heard[0], 'utf-8'), "dxcallsign": str(heard[0], "utf-8"),
"dxgrid": str(heard[1], 'utf-8'), "dxgrid": str(heard[1], "utf-8"),
"timestamp": heard[2], "timestamp": heard[2],
"datatype": heard[3], "datatype": heard[3],
"snr": heard[4], "snr": heard[4],
@ -422,6 +426,9 @@ def send_tnc_state():
return json.dumps(output) return json.dumps(output)
# This has apparently been taken out of a class, but is never called because
# the `self.request.sendall` call is a syntax error as `self` is undefined.
def process_daemon_commands(data): def process_daemon_commands(data):
""" """
process daemon commands process daemon commands
@ -434,39 +441,41 @@ def process_daemon_commands(data):
""" """
# convert data to json object # convert data to json object
received_json = json.loads(data) received_json = json.loads(data)
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json) log.debug("[SCK] CMD", command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'mycallsign': if received_json["type"] == "set" and received_json["command"] == "mycallsign":
try: try:
callsign = received_json["parameter"] callsign = received_json["parameter"]
if bytes(callsign, 'utf-8') == b'': if bytes(callsign, "utf-8") == b"":
self.request.sendall(b'INVALID CALLSIGN') self.request.sendall(b"INVALID CALLSIGN")
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC) log.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) log.info("[DMN] SET MYCALL", call=static.MYCALLSIGN,
except Exception as e: crc=static.MYCALLSIGN_CRC)
except Exception as err:
command_response("mycallsign", False) command_response("mycallsign", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'mygrid': if received_json["type"] == "set" and received_json["command"] == "mygrid":
try: try:
mygrid = received_json["parameter"] mygrid = received_json["parameter"]
if bytes(mygrid, 'utf-8') == b'': if bytes(mygrid, "utf-8") == b"":
self.request.sendall(b'INVALID GRID') self.request.sendall(b"INVALID GRID")
else: else:
static.MYGRID = bytes(mygrid, 'utf-8') static.MYGRID = bytes(mygrid, "utf-8")
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID) log.info("[SCK] SET MYGRID", grid=static.MYGRID)
command_response("mygrid", True) command_response("mygrid", True)
except Exception as e: except Exception as err:
command_response("mygrid", False) command_response("mygrid", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED: if received_json["type"] == "set" and received_json["command"] == "start_tnc" and not static.TNCSTARTED:
try: try:
mycall = str(received_json["parameter"][0]["mycall"]) mycall = str(received_json["parameter"][0]["mycall"])
mygrid = str(received_json["parameter"][0]["mygrid"]) mygrid = str(received_json["parameter"][0]["mygrid"])
@ -486,7 +495,7 @@ def process_daemon_commands(data):
enable_scatter = str(received_json["parameter"][0]["enable_scatter"]) enable_scatter = str(received_json["parameter"][0]["enable_scatter"])
enable_fft = str(received_json["parameter"][0]["enable_fft"]) enable_fft = str(received_json["parameter"][0]["enable_fft"])
enable_fsk = str(received_json["parameter"][0]["enable_fsk"]) enable_fsk = str(received_json["parameter"][0]["enable_fsk"])
low_bandwith_mode = str(received_json["parameter"][0]["low_bandwith_mode"]) low_bandwidth_mode = str(received_json["parameter"][0]["low_bandwidth_mode"])
tuning_range_fmin = str(received_json["parameter"][0]["tuning_range_fmin"]) tuning_range_fmin = str(received_json["parameter"][0]["tuning_range_fmin"])
tuning_range_fmax = str(received_json["parameter"][0]["tuning_range_fmax"]) tuning_range_fmax = str(received_json["parameter"][0]["tuning_range_fmax"])
tx_audio_level = str(received_json["parameter"][0]["tx_audio_level"]) tx_audio_level = str(received_json["parameter"][0]["tx_audio_level"])
@ -494,40 +503,40 @@ 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]) log.debug(f"[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_bandwidth_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 err:
command_response("start_tnc", False) command_response("start_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'get' and received_json["command"] == 'test_hamlib': if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
try: try:
devicename = str(received_json["parameter"][0]["devicename"]) devicename = str(received_json["parameter"][0]["devicename"])
deviceport = str(received_json["parameter"][0]["deviceport"]) deviceport = str(received_json["parameter"][0]["deviceport"])
@ -541,36 +550,37 @@ def process_daemon_commands(data):
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"]) rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
rigctld_port = str(received_json["parameter"][0]["rigctld_port"]) rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
DAEMON_QUEUE.put(['TEST_HAMLIB', DAEMON_QUEUE.put(["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 err:
command_response("test_hamlib", False) command_response("test_hamlib", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'stop_tnc': if received_json["type"] == "set" and received_json["command"] == "stop_tnc":
try: try:
static.TNCPROCESS.kill() static.TNCPROCESS.kill()
# unregister process from atexit to avoid process zombies # unregister process from atexit to avoid process zombies
atexit.unregister(static.TNCPROCESS.kill) atexit.unregister(static.TNCPROCESS.kill)
structlog.get_logger("structlog").warning("[DMN] Stopping TNC") log.warning("[DMN] Stopping TNC")
static.TNCSTARTED = False static.TNCSTARTED = False
command_response("stop_tnc", True) command_response("stop_tnc", True)
except Exception as e: except Exception as err:
command_response("stop_tnc", False) command_response("stop_tnc", False)
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json) log.warning("[SCK] command execution error", e=err, command=received_json)
def send_daemon_state(): def send_daemon_state():
""" """
@ -580,32 +590,32 @@ def send_daemon_state():
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}" python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
output = { output = {
'command': 'daemon_state', "command": "daemon_state",
'daemon_state': [], "daemon_state": [],
'python_version': str(python_version), "python_version": str(python_version),
'hamlib_version': static.HAMLIB_VERSION, "hamlib_version": static.HAMLIB_VERSION,
'input_devices': static.AUDIO_INPUT_DEVICES, "input_devices": static.AUDIO_INPUT_DEVICES,
'output_devices': static.AUDIO_OUTPUT_DEVICES, "output_devices": static.AUDIO_OUTPUT_DEVICES,
'serial_devices': static.SERIAL_DEVICES, "serial_devices": static.SERIAL_DEVICES,
#'cpu': str(psutil.cpu_percent()), # "cpu": str(psutil.cpu_percent()),
#'ram': str(psutil.virtual_memory().percent), # "ram": str(psutil.virtual_memory().percent),
'version': '0.1' "version": "0.1"
} }
if static.TNCSTARTED: if static.TNCSTARTED:
output["daemon_state"].append({"status": "running"}) output["daemon_state"].append({"status": "running"})
else: else:
output["daemon_state"].append({"status": "stopped"}) output["daemon_state"].append({"status": "stopped"})
jsondata = json.dumps(output) return json.dumps(output)
return jsondata except Exception as err:
except Exception as e: log.warning("[SCK] error", e=err)
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

@ -8,115 +8,118 @@ Here we are saving application wide variables and stats, which have to be access
Not nice, suggestions are appreciated :-) Not nice, suggestions are appreciated :-)
""" """
VERSION = '0.4.0-alpha' import subprocess
VERSION = "0.4.0-alpha"
# DAEMON # DAEMON
DAEMONPORT = 3001 DAEMONPORT: int = 3001
TNCSTARTED = False TNCSTARTED: bool = False
TNCPROCESS = 0 TNCPROCESS: subprocess.Popen
# Operator Defaults # Operator Defaults
MYCALLSIGN = b'AA0AA' MYCALLSIGN: bytes = b"AA0AA"
MYCALLSIGN_CRC = b'A' MYCALLSIGN_CRC: bytes = b"A"
DXCALLSIGN = b'AA0AA' DXCALLSIGN: bytes = b"AA0AA"
DXCALLSIGN_CRC = b'A' DXCALLSIGN_CRC: bytes = b"A"
MYGRID = b'' MYGRID: bytes = b""
DXGRID = b'' DXGRID: bytes = b""
SSID_LIST = [] # ssid list we are responding to SSID_LIST: list = [] # ssid list we are responding to
LOW_BANDWITH_MODE = False LOW_BANDWIDTH_MODE: bool = False
# --------------------------------- # ---------------------------------
# Server Defaults # Server Defaults
HOST = "0.0.0.0" HOST: str = "0.0.0.0"
PORT = 3000 PORT: int = 3000
SOCKET_TIMEOUT = 1 # seconds SOCKET_TIMEOUT: int = 1 # seconds
# --------------------------------- # ---------------------------------
SERIAL_DEVICES = [] SERIAL_DEVICES: list = []
# --------------------------------- # ---------------------------------
PTT_STATE = False PTT_STATE: bool = False
TRANSMITTING = False TRANSMITTING: bool = False
HAMLIB_VERSION = '0' HAMLIB_VERSION: str = "0"
HAMLIB_PTT_TYPE = 'RTS' HAMLIB_PTT_TYPE: str = "RTS"
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO' HAMLIB_DEVICE_NAME: str = "RIG_MODEL_DUMMY_NOVFO"
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0' HAMLIB_DEVICE_PORT: str = "/dev/ttyUSB0"
HAMLIB_SERIAL_SPEED = '9600' HAMLIB_SERIAL_SPEED: str = "9600"
HAMLIB_PTT_PORT = '/dev/ttyUSB0' HAMLIB_PTT_PORT: str = "/dev/ttyUSB0"
HAMLIB_STOP_BITS = '1' HAMLIB_STOP_BITS: str = "1"
HAMLIB_DATA_BITS = '8' HAMLIB_DATA_BITS: str = "8"
HAMLIB_HANDSHAKE = 'None' HAMLIB_HANDSHAKE: str = "None"
HAMLIB_RADIOCONTROL = 'direct' HAMLIB_RADIOCONTROL: str = "direct"
HAMLIB_RIGCTLD_IP = '127.0.0.1' HAMLIB_RIGCTLD_IP: str = "127.0.0.1"
HAMLIB_RIGCTLD_PORT = '4532' HAMLIB_RIGCTLD_PORT: str = "4532"
HAMLIB_FREQUENCY = 0 HAMLIB_FREQUENCY: int = 0
HAMLIB_MODE = '' HAMLIB_MODE: str = ""
HAMLIB_BANDWITH = 0 HAMLIB_BANDWIDTH: int = 0
# ------------------------- # -------------------------
# FreeDV Defaults # FreeDV Defaults
SNR = 0 SNR: float = 0
FREQ_OFFSET = 0 FREQ_OFFSET: float = 0
SCATTER = [] SCATTER: list = []
ENABLE_SCATTER = False ENABLE_SCATTER: bool = False
ENABLE_FSK = False ENABLE_FSK: bool = False
RESPOND_TO_CQ = False RESPOND_TO_CQ: bool = False
# --------------------------------- # ---------------------------------
# Audio Defaults # Audio Defaults
TX_AUDIO_LEVEL = 50 TX_AUDIO_LEVEL: int = 50
AUDIO_INPUT_DEVICES = [] AUDIO_INPUT_DEVICES: list = []
AUDIO_OUTPUT_DEVICES = [] AUDIO_OUTPUT_DEVICES: list = []
AUDIO_INPUT_DEVICE = -2 AUDIO_INPUT_DEVICE: int = -2
AUDIO_OUTPUT_DEVICE = -2 AUDIO_OUTPUT_DEVICE: int = -2
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0] BUFFER_OVERFLOW_COUNTER: list = [0, 0, 0, 0, 0]
AUDIO_RMS = 0 AUDIO_RMS: int = 0
FFT = [0] FFT: list = [0]
ENABLE_FFT = False ENABLE_FFT: bool = False
CHANNEL_BUSY = None CHANNEL_BUSY: bool = False
# ARQ PROTOCOL VERSION # ARQ PROTOCOL VERSION
ARQ_PROTOCOL_VERSION = 1 ARQ_PROTOCOL_VERSION: int = 1
# ARQ statistics # ARQ statistics
ARQ_BYTES_PER_MINUTE_BURST = 0 ARQ_BYTES_PER_MINUTE_BURST: int = 0
ARQ_BYTES_PER_MINUTE = 0 ARQ_BYTES_PER_MINUTE: int = 0
ARQ_BITS_PER_SECOND_BURST = 0 ARQ_BITS_PER_SECOND_BURST: int = 0
ARQ_BITS_PER_SECOND = 0 ARQ_BITS_PER_SECOND: int = 0
ARQ_COMPRESSION_FACTOR = 0 ARQ_COMPRESSION_FACTOR: int = 0
ARQ_TRANSMISSION_PERCENT = 0 ARQ_TRANSMISSION_PERCENT: int = 0
ARQ_SPEED_LEVEL = 0 ARQ_SPEED_LEVEL: int = 0
TOTAL_BYTES = 0 TOTAL_BYTES: int = 0
#CHANNEL_STATE = 'RECEIVING_SIGNALLING' # CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = 'IDLE' TNC_STATE: str = "IDLE"
ARQ_STATE = False ARQ_STATE: bool = False
ARQ_SESSION = False ARQ_SESSION: bool = False
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed # disconnected, connecting, connected, disconnecting, failed
ARQ_SESSION_STATE: str = "disconnected"
# BEACON STATE # BEACON STATE
BEACON_STATE = False BEACON_STATE: bool = False
BEACON_PAUSE = False BEACON_PAUSE: bool = False
# ------- RX BUFFER # ------- RX BUFFER
RX_BUFFER = [] RX_BUFFER: list = []
RX_MSG_BUFFER = [] RX_MSG_BUFFER: list = []
RX_BURST_BUFFER = [] RX_BURST_BUFFER: list = []
RX_FRAME_BUFFER = b'' RX_FRAME_BUFFER: bytes = b""
#RX_BUFFER_SIZE = 0 # RX_BUFFER_SIZE: int = 0
# ------- HEARD STATIOS BUFFER # ------- HEARD STATIONS BUFFER
HEARD_STATIONS = [] HEARD_STATIONS: list = []
# ------- INFO MESSAGE BUFFER # ------- INFO MESSAGE BUFFER
INFO = [] INFO: list = []
# ------- CODEC2 SETTINGS # ------- CODEC2 SETTINGS
TUNING_RANGE_FMIN = -50.0 TUNING_RANGE_FMIN: float = -50.0
TUNING_RANGE_FMAX = 50.0 TUNING_RANGE_FMAX: float = 50.0

View file

@ -6,19 +6,14 @@ import pyaudio
def list_audio_devices(): def list_audio_devices():
p = pyaudio.PyAudio() p = pyaudio.PyAudio()
devices = []
print("--------------------------------------------------------------------") print("--------------------------------------------------------------------")
for x in range(0, p.get_device_count()): devices = [
devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}") f"{x} - {p.get_device_info_by_index(x)['name']}"
for x in range(p.get_device_count())
for line in devices: ]
print(line)
for line in devices:
print(line)
list_audio_devices() list_audio_devices()

View file

@ -11,10 +11,7 @@ import sys
import argparse import argparse
import time import time
# --------------------------------------------GET PARAMETER INPUTS
#--------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC') parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--port', dest="socket_port", default=3000, help="Set the port, the socket is listening on.", type=int) parser.add_argument('--port', dest="socket_port", default=3000, help="Set the port, the socket is listening on.", type=int)
parser.add_argument('--data', dest="data", default=False, help="data", type=str) parser.add_argument('--data', dest="data", default=False, help="data", type=str)

View file

@ -6,13 +6,14 @@ Created on Fri Dec 11 21:53:35 2020
@author: parallels @author: parallels
""" """
import socket
import sys
import argparse import argparse
import random import random
import socket
#https://www.askpython.com/python/examples/generate-random-strings-in-python
def create_string(length): def create_string(length):
# https://www.askpython.com/python/examples/generate-random-strings-in-python
random_string = '' random_string = ''
for _ in range(length): for _ in range(length):
# Considering only upper and lowercase letters # Considering only upper and lowercase letters
@ -22,47 +23,32 @@ def create_string(length):
random_integer = random_integer - 32 if flip_bit == 1 else random_integer random_integer = random_integer - 32 if flip_bit == 1 else random_integer
# Keep appending random characters using chr(x) # Keep appending random characters using chr(x)
random_string += (chr(random_integer)) random_string += (chr(random_integer))
print("STR:" + str(random_string)) print(f"STR: {random_string!s}")
return random_string
#--------------------------------------------GET PARAMETER INPUTS return random_string
# --------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC') parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--port', dest="socket_port", default=9000, help="Set the port, the socket is listening on.", type=int) parser.add_argument('--port', dest="socket_port", default=9000, help="Set the port, the socket is listening on.", type=int)
#parser.add_argument('--data', dest="data", default=False, help="data", type=str) # parser.add_argument('--data', dest="data", default=False, help="data", type=str)
parser.add_argument('--random', dest="datalength", default=False, help="data", type=int) parser.add_argument('--random', dest="datalength", default=False, help="data", type=int)
args = parser.parse_args() args = parser.parse_args()
data = create_string(args.datalength) data = create_string(args.datalength)
data = bytes("ARQ:DATA:" + "" + data + "" + "\n", "utf-8") data = bytes("ARQ:DATA:" + "" + data + "" + "\n", "utf-8")
#print(data)
HOST, PORT = "localhost", args.socket_port HOST, PORT = "localhost", args.socket_port
#data = args.data # data = args.data
# Create a socket (SOCK_STREAM means a TCP socket) # Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data # Connect to server and send data
sock.connect((HOST, PORT)) sock.connect((HOST, PORT))
#sock.sendall(bytes(data + "\n", "utf-8")) # sock.sendall(bytes(data + "\n", "utf-8"))
sock.sendall(data) sock.sendall(data)
# Receive data from the server and shut down # Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8") received = str(sock.recv(1024), "utf-8")
print("Sent: {}".format(data)) print(f"Sent: {data}")