mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #201 from DJ2LS/pep8_improvements
This commit is contained in:
commit
8b9b54591f
2
.github/workflows/ctest.yml
vendored
2
.github/workflows/ctest.yml
vendored
|
@ -4,7 +4,7 @@ on: [push]
|
|||
|
||||
jobs:
|
||||
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
|
||||
# cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
|
|
|
@ -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.
|
||||
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](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
|
||||
* xssfox, her repository helped me a lot in an early stage of development -
|
||||
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
|
||||
Download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies
|
||||
|
|
|
@ -217,7 +217,7 @@ exports.getDaemonState = function() {
|
|||
// START TNC
|
||||
// ` `== 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({
|
||||
type: 'set',
|
||||
command: 'start_tnc',
|
||||
|
@ -240,7 +240,7 @@ exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, de
|
|||
enable_scatter: enable_scatter,
|
||||
enable_fft: enable_fft,
|
||||
enable_fsk: enable_fsk,
|
||||
low_bandwith_mode : low_bandwith_mode,
|
||||
low_bandwidth_mode : low_bandwidth_mode,
|
||||
tuning_range_fmin : tuning_range_fmin,
|
||||
tuning_range_fmax : tuning_range_fmax,
|
||||
tx_audio_level : tx_audio_level,
|
||||
|
|
|
@ -68,7 +68,7 @@ const configDefaultSettings = '{\
|
|||
"enable_scatter" : "False",\
|
||||
"enable_fft" : "False",\
|
||||
"enable_fsk" : "False",\
|
||||
"low_bandwith_mode" : "False",\
|
||||
"low_bandwidth_mode" : "False",\
|
||||
"theme" : "default",\
|
||||
"screen_height" : 430,\
|
||||
"screen_width" : 1050,\
|
||||
|
|
|
@ -112,7 +112,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
|
|||
|
||||
document.getElementById("scatterSwitch").value = config.enable_scatter;
|
||||
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("respondCQSwitch").value = config.respond_to_cq;
|
||||
|
||||
|
@ -132,7 +132,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
|
|||
document.getElementById("fftSwitch").checked = false;
|
||||
}
|
||||
|
||||
if(config.low_bandwith_mode == 'True'){
|
||||
if(config.low_bandwidth_mode == 'True'){
|
||||
document.getElementById("500HzModeSwitch").checked = true;
|
||||
} else {
|
||||
document.getElementById("500HzModeSwitch").checked = false;
|
||||
|
@ -522,9 +522,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
|
|||
// enable 500z Switch clicked
|
||||
document.getElementById("500HzModeSwitch").addEventListener("click", () => {
|
||||
if(document.getElementById("500HzModeSwitch").checked == true){
|
||||
config.low_bandwith_mode = "True";
|
||||
config.low_bandwidth_mode = "True";
|
||||
} else {
|
||||
config.low_bandwith_mode = "False";
|
||||
config.low_bandwidth_mode = "False";
|
||||
}
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
});
|
||||
|
@ -650,9 +650,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
|
|||
}
|
||||
|
||||
if (document.getElementById("500HzModeSwitch").checked == true){
|
||||
var low_bandwith_mode = "True";
|
||||
var low_bandwidth_mode = "True";
|
||||
} else {
|
||||
var low_bandwith_mode = "False";
|
||||
var low_bandwidth_mode = "False";
|
||||
}
|
||||
|
||||
if (document.getElementById("fskModeSwitch").checked == true){
|
||||
|
@ -732,7 +732,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
|
|||
config.enable_scatter = enable_scatter;
|
||||
config.enable_fft = enable_fft;
|
||||
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.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
|
||||
document.getElementById("mode").innerHTML = arg.mode;
|
||||
|
||||
// SET BANDWITH
|
||||
document.getElementById("bandwith").innerHTML = arg.bandwith;
|
||||
// SET bandwidth
|
||||
document.getElementById("bandwidth").innerHTML = arg.bandwidth;
|
||||
|
||||
// SET BYTES PER MINUTE
|
||||
if (typeof(arg.arq_bytes_per_minute) == 'undefined') {
|
||||
|
|
|
@ -55,7 +55,7 @@ client.on('connect', function(data) {
|
|||
//channel_state: "-",
|
||||
frequency: "-",
|
||||
mode: "-",
|
||||
bandwith: "-",
|
||||
bandwidth: "-",
|
||||
rms_level: 0
|
||||
};
|
||||
ipcRenderer.send('request-update-tnc-state', Data);
|
||||
|
@ -84,7 +84,7 @@ client.on('error', function(data) {
|
|||
//channel_state: "-",
|
||||
frequency: "-",
|
||||
mode: "-",
|
||||
bandwith: "-",
|
||||
bandwidth: "-",
|
||||
rms_level: 0
|
||||
|
||||
};
|
||||
|
@ -199,7 +199,7 @@ client.on('data', function(socketdata) {
|
|||
frequency: data['frequency'],
|
||||
speed_level: data['speed_level'],
|
||||
mode: data['mode'],
|
||||
bandwith: data['bandwith'],
|
||||
bandwidth: data['bandwidth'],
|
||||
rms_level: data['audio_rms'],
|
||||
fft: data['fft'],
|
||||
channel_busy: data['channel_busy'],
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<! ------Chats area ---------------------------------------------------------------------->
|
||||
<div class="container-fluid m-0 p-0">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -61,7 +61,7 @@
|
|||
<div class="container-fluid mt-2 p-0">
|
||||
<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>-->
|
||||
<!--<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>-->
|
||||
|
||||
<textarea class="form-control rounded-pill m-1 p-1" rows="1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></textarea>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
</button>
|
||||
</span>
|
||||
<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>
|
||||
</button>
|
||||
</span>
|
||||
|
@ -1023,7 +1023,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end of blur div -->
|
||||
<!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------>
|
||||
<nav class="navbar fixed-bottom navbar-light bg-light">
|
||||
|
@ -1054,7 +1053,7 @@
|
|||
<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>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 class="container-fluid p-0" style="width:12rem">
|
||||
|
|
|
@ -102,7 +102,7 @@ python3 test_tx.py --mode datac1 --delay 500 --frames 2 --bursts 1 | python3 tes
|
|||
|
||||
## AUDIO test via virtual audio devices
|
||||
### 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
|
||||
```
|
||||
|
|
|
@ -18,6 +18,7 @@ class DEBUGLEVEL(Enum):
|
|||
RIG_DEBUG_TRACE = 5
|
||||
RIG_DEBUG_CACHE = 6
|
||||
|
||||
|
||||
class RETCODE(Enum):
|
||||
RIG_OK = 0
|
||||
RIG_EINVAL = 1
|
||||
|
@ -38,13 +39,9 @@ class RETCODE(Enum):
|
|||
RIG_EVFO = 16
|
||||
RIG_EDOM = 17
|
||||
|
||||
|
||||
|
||||
|
||||
libname = pathlib.Path("../tnc/lib/hamlib/linux/libhamlib.so")
|
||||
hamlib = ctypes.CDLL(libname)
|
||||
|
||||
|
||||
class SERIAL(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("data_bits", ctypes.c_int),
|
||||
|
@ -54,16 +51,19 @@ class SERIAL(ctypes.Structure):
|
|||
("handshake", ctypes.c_void_p),
|
||||
]
|
||||
|
||||
|
||||
class PARM(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("serial", SERIAL),
|
||||
]
|
||||
|
||||
|
||||
class TYPE(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("rig", ctypes.c_void_p),
|
||||
]
|
||||
|
||||
|
||||
class MYPORT(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("pathname", ctypes.c_char),
|
||||
|
@ -82,8 +82,6 @@ myport.parm.serial.data_bits = 7
|
|||
myport.parm.serial.stop_bits = 2
|
||||
myport.parm.serial.rate = 9600
|
||||
|
||||
|
||||
|
||||
rig = hamlib.rig_init(myrig_model)
|
||||
|
||||
retcode = hamlib.rig_set_parm(rig, 'stop_bits', 5)
|
||||
|
@ -111,13 +109,9 @@ print(retcode)
|
|||
'''
|
||||
retcode = hamlib.rig_open(rig)
|
||||
print(retcode)
|
||||
|
||||
|
||||
hamlib.rig_close(rig)
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# riginfo = create_string_buffer(1024)
|
||||
# retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ for i in range(N_BURSTS):
|
|||
) # 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
|
||||
] = 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)
|
||||
|
|
10
test/pong.py
10
test/pong.py
|
@ -101,7 +101,7 @@ def send_pong(burst,n_total_burst,frame,n_total_frame):
|
|||
mod_out_preamble = mod_out_preamble()
|
||||
|
||||
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 = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
|
||||
|
@ -129,17 +129,15 @@ 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 = bytes_out() # get pointer from bytes_out
|
||||
|
||||
|
||||
|
||||
receive = True
|
||||
while receive == True:
|
||||
while receive:
|
||||
time.sleep(0.01)
|
||||
|
||||
data_in = b''
|
||||
|
||||
nin = c_lib.freedv_nin(freedv)
|
||||
nin_converted = int(nin*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE))
|
||||
if DEBUGGING_MODE == True:
|
||||
if DEBUGGING_MODE:
|
||||
print("-----------------------------")
|
||||
print("NIN: " + str(nin) + " [ " + str(nin_converted) + " ]")
|
||||
|
||||
|
@ -149,7 +147,7 @@ while receive == True:
|
|||
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
|
||||
|
||||
if DEBUGGING_MODE == True:
|
||||
if DEBUGGING_MODE:
|
||||
print("SYNC: " + str(c_lib.freedv_get_rx_status(freedv)))
|
||||
|
||||
if nbytes == bytes_per_frame:
|
||||
|
|
|
@ -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.
|
||||
assert False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run pytest with the current script as the filename.
|
||||
ecode = pytest.main(["-v", sys.argv[0]])
|
||||
|
|
|
@ -14,7 +14,7 @@ import numpy as np
|
|||
import pytest
|
||||
|
||||
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
|
||||
READ_SZ = 8
|
||||
NTESTS = 10000
|
||||
|
|
|
@ -72,7 +72,7 @@ class Test:
|
|||
self.AUDIO_SAMPLE_RATE_RX / self.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 self.AUDIO_INPUT_DEVICE != -1:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
|
|
@ -71,7 +71,7 @@ class Test:
|
|||
self.AUDIO_SAMPLE_RATE_RX / self.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 self.AUDIO_INPUT_DEVICE != -1:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
|
|
@ -77,7 +77,7 @@ class Test:
|
|||
|
||||
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:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
@ -189,7 +189,7 @@ class Test:
|
|||
payload_per_frame = bytes_per_frame - 2
|
||||
|
||||
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
|
||||
|
||||
crc = ctypes.c_ushort(
|
||||
|
|
|
@ -76,7 +76,7 @@ class Test:
|
|||
self.AUDIO_SAMPLE_RATE_RX / self.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 self.AUDIO_INPUT_DEVICE != -1:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
|
|
@ -76,7 +76,7 @@ class Test:
|
|||
self.AUDIO_SAMPLE_RATE_RX / self.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 self.AUDIO_INPUT_DEVICE != -1:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
|
|
@ -82,7 +82,7 @@ class Test:
|
|||
|
||||
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:
|
||||
self.p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
@ -196,7 +196,7 @@ class Test:
|
|||
) # use this if CRC16 checksum is required ( DATA1-3)
|
||||
buffer[
|
||||
: 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
|
||||
# crc algorithm incompatibilities
|
||||
|
|
|
@ -67,7 +67,7 @@ def test_mm_rx():
|
|||
|
||||
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:
|
||||
p_audio = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
|
|
|
@ -93,7 +93,7 @@ def test_mm_tx():
|
|||
payload_per_frame = bytes_per_frame - 2
|
||||
|
||||
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
|
||||
|
||||
# Generate CRC16
|
||||
|
|
|
@ -47,7 +47,7 @@ def test_rx():
|
|||
# make sure our resampler will work
|
||||
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:
|
||||
# auto search for loopback devices
|
||||
if AUDIO_INPUT_DEVICE == -2:
|
||||
|
|
|
@ -107,7 +107,7 @@ def test_valid_disconnect(mycall: str, dxcall: str):
|
|||
# Set the SSIDs we'll use for this test.
|
||||
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 = helpers.bytes_to_callsign(mycallsign_bytes)
|
||||
static.MYCALLSIGN = mycallsign
|
||||
|
@ -160,7 +160,7 @@ def test_foreign_disconnect(mycall: str, dxcall: str):
|
|||
:return: Bytearray of the requested frame
|
||||
: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 = helpers.bytes_to_callsign(mycallsign_bytes)
|
||||
static.MYCALLSIGN = mycallsign
|
||||
|
|
|
@ -37,7 +37,7 @@ def test_tx():
|
|||
AUDIO_SAMPLE_RATE_TX = 48000
|
||||
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:
|
||||
# auto search for loopback devices
|
||||
if AUDIO_OUTPUT_DEVICE == -2:
|
||||
|
@ -109,7 +109,7 @@ def test_tx():
|
|||
# Create buffer for data
|
||||
# Use this if CRC16 checksum is required (DATA1-3)
|
||||
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
|
||||
|
||||
# Create CRC for data frame - we are using the CRC function shipped with codec2 to avoid
|
||||
|
|
41
tnc/audio.py
41
tnc/audio.py
|
@ -1,22 +1,23 @@
|
|||
|
||||
"""
|
||||
Gather information about audio devices.
|
||||
"""
|
||||
import atexit
|
||||
import json
|
||||
import multiprocessing
|
||||
import sys
|
||||
|
||||
import sounddevice as sd
|
||||
|
||||
atexit.register(sd._terminate)
|
||||
|
||||
|
||||
def get_audio_devices():
|
||||
"""
|
||||
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
|
||||
|
||||
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.get_context('spawn')
|
||||
# multiprocessing.get_context("spawn")
|
||||
|
||||
# we need to reset and initialize sounddevice before running the multiprocessing part.
|
||||
# If we are not doing this at this early point, not all devices will be displayed
|
||||
|
@ -27,40 +28,40 @@ def get_audio_devices():
|
|||
proxy_input_devices = manager.list()
|
||||
proxy_output_devices = manager.list()
|
||||
# print(multiprocessing.get_start_method())
|
||||
p = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
|
||||
p.start()
|
||||
p.join()
|
||||
proc = multiprocessing.Process(target=fetch_audio_devices, args=(proxy_input_devices, proxy_output_devices))
|
||||
proc.start()
|
||||
proc.join()
|
||||
|
||||
return list(proxy_input_devices), list(proxy_output_devices)
|
||||
|
||||
|
||||
def fetch_audio_devices(input_devices, output_devices):
|
||||
"""
|
||||
get audio devices from portaudio
|
||||
|
||||
Args:
|
||||
input_devices: proxy variable for input devices
|
||||
output_devices: proxy variable for outout devices
|
||||
output_devices: proxy variable for output devices
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
devices = sd.query_devices(device=None, kind=None)
|
||||
for index, device in enumerate(devices):
|
||||
#for i in range(0, p.get_device_count()):
|
||||
# we need to do a try exception, beacuse for windows theres no audio device range
|
||||
# we need to do a try exception, because for windows there's no audio device range
|
||||
try:
|
||||
name = device["name"]
|
||||
|
||||
maxOutputChannels = device["max_output_channels"]
|
||||
maxInputChannels = device["max_input_channels"]
|
||||
max_output_channels = device["max_output_channels"]
|
||||
max_input_channels = device["max_input_channels"]
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
maxInputChannels = 0
|
||||
maxOutputChannels = 0
|
||||
name = ''
|
||||
except Exception as err:
|
||||
print(err)
|
||||
max_input_channels = 0
|
||||
max_output_channels = 0
|
||||
name = ""
|
||||
|
||||
if maxInputChannels > 0:
|
||||
if max_input_channels > 0:
|
||||
input_devices.append({"id": index, "name": name})
|
||||
if maxOutputChannels > 0:
|
||||
if max_output_channels > 0:
|
||||
output_devices.append({"id": index, "name": name})
|
||||
|
|
|
@ -42,6 +42,7 @@ def freedv_get_mode_value_by_name(mode: str) -> int:
|
|||
"""
|
||||
return FREEDV_MODE[mode].value
|
||||
|
||||
|
||||
# Function for returning the mode name
|
||||
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
|
||||
|
||||
|
||||
# Check if we are running in a pyinstaller environment
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
sys.path.append(getattr(sys, "_MEIPASS"))
|
||||
|
@ -61,13 +63,13 @@ else:
|
|||
sys.path.append(os.path.abspath("."))
|
||||
|
||||
structlog.get_logger("structlog").info("[C2 ] Searching for libcodec2...")
|
||||
if sys.platform == 'linux':
|
||||
files = glob.glob(r'**/*libcodec2*',recursive=True)
|
||||
files.append('libcodec2.so')
|
||||
elif sys.platform == 'darwin':
|
||||
files = glob.glob(r'**/*libcodec2*.dylib',recursive=True)
|
||||
elif sys.platform in ['win32', 'win64']:
|
||||
files = glob.glob(r'**\*libcodec2*.dll',recursive=True)
|
||||
if sys.platform == "linux":
|
||||
files = glob.glob(r"**/*libcodec2*", recursive=True)
|
||||
files.append("libcodec2.so")
|
||||
elif sys.platform == "darwin":
|
||||
files = glob.glob(r"**/*libcodec2*.dylib", recursive=True)
|
||||
elif sys.platform in ["win32", "win64"]:
|
||||
files = glob.glob(r"**\*libcodec2*.dll", recursive=True)
|
||||
else:
|
||||
files = []
|
||||
|
||||
|
@ -77,11 +79,11 @@ for file in files:
|
|||
api = ctypes.CDLL(file)
|
||||
structlog.get_logger("structlog").info("[C2 ] Libcodec2 loaded", path=file)
|
||||
break
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=e)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").warning("[C2 ] Libcodec2 found but not loaded", path=file, e=err)
|
||||
|
||||
# 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")
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -144,6 +146,7 @@ api.FREEDV_MODE_DATAC3 = 12
|
|||
api.FREEDV_MODE_DATAC0 = 14
|
||||
api.FREEDV_MODE_FSK_LDPC = 9
|
||||
|
||||
|
||||
# -------------------------------- FSK LDPC MODE SETTINGS
|
||||
|
||||
# Advanced structure for fsk modes
|
||||
|
@ -159,14 +162,15 @@ class ADVANCED(ctypes.Structure):
|
|||
("codename", ctypes.c_char_p),
|
||||
]
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
adv.interleave_frames = 0 # max amplitude
|
||||
adv.M = 2 # number of fsk tones 2/4
|
||||
adv.Rs = 100 # symbol rate
|
||||
adv.Fs = 8000 # sample rate
|
||||
adv.first_tone = 1500 # first tone freq
|
||||
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_56_56 rate 0.50 (112,56) BPF: 7 not working
|
||||
|
@ -179,7 +183,7 @@ H_128_256_5 rate 0.50 (256,128) BPF: 16 working
|
|||
H_4096_8192_3d rate 0.50 (8192,4096) BPF: 512 not working
|
||||
H_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
|
||||
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
|
||||
'''
|
||||
"""
|
||||
# --------------- 2 FSK H_128_256_5, 16 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED()
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0
|
||||
|
@ -188,7 +192,7 @@ api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 100
|
|||
api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1400 # 1150 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 120 # 200
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = 'H_128_256_5'.encode('utf-8') # code word
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = "H_128_256_5".encode("utf-8") # code word
|
||||
|
||||
# --------------- 4 H_256_512_4, 7 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED()
|
||||
|
@ -198,7 +202,7 @@ api.FREEDV_MODE_FSK_LDPC_1_ADV.Rs = 100
|
|||
api.FREEDV_MODE_FSK_LDPC_1_ADV.Fs = 8000
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1250 # 1250 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = 'H_256_512_4'.encode('utf-8') # code word
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_256_512_4".encode("utf-8") # code word
|
||||
|
||||
# ------- MODEM STATS STRUCTURES
|
||||
MODEM_STATS_NC_MAX = 50 + 1
|
||||
|
@ -209,6 +213,7 @@ MODEM_STATS_NSPEC = 512
|
|||
MODEM_STATS_MAX_F_HZ = 4000
|
||||
MODEM_STATS_MAX_F_EST = 4
|
||||
|
||||
|
||||
# Modem stats structure
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
""" """
|
||||
|
@ -231,6 +236,7 @@ class MODEMSTATS(ctypes.Structure):
|
|||
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
|
||||
]
|
||||
|
||||
|
||||
# Return code flags for freedv_get_rx_status() function
|
||||
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
|
||||
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
|
||||
|
@ -255,13 +261,15 @@ api.rx_sync_flags_to_text = [
|
|||
"EBS-",
|
||||
"EBST"]
|
||||
|
||||
|
||||
# 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
|
||||
"""
|
||||
|
||||
# A buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
||||
# self.nbuffer is the current number of samples in the buffer
|
||||
def __init__(self, size):
|
||||
|
@ -304,14 +312,16 @@ class audio_buffer:
|
|||
assert self.nbuffer >= 0
|
||||
self.mutex.release()
|
||||
|
||||
|
||||
# Resampler ---------------------------------------------------------
|
||||
|
||||
api.FDMDV_OS_48 = int(6) # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = int(api.FDMDV_OS_TAPS_48K/api.FDMDV_OS_48) # number of OS filter taps at 8kHz
|
||||
api.FDMDV_OS_48 = 6 # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = 48 # number of OS filter taps at 48kHz
|
||||
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_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
|
||||
|
||||
|
||||
class resampler:
|
||||
"""
|
||||
Re-sampler class
|
||||
|
@ -375,7 +385,7 @@ class resampler:
|
|||
# In C: pin8=&in8_mem[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)
|
||||
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
|
||||
self.filter_mem8 = in8_mem[:self.MEM8]
|
||||
|
|
215
tnc/daemon.py
215
tnc/daemon.py
|
@ -15,8 +15,6 @@ import argparse
|
|||
import atexit
|
||||
import multiprocessing
|
||||
import os
|
||||
import queue
|
||||
import re
|
||||
import signal
|
||||
import socketserver
|
||||
import subprocess
|
||||
|
@ -24,17 +22,14 @@ import sys
|
|||
import threading
|
||||
import time
|
||||
|
||||
import crcengine
|
||||
import psutil
|
||||
import serial.tools.list_ports
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
import audio
|
||||
import helpers
|
||||
import crcengine
|
||||
import log_handler
|
||||
import serial.tools.list_ports
|
||||
import sock
|
||||
import static
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
|
||||
# signal handler for closing aplication
|
||||
|
@ -47,20 +42,24 @@ def signal_handler(sig, frame):
|
|||
|
||||
Returns: system exit
|
||||
"""
|
||||
print('Closing daemon...')
|
||||
print("Closing daemon...")
|
||||
sock.CLOSE_SIGNAL = True
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
class DAEMON():
|
||||
|
||||
class DAEMON:
|
||||
"""
|
||||
Daemon class
|
||||
|
||||
"""
|
||||
log = structlog.get_logger("DAEMON")
|
||||
|
||||
def __init__(self):
|
||||
# load crc engine
|
||||
self.crc_algorithm = crcengine.new('crc16-ccitt-false') # load crc8 library
|
||||
self.crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library
|
||||
|
||||
self.daemon_queue = sock.DAEMON_QUEUE
|
||||
update_audio_devices = threading.Thread(target=self.update_audio_devices, name="UPDATE_AUDIO_DEVICES", daemon=True)
|
||||
|
@ -76,12 +75,12 @@ class DAEMON():
|
|||
"""
|
||||
Update audio devices and set to static
|
||||
"""
|
||||
while 1:
|
||||
while True:
|
||||
try:
|
||||
if not static.TNCSTARTED:
|
||||
static.AUDIO_INPUT_DEVICES, static.AUDIO_OUTPUT_DEVICES = audio.get_audio_devices()
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] update_audio_devices: Exception gathering audio devices:", e=e)
|
||||
except Exception as err1:
|
||||
self.log.error("[DMN] update_audio_devices: Exception gathering audio devices:", e=err1)
|
||||
# print(e)
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -89,30 +88,29 @@ class DAEMON():
|
|||
"""
|
||||
Update serial devices and set to static
|
||||
"""
|
||||
while 1:
|
||||
while True:
|
||||
try:
|
||||
#print("update serial")
|
||||
serial_devices = []
|
||||
ports = serial.tools.list_ports.comports()
|
||||
for port, desc, hwid in ports:
|
||||
# calculate hex of hwid if we have unique names
|
||||
crc_hwid = self.crc_algorithm(bytes(hwid, encoding='utf-8'))
|
||||
crc_hwid = crc_hwid.to_bytes(2, byteorder='big')
|
||||
crc_hwid = self.crc_algorithm(bytes(hwid, encoding="utf-8"))
|
||||
crc_hwid = crc_hwid.to_bytes(2, byteorder="big")
|
||||
crc_hwid = crc_hwid.hex()
|
||||
description = f"{desc} [{crc_hwid}]"
|
||||
serial_devices.append({"port": str(port), "description": str(description)})
|
||||
|
||||
static.SERIAL_DEVICES = serial_devices
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] update_serial_devices: Exception gathering serial devices:", e=e)
|
||||
except Exception as err1:
|
||||
self.log.error("[DMN] update_serial_devices: Exception gathering serial devices:", e=err1)
|
||||
# print(e)
|
||||
|
||||
def worker(self):
|
||||
"""
|
||||
Worker to handle the received commands
|
||||
"""
|
||||
while 1:
|
||||
while True:
|
||||
try:
|
||||
data = self.daemon_queue.get()
|
||||
|
||||
|
@ -133,138 +131,138 @@ class DAEMON():
|
|||
# data[15] rigctld_port
|
||||
# data[16] send_scatter
|
||||
# data[17] send_fft
|
||||
# data[18] low_bandwith_mode
|
||||
# data[18] low_bandwidth_mode
|
||||
# data[19] tuning_range_fmin
|
||||
# data[20] tuning_range_fmax
|
||||
# data[21] enable FSK
|
||||
# data[22] tx-audio-level
|
||||
# data[23] respond_to_cq
|
||||
|
||||
if data[0] == 'STARTTNC':
|
||||
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||
if data[0] == "STARTTNC":
|
||||
self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||
|
||||
# list of parameters, necessary for running subprocess command as a list
|
||||
options = []
|
||||
|
||||
options.append('--port')
|
||||
options.append("--port")
|
||||
options.append(str(static.DAEMONPORT - 1))
|
||||
|
||||
options.append('--mycall')
|
||||
options.append("--mycall")
|
||||
options.append(data[1])
|
||||
|
||||
options.append('--mygrid')
|
||||
options.append("--mygrid")
|
||||
options.append(data[2])
|
||||
|
||||
options.append('--rx')
|
||||
options.append("--rx")
|
||||
options.append(data[3])
|
||||
|
||||
options.append('--tx')
|
||||
options.append("--tx")
|
||||
options.append(data[4])
|
||||
|
||||
# if radiocontrol != disabled
|
||||
# this should hopefully avoid a ton of problems if we are just running in
|
||||
# disabled mode
|
||||
|
||||
if data[13] != 'disabled':
|
||||
options.append('--devicename')
|
||||
if data[13] != "disabled":
|
||||
options.append("--devicename")
|
||||
options.append(data[5])
|
||||
|
||||
options.append('--deviceport')
|
||||
options.append("--deviceport")
|
||||
options.append(data[6])
|
||||
|
||||
options.append('--serialspeed')
|
||||
options.append("--serialspeed")
|
||||
options.append(data[7])
|
||||
|
||||
options.append('--pttprotocol')
|
||||
options.append("--pttprotocol")
|
||||
options.append(data[8])
|
||||
|
||||
options.append('--pttport')
|
||||
options.append("--pttport")
|
||||
options.append(data[9])
|
||||
|
||||
options.append('--data_bits')
|
||||
options.append("--data_bits")
|
||||
options.append(data[10])
|
||||
|
||||
options.append('--stop_bits')
|
||||
options.append("--stop_bits")
|
||||
options.append(data[11])
|
||||
|
||||
options.append('--handshake')
|
||||
options.append("--handshake")
|
||||
options.append(data[12])
|
||||
|
||||
options.append('--radiocontrol')
|
||||
options.append("--radiocontrol")
|
||||
options.append(data[13])
|
||||
|
||||
if data[13] == 'rigctld':
|
||||
options.append('--rigctld_ip')
|
||||
if data[13] == "rigctld":
|
||||
options.append("--rigctld_ip")
|
||||
options.append(data[14])
|
||||
|
||||
options.append('--rigctld_port')
|
||||
options.append("--rigctld_port")
|
||||
options.append(data[15])
|
||||
|
||||
if data[16] == 'True':
|
||||
options.append('--scatter')
|
||||
if data[16] == "True":
|
||||
options.append("--scatter")
|
||||
|
||||
if data[17] == 'True':
|
||||
options.append('--fft')
|
||||
if data[17] == "True":
|
||||
options.append("--fft")
|
||||
|
||||
if data[18] == 'True':
|
||||
options.append('--500hz')
|
||||
if data[18] == "True":
|
||||
options.append("--500hz")
|
||||
|
||||
options.append('--tuning_range_fmin')
|
||||
options.append("--tuning_range_fmin")
|
||||
options.append(data[19])
|
||||
|
||||
options.append('--tuning_range_fmax')
|
||||
options.append("--tuning_range_fmax")
|
||||
options.append(data[20])
|
||||
|
||||
# overriding FSK mode
|
||||
#if data[21] == 'True':
|
||||
# options.append('--fsk')
|
||||
# if data[21] == "True":
|
||||
# options.append("--fsk")
|
||||
|
||||
options.append('--tx-audio-level')
|
||||
options.append("--tx-audio-level")
|
||||
options.append(data[22])
|
||||
|
||||
if data[23] == 'True':
|
||||
options.append('--qrv')
|
||||
if data[23] == "True":
|
||||
options.append("--qrv")
|
||||
|
||||
# Try running tnc from binary, else run from source
|
||||
# This helps running the tnc in a developer environment
|
||||
try:
|
||||
command = []
|
||||
if sys.platform in ['linux', 'darwin']:
|
||||
command.append('./freedata-tnc')
|
||||
elif sys.platform in ['win32', 'win64']:
|
||||
command.append('freedata-tnc.exe')
|
||||
if sys.platform in ["linux", "darwin"]:
|
||||
command.append("./freedata-tnc")
|
||||
elif sys.platform in ["win32", "win64"]:
|
||||
command.append("freedata-tnc.exe")
|
||||
|
||||
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")
|
||||
except FileNotFoundError as e:
|
||||
structlog.get_logger("structlog").error("[DMN] worker: Exception:", e=e)
|
||||
self.log.info("[DMN] TNC started", path="binary")
|
||||
except FileNotFoundError as err1:
|
||||
self.log.error("[DMN] worker: Exception:", e=err1)
|
||||
command = []
|
||||
if sys.platform in ['linux', 'darwin']:
|
||||
command.append('python3')
|
||||
elif sys.platform in ['win32', 'win64']:
|
||||
command.append('python')
|
||||
if sys.platform in ["linux", "darwin"]:
|
||||
command.append("python3")
|
||||
elif sys.platform in ["win32", "win64"]:
|
||||
command.append("python")
|
||||
|
||||
command.append('main.py')
|
||||
command.append("main.py")
|
||||
command += options
|
||||
p = subprocess.Popen(command)
|
||||
atexit.register(p.kill)
|
||||
proc = subprocess.Popen(command)
|
||||
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
|
||||
'''
|
||||
"""
|
||||
# WE HAVE THIS PART in SOCKET
|
||||
if data[0] == 'STOPTNC':
|
||||
if data[0] == "STOPTNC":
|
||||
static.TNCPROCESS.kill()
|
||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
||||
self.log.warning("[DMN] Stopping TNC")
|
||||
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
||||
static.TNCSTARTED = False
|
||||
'''
|
||||
"""
|
||||
# data[1] devicename
|
||||
# data[2] deviceport
|
||||
# data[3] serialspeed
|
||||
|
@ -276,7 +274,7 @@ class DAEMON():
|
|||
# data[9] radiocontrol
|
||||
# data[10] rigctld_ip
|
||||
# data[11] rigctld_port
|
||||
if data[0] == 'TEST_HAMLIB':
|
||||
if data[0] == "TEST_HAMLIB":
|
||||
devicename = data[1]
|
||||
deviceport = data[2]
|
||||
serialspeed = data[3]
|
||||
|
@ -290,11 +288,11 @@ class DAEMON():
|
|||
rigctld_port = data[11]
|
||||
|
||||
# check how we want to control the radio
|
||||
if radiocontrol == 'direct':
|
||||
if radiocontrol == "direct":
|
||||
import rig
|
||||
elif radiocontrol == 'rigctl':
|
||||
elif radiocontrol == "rigctl":
|
||||
import rigctl as rig
|
||||
elif radiocontrol == 'rigctld':
|
||||
elif radiocontrol == "rigctld":
|
||||
import rigctld as rig
|
||||
else:
|
||||
import rigdummy as rig
|
||||
|
@ -304,20 +302,20 @@ class DAEMON():
|
|||
serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits,
|
||||
handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port)
|
||||
|
||||
hamlib_version = rig.hamlib_version
|
||||
# hamlib_version = rig.hamlib_version
|
||||
|
||||
hamlib.set_ptt(True)
|
||||
pttstate = hamlib.get_ptt()
|
||||
|
||||
if pttstate:
|
||||
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status='SUCCESS')
|
||||
response = {'command': 'test_hamlib', 'result': 'SUCCESS'}
|
||||
self.log.info("[DMN] Hamlib PTT", status="SUCCESS")
|
||||
response = {"command": "test_hamlib", "result": "SUCCESS"}
|
||||
elif not pttstate:
|
||||
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status='NO SUCCESS')
|
||||
response = {'command': 'test_hamlib', 'result': 'NOSUCCESS'}
|
||||
self.log.warning("[DMN] Hamlib PTT", status="NO SUCCESS")
|
||||
response = {"command": "test_hamlib", "result": "NOSUCCESS"}
|
||||
else:
|
||||
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status='FAILED')
|
||||
response = {'command': 'test_hamlib', 'result': 'FAILED'}
|
||||
self.log.error("[DMN] Hamlib PTT", status="FAILED")
|
||||
response = {"command": "test_hamlib", "result": "FAILED"}
|
||||
|
||||
hamlib.set_ptt(False)
|
||||
hamlib.close_rig()
|
||||
|
@ -325,39 +323,40 @@ class DAEMON():
|
|||
jsondata = json.dumps(response)
|
||||
sock.SOCKET_QUEUE.put(jsondata)
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] worker: Exception: ", e=e)
|
||||
# print(e)
|
||||
except Exception as err1:
|
||||
self.log.error("[DMN] worker: Exception: ", e=err1)
|
||||
|
||||
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()
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description='FreeDATA Daemon')
|
||||
PARSER.add_argument('--port', dest="socket_port", default=3001, help="Socket port in the range of 1024-65536", type=int)
|
||||
PARSER = argparse.ArgumentParser(description="FreeDATA Daemon")
|
||||
PARSER.add_argument("--port", dest="socket_port", default=3001, help="Socket port in the range of 1024-65536", type=int)
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
static.DAEMONPORT = ARGS.socket_port
|
||||
|
||||
try:
|
||||
if sys.platform == 'linux':
|
||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform == "linux":
|
||||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "daemon"
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform == "darwin":
|
||||
logging_path = os.getenv("HOME") + "/Library/" + "Application Support/" + "FreeDATA/" + "daemon"
|
||||
|
||||
if sys.platform in ['win32', 'win64']:
|
||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'daemon'
|
||||
if sys.platform in ["win32", "win64"]:
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "daemon"
|
||||
|
||||
if not os.path.exists(logging_path):
|
||||
os.makedirs(logging_path)
|
||||
log_handler.setup_logging(logging_path)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e)
|
||||
except Exception as err:
|
||||
mainlog.error("[DMN] logger init error", exception=err)
|
||||
|
||||
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
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
cmdserver = sock.ThreadedTCPServer((static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler)
|
||||
|
@ -365,11 +364,11 @@ if __name__ == '__main__':
|
|||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=e)
|
||||
except Exception as err:
|
||||
mainlog.error("[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err)
|
||||
sys.exit(1)
|
||||
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:
|
||||
time.sleep(1)
|
||||
|
|
File diff suppressed because it is too large
Load diff
104
tnc/helpers.py
104
tnc/helpers.py
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
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 crcengine
|
||||
import structlog
|
||||
|
||||
import static
|
||||
import structlog
|
||||
|
||||
|
||||
def wait(seconds: float) -> bool:
|
||||
|
@ -27,6 +25,7 @@ def wait(seconds: float) -> bool:
|
|||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
|
||||
def get_crc_8(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -40,11 +39,12 @@ def get_crc_8(data) -> bytes:
|
|||
Returns:
|
||||
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_data.to_bytes(1, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(1, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_16(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -58,11 +58,12 @@ def get_crc_16(data) -> bytes:
|
|||
Returns:
|
||||
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_data.to_bytes(2, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(2, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_24(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -77,13 +78,18 @@ def get_crc_24(data) -> bytes:
|
|||
Returns:
|
||||
CRC-24 (OpenPGP) of the provided data as bytes
|
||||
"""
|
||||
crc_algorithm = crcengine.create(0x864cfb, 24, 0xb704ce, ref_in=False,
|
||||
ref_out=False, xor_out=0,
|
||||
name='crc-24-openpgp')
|
||||
crc_algorithm = crcengine.create(0x864cfb,
|
||||
24,
|
||||
0xb704ce,
|
||||
ref_in=False,
|
||||
ref_out=False,
|
||||
xor_out=0,
|
||||
name="crc-24-openpgp")
|
||||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(3, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(3, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_32(data: bytes) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -97,11 +103,12 @@ def get_crc_32(data: bytes) -> bytes:
|
|||
Returns:
|
||||
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_data.to_bytes(4, byteorder='big')
|
||||
crc_data = crc_data.to_bytes(4, byteorder="big")
|
||||
return crc_data
|
||||
|
||||
|
||||
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])
|
||||
break
|
||||
|
||||
|
||||
# for idx, item in enumerate(static.HEARD_STATIONS):
|
||||
# if dxcallsign in item:
|
||||
# item = [dxcallsign, int(time.time())]
|
||||
# static.HEARD_STATIONS[idx] = item
|
||||
|
||||
|
||||
def callsign_to_bytes(callsign) -> bytes:
|
||||
"""
|
||||
|
||||
|
@ -165,18 +174,17 @@ def callsign_to_bytes(callsign) -> bytes:
|
|||
|
||||
# Try converting to bytestring if possible type string
|
||||
try:
|
||||
callsign = bytes(callsign, 'utf-8')
|
||||
except TypeError as e:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=e)
|
||||
pass
|
||||
callsign = bytes(callsign, "utf-8")
|
||||
except TypeError as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Exception converting callsign to bytes:", e=err)
|
||||
|
||||
# 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
|
||||
try:
|
||||
ssid = int(callsign[1])
|
||||
except IndexError as e:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=e)
|
||||
except IndexError as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] callsign_to_bytes: Error callsign SSID to integer:", e=err)
|
||||
|
||||
# callsign = callsign[0]
|
||||
# bytestring = bytearray(8)
|
||||
|
@ -189,6 +197,7 @@ def callsign_to_bytes(callsign) -> bytes:
|
|||
return encode_call(callsign + ssid)
|
||||
# return bytes(bytestring)
|
||||
|
||||
|
||||
def bytes_to_callsign(bytestring: bytes) -> bytes:
|
||||
"""
|
||||
Convert our callsign, received by a frame to a callsign in a human readable format
|
||||
|
@ -218,23 +227,24 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
|
|||
# -15 generic additional station, digi, mobile, wx, etc
|
||||
|
||||
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
|
||||
'''
|
||||
"""
|
||||
callsign = bytes(bytestring[:7])
|
||||
callsign = callsign.rstrip(b'\x00')
|
||||
callsign = callsign.rstrip(b"\x00")
|
||||
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
|
||||
|
||||
callsign = callsign + b'-'
|
||||
callsign = callsign.decode('utf-8')
|
||||
callsign = callsign + b"-"
|
||||
callsign = callsign.decode("utf-8")
|
||||
callsign = callsign + str(ssid)
|
||||
callsign = callsign.encode('utf-8')
|
||||
callsign = callsign.encode("utf-8")
|
||||
|
||||
return bytes(callsign)
|
||||
'''
|
||||
"""
|
||||
decoded = decode_call(bytestring)
|
||||
callsign = decoded[:-1]
|
||||
ssid = ord(bytes(decoded[-1], "utf-8"))
|
||||
return bytes(f"{callsign}-{ssid}", "utf-8")
|
||||
|
||||
|
||||
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
|
||||
|
@ -248,19 +258,18 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|||
False
|
||||
"""
|
||||
|
||||
# print(callsign)
|
||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Checking:", callsign=callsign)
|
||||
try:
|
||||
# We want the callsign without SSID
|
||||
callsign = callsign.split(b'-')[0]
|
||||
callsign = callsign.split(b"-")[0]
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=e)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").debug("[HLP] check_callsign: Error callsign SSIG to integer:", e=err)
|
||||
|
||||
for ssid in static.SSID_LIST:
|
||||
call_with_ssid = bytearray(callsign)
|
||||
call_with_ssid.extend('-'.encode('utf-8'))
|
||||
call_with_ssid.extend(str(ssid).encode('utf-8'))
|
||||
call_with_ssid.extend("-".encode("utf-8"))
|
||||
call_with_ssid.extend(str(ssid).encode("utf-8"))
|
||||
|
||||
callsign_crc = get_crc_24(call_with_ssid)
|
||||
|
||||
|
@ -270,9 +279,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|||
|
||||
return [False, ""]
|
||||
|
||||
|
||||
def encode_grid(grid):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
grid:string: maidenhead QTH locater [a-r][a-r][0-9][0-9][a-x][a-x]
|
||||
Returns:
|
||||
|
@ -282,8 +292,8 @@ def encode_grid(grid):
|
|||
|
||||
grid = grid.upper() # upper case to be save
|
||||
|
||||
int_first = ord(grid[0]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||
int_sec = ord(grid[1]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||
int_first = ord(grid[0]) - 65 # -65 offset for "A" become zero, utf8 table
|
||||
int_sec = ord(grid[1]) - 65 # -65 offset for "A" become zero, utf8 table
|
||||
|
||||
int_val = (int_first * 18) + int_sec # encode for modulo devision, 2 numbers in 1
|
||||
|
||||
|
@ -294,24 +304,25 @@ def encode_grid(grid):
|
|||
out_code_word |= (int_val & 0b1111111) # using bit OR to add new value
|
||||
out_code_word <<= 7 # shift 7 bit left having space next bits, letter A-X
|
||||
|
||||
int_val = ord(grid[4]) - 65 # -65 offset for 'A' become zero, utf8 table
|
||||
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 <<= 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
|
||||
|
||||
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):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
b_code_word:bytes: 4 bytes with 26 bit valid data LSB
|
||||
Returns:
|
||||
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)
|
||||
code_word >>= 5
|
||||
|
@ -321,7 +332,7 @@ def decode_grid(b_code_word:bytes):
|
|||
|
||||
grid = str(int(code_word & 0b1111111)) + grid
|
||||
if (code_word & 0b1111111) < 10:
|
||||
grid = f'0{grid}'
|
||||
grid = f"0{grid}"
|
||||
code_word >>= 9
|
||||
|
||||
int_val = int(code_word & 0b111111111)
|
||||
|
@ -332,9 +343,10 @@ def decode_grid(b_code_word:bytes):
|
|||
|
||||
return grid
|
||||
|
||||
|
||||
def encode_call(call):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
|
||||
|
||||
|
@ -349,22 +361,24 @@ def encode_call(call):
|
|||
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 |= (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')
|
||||
return out_code_word.to_bytes(length=6, byteorder="big")
|
||||
|
||||
|
||||
def decode_call(b_code_word: bytes):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
b_code_word:bytes: 6 bytes with 6 bits/sign valid data char signs LSB
|
||||
|
||||
Returns:
|
||||
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
|
||||
|
||||
call = str()
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import logging.config
|
||||
|
||||
import structlog
|
||||
|
||||
|
||||
# https://www.structlog.org/en/stable/standard-library.html
|
||||
def setup_logging(filename):
|
||||
"""
|
||||
|
@ -8,8 +13,6 @@ def setup_logging(filename):
|
|||
Returns:
|
||||
|
||||
"""
|
||||
import logging.config
|
||||
import structlog
|
||||
|
||||
timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S")
|
||||
pre_chain = [
|
||||
|
@ -19,7 +22,8 @@ def setup_logging(filename):
|
|||
timestamper,
|
||||
]
|
||||
|
||||
logging.config.dictConfig({
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
|
@ -43,7 +47,7 @@ def setup_logging(filename):
|
|||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.WatchedFileHandler",
|
||||
"filename": filename + '.log',
|
||||
"filename": f"{filename}.log",
|
||||
"formatter": "plain",
|
||||
},
|
||||
},
|
||||
|
@ -53,8 +57,9 @@ def setup_logging(filename):
|
|||
"level": "DEBUG",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.add_log_level,
|
||||
|
|
94
tnc/main.py
94
tnc/main.py
|
@ -16,15 +16,14 @@ import sys
|
|||
import threading
|
||||
import time
|
||||
|
||||
import structlog
|
||||
|
||||
import data_handler
|
||||
import helpers
|
||||
import log_handler
|
||||
import modem
|
||||
import static
|
||||
import structlog
|
||||
|
||||
|
||||
# signal handler for closing aplication
|
||||
def signal_handler(sig, frame):
|
||||
"""
|
||||
a signal handler, which closes the network/socket when closing the application
|
||||
|
@ -35,56 +34,57 @@ def signal_handler(sig, frame):
|
|||
Returns: system exit
|
||||
|
||||
"""
|
||||
print('Closing TNC...')
|
||||
print("Closing TNC...")
|
||||
sock.CLOSE_SIGNAL = True
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# we need to run this on windows for multiprocessing support
|
||||
if __name__ == "__main__":
|
||||
# we need to run this on Windows for multiprocessing support
|
||||
multiprocessing.freeze_support()
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
PARSER = argparse.ArgumentParser(description='FreeDATA TNC')
|
||||
PARSER.add_argument('--mycall', dest="mycall", default="AA0AA", help="My callsign", type=str)
|
||||
PARSER.add_argument('--ssid', dest="ssid_list", nargs='*', default=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], help="SSID list we are responding to", type=str)
|
||||
PARSER.add_argument('--mygrid', dest="mygrid", default="JN12AA", help="My gridsquare", type=str)
|
||||
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int)
|
||||
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
||||
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int)
|
||||
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
|
||||
PARSER.add_argument('--devicename', dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str)
|
||||
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int)
|
||||
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", choices=['USB', 'RIG', 'RTS', 'DTR', 'CM108', 'MICDATA', 'PARALLEL', 'DTR-H', 'DTR-L', 'NONE'], default='USB', help="PTT Type", type=str)
|
||||
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
||||
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int)
|
||||
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int)
|
||||
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
|
||||
PARSER.add_argument('--radiocontrol', dest="hamlib_radiocontrol", choices=['disabled', 'direct', 'rigctl', 'rigctld'], default="disabled", help="Set how you want to control your radio")
|
||||
PARSER.add_argument('--rigctld_port', dest="rigctld_port", default=4532, type=int, help="Set rigctld port")
|
||||
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="localhost", help="Set rigctld ip")
|
||||
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network")
|
||||
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network")
|
||||
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )")
|
||||
PARSER.add_argument('--fsk', dest="enable_fsk", action="store_true", help="Enable FSK mode for ping, beacon and CQ")
|
||||
PARSER.add_argument('--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_fmax', dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float)
|
||||
PARSER.add_argument('--tx-audio-level', dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int)
|
||||
PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
|
||||
PARSER.add_argument("--mycall", dest="mycall", default="AA0AA", help="My callsign", type=str)
|
||||
PARSER.add_argument("--ssid", dest="ssid_list", nargs="*", default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], help="SSID list we are responding to", type=str)
|
||||
PARSER.add_argument("--mygrid", dest="mygrid", default="JN12AA", help="My gridsquare", type=str)
|
||||
PARSER.add_argument("--rx", dest="audio_input_device", default=0, help="listening sound card", type=int)
|
||||
PARSER.add_argument("--tx", dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
||||
PARSER.add_argument("--port", dest="socket_port", default=3000, help="Socket port in the range of 1024-65536", type=int)
|
||||
PARSER.add_argument("--deviceport", dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
|
||||
PARSER.add_argument("--devicename", dest="hamlib_device_name", default="2028", help="Hamlib device name", type=str)
|
||||
PARSER.add_argument("--serialspeed", dest="hamlib_serialspeed", choices=[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200], default=9600, help="Serialspeed", type=int)
|
||||
PARSER.add_argument("--pttprotocol", dest="hamlib_ptt_type", choices=["USB", "RIG", "RTS", "DTR", "CM108", "MICDATA", "PARALLEL", "DTR-H", "DTR-L", "NONE"], default="USB", help="PTT Type", type=str)
|
||||
PARSER.add_argument("--pttport", dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
||||
PARSER.add_argument("--data_bits", dest="hamlib_data_bits", choices=[7, 8], default=8, help="Hamlib data bits", type=int)
|
||||
PARSER.add_argument("--stop_bits", dest="hamlib_stop_bits", choices=[1, 2], default=1, help="Hamlib stop bits", type=int)
|
||||
PARSER.add_argument("--handshake", dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
|
||||
PARSER.add_argument("--radiocontrol", dest="hamlib_radiocontrol", choices=["disabled", "direct", "rigctl", "rigctld"], default="disabled", help="Set how you want to control your radio")
|
||||
PARSER.add_argument("--rigctld_port", dest="rigctld_port", default=4532, type=int, help="Set rigctld port")
|
||||
PARSER.add_argument("--rigctld_ip", dest="rigctld_ip", default="localhost", help="Set rigctld ip")
|
||||
PARSER.add_argument("--scatter", dest="send_scatter", action="store_true", help="Send scatter information via network")
|
||||
PARSER.add_argument("--fft", dest="send_fft", action="store_true", help="Send fft information via network")
|
||||
PARSER.add_argument("--500hz", dest="low_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("--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_fmax", dest="tuning_range_fmax", choices=[50.0, 100.0, 150.0, 200.0, 250.0], default=50.0, help="Tuning range fmax", type=float)
|
||||
PARSER.add_argument("--tx-audio-level", dest="tx_audio_level", default=50, help="Set the tx audio level at an early stage", type=int)
|
||||
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
# additional step for beeing sure our callsign is correctly
|
||||
# additional step for being sure our callsign is correctly
|
||||
# in case we are not getting a station ssid
|
||||
# then we are forcing a station ssid = 0
|
||||
mycallsign = bytes(ARGS.mycall.upper(), 'utf-8')
|
||||
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
|
||||
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
||||
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
||||
|
||||
static.SSID_LIST = ARGS.ssid_list
|
||||
|
||||
static.MYGRID = bytes(ARGS.mygrid, 'utf-8')
|
||||
static.MYGRID = bytes(ARGS.mygrid, "utf-8")
|
||||
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
||||
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
||||
static.PORT = ARGS.socket_port
|
||||
|
@ -102,7 +102,7 @@ if __name__ == '__main__':
|
|||
static.ENABLE_SCATTER = ARGS.send_scatter
|
||||
static.ENABLE_FFT = ARGS.send_fft
|
||||
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_FMAX = ARGS.tuning_range_fmax
|
||||
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
|
||||
|
@ -113,20 +113,20 @@ if __name__ == '__main__':
|
|||
|
||||
# config logging
|
||||
try:
|
||||
if sys.platform == 'linux':
|
||||
logging_path = os.getenv("HOME") + '/.config/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform == "linux":
|
||||
logging_path = os.getenv("HOME") + "/.config/" + "FreeDATA/" + "tnc"
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
logging_path = os.getenv("HOME") + '/Library/' + 'Application Support/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform == "darwin":
|
||||
logging_path = os.getenv("HOME") + "/Library/" + "Application Support/" + "FreeDATA/" + "tnc"
|
||||
|
||||
if sys.platform in ['win32', 'win64']:
|
||||
logging_path = os.getenv('APPDATA') + '/' + 'FreeDATA/' + 'tnc'
|
||||
if sys.platform in ["win32", "win64"]:
|
||||
logging_path = os.getenv("APPDATA") + "/" + "FreeDATA/" + "tnc"
|
||||
|
||||
if not os.path.exists(logging_path):
|
||||
os.makedirs(logging_path)
|
||||
log_handler.setup_logging(logging_path)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] logger init error", exception=e)
|
||||
except Exception as err:
|
||||
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)
|
||||
|
||||
|
@ -147,8 +147,8 @@ if __name__ == '__main__':
|
|||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=e)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
|
||||
sys.exit(1)
|
||||
while 1:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
|
224
tnc/modem.py
224
tnc/modem.py
|
@ -10,32 +10,26 @@ Created on Wed Dec 23 07:04:24 2020
|
|||
|
||||
import atexit
|
||||
import ctypes
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import queue
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from collections import deque
|
||||
|
||||
# import audio
|
||||
import codec2
|
||||
import data_handler
|
||||
import numpy as np
|
||||
import sock
|
||||
import sounddevice as sd
|
||||
import static
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
import audio
|
||||
import codec2
|
||||
import data_handler
|
||||
import helpers
|
||||
import log_handler
|
||||
import sock
|
||||
import static
|
||||
|
||||
TESTMODE = False
|
||||
RXCHANNEL = ''
|
||||
TXCHANNEL = ''
|
||||
RXCHANNEL = ""
|
||||
TXCHANNEL = ""
|
||||
|
||||
# Initialize FIFO queue to store received frames
|
||||
MODEM_RECEIVED_QUEUE = queue.Queue()
|
||||
|
@ -47,8 +41,11 @@ RECEIVE_DATAC1 = False
|
|||
RECEIVE_DATAC3 = False
|
||||
RECEIVE_FSK_LDPC_1 = False
|
||||
|
||||
class RF():
|
||||
|
||||
class RF:
|
||||
""" """
|
||||
log = structlog.get_logger("RF")
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.sampler_avg = 0
|
||||
|
@ -86,38 +83,48 @@ class RF():
|
|||
|
||||
# Open codec2 instances
|
||||
self.datac0_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p)
|
||||
self.c_lib.freedv_set_tuning_range(self.datac0_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.c_lib.freedv_set_tuning_range(self.datac0_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
|
||||
ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv) / 8)
|
||||
self.datac0_payload_per_frame = self.datac0_bytes_per_frame - 2
|
||||
self.datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(self.datac0_freedv)
|
||||
self.datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(self.datac0_freedv)
|
||||
self.datac0_n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.datac0_freedv)
|
||||
self.datac0_n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.datac0_freedv)
|
||||
self.datac0_n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(
|
||||
self.datac0_freedv)
|
||||
self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac0_freedv, 1)
|
||||
self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
|
||||
self.datac1_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p)
|
||||
self.c_lib.freedv_set_tuning_range(self.datac1_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.c_lib.freedv_set_tuning_range(self.datac1_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
|
||||
ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.datac1_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8)
|
||||
self.datac1_bytes_out = ctypes.create_string_buffer(self.datac1_bytes_per_frame)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, 1)
|
||||
self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
|
||||
self.datac3_freedv = ctypes.cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p)
|
||||
self.c_lib.freedv_set_tuning_range(self.datac3_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN), ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.c_lib.freedv_set_tuning_range(self.datac3_freedv, ctypes.c_float(static.TUNING_RANGE_FMIN),
|
||||
ctypes.c_float(static.TUNING_RANGE_FMAX))
|
||||
self.datac3_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8)
|
||||
self.datac3_bytes_out = ctypes.create_string_buffer(self.datac3_bytes_per_frame)
|
||||
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, 1)
|
||||
self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
|
||||
self.fsk_ldpc_freedv_0 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), ctypes.c_void_p)
|
||||
self.fsk_ldpc_freedv_0 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
|
||||
ctypes.byref(
|
||||
codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)),
|
||||
ctypes.c_void_p)
|
||||
self.fsk_ldpc_bytes_per_frame_0 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_0) / 8)
|
||||
self.fsk_ldpc_bytes_out_0 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_0)
|
||||
# codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1)
|
||||
self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||
|
||||
self.fsk_ldpc_freedv_1 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC, ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), ctypes.c_void_p)
|
||||
self.fsk_ldpc_freedv_1 = ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
|
||||
ctypes.byref(
|
||||
codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)),
|
||||
ctypes.c_void_p)
|
||||
self.fsk_ldpc_bytes_per_frame_1 = int(codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_1) / 8)
|
||||
self.fsk_ldpc_bytes_out_1 = ctypes.create_string_buffer(self.fsk_ldpc_bytes_per_frame_1)
|
||||
# codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1)
|
||||
|
@ -132,26 +139,29 @@ class RF():
|
|||
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
||||
if not TESTMODE:
|
||||
try:
|
||||
self.stream = sd.RawStream(channels=1, dtype='int16', callback=self.callback, device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE), samplerate = self.AUDIO_SAMPLE_RATE_RX, blocksize=4800)
|
||||
self.stream = sd.RawStream(channels=1, dtype="int16", callback=self.callback,
|
||||
device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE),
|
||||
samplerate=self.AUDIO_SAMPLE_RATE_RX, blocksize=4800)
|
||||
atexit.register(self.stream.stop)
|
||||
structlog.get_logger("structlog").info("[MDM] init: opened audio devices")
|
||||
self.log.info("[MDM] init: opened audio devices")
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[MDM] init: can't open audio device. Exit", e=e)
|
||||
except Exception as err:
|
||||
self.log.error("[MDM] init: can't open audio device. Exit", e=err)
|
||||
sys.exit(1)
|
||||
|
||||
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.stream.start()
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[MDM] init: starting pyaudio callback failed", e=e)
|
||||
except Exception as err:
|
||||
self.log.error("[MDM] init: starting pyaudio callback failed", e=err)
|
||||
|
||||
else:
|
||||
# create a stream object for simulating audio stream
|
||||
class Object(object):
|
||||
pass
|
||||
|
||||
self.stream = Object()
|
||||
self.stream.active = True
|
||||
|
||||
|
@ -159,31 +169,36 @@ class RF():
|
|||
try:
|
||||
os.mkfifo(RXCHANNEL)
|
||||
os.mkfifo(TXCHANNEL)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error(f"[MDM] init:mkfifo: Exception: {e}")
|
||||
pass
|
||||
except Exception as err:
|
||||
self.log.error(f"[MDM] init:mkfifo: Exception: {err}")
|
||||
|
||||
mkfifo_write_callback_thread = threading.Thread(target=self.mkfifo_write_callback, name="MKFIFO WRITE CALLBACK THREAD",daemon=True)
|
||||
mkfifo_write_callback_thread = threading.Thread(target=self.mkfifo_write_callback,
|
||||
name="MKFIFO WRITE CALLBACK THREAD", daemon=True)
|
||||
mkfifo_write_callback_thread.start()
|
||||
|
||||
mkfifo_read_callback_thread = threading.Thread(target=self.mkfifo_read_callback, name="MKFIFO READ CALLBACK THREAD",daemon=True)
|
||||
mkfifo_read_callback_thread = threading.Thread(target=self.mkfifo_read_callback,
|
||||
name="MKFIFO READ CALLBACK THREAD", daemon=True)
|
||||
mkfifo_read_callback_thread.start()
|
||||
|
||||
# --------------------------------------------INIT AND OPEN HAMLIB
|
||||
# Check how we want to control the radio
|
||||
if static.HAMLIB_RADIOCONTROL == 'direct':
|
||||
if static.HAMLIB_RADIOCONTROL == "direct":
|
||||
import rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'rigctl':
|
||||
elif static.HAMLIB_RADIOCONTROL == "rigctl":
|
||||
import rigctl as rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'rigctld':
|
||||
elif static.HAMLIB_RADIOCONTROL == "rigctld":
|
||||
import rigctld as rig
|
||||
elif static.HAMLIB_RADIOCONTROL == 'disabled':
|
||||
elif static.HAMLIB_RADIOCONTROL == "disabled":
|
||||
import rigdummy as rig
|
||||
else:
|
||||
import rigdummy as rig
|
||||
|
||||
self.hamlib = rig.radio()
|
||||
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT, hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED, pttport=static.HAMLIB_PTT_PORT, data_bits=static.HAMLIB_DATA_BITS, stop_bits=static.HAMLIB_STOP_BITS, handshake=static.HAMLIB_HANDSHAKE, rigctld_ip = static.HAMLIB_RIGCTLD_IP, rigctld_port = static.HAMLIB_RIGCTLD_PORT)
|
||||
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT,
|
||||
hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED,
|
||||
pttport=static.HAMLIB_PTT_PORT, data_bits=static.HAMLIB_DATA_BITS,
|
||||
stop_bits=static.HAMLIB_STOP_BITS, handshake=static.HAMLIB_HANDSHAKE,
|
||||
rigctld_ip=static.HAMLIB_RIGCTLD_IP, rigctld_port=static.HAMLIB_RIGCTLD_PORT)
|
||||
|
||||
# --------------------------------------------START DECODER THREAD
|
||||
if static.ENABLE_FFT:
|
||||
|
@ -200,10 +215,12 @@ class RF():
|
|||
audio_thread_datac3.start()
|
||||
|
||||
if static.ENABLE_FSK:
|
||||
audio_thread_fsk_ldpc0 = threading.Thread(target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0", daemon=True)
|
||||
audio_thread_fsk_ldpc0 = threading.Thread(target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0",
|
||||
daemon=True)
|
||||
audio_thread_fsk_ldpc0.start()
|
||||
|
||||
audio_thread_fsk_ldpc1 = threading.Thread(target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1", daemon=True)
|
||||
audio_thread_fsk_ldpc1 = threading.Thread(target=self.audio_fsk_ldpc_1, name="AUDIO_THREAD FSK LDPC1",
|
||||
daemon=True)
|
||||
audio_thread_fsk_ldpc1.start()
|
||||
|
||||
hamlib_thread = threading.Thread(target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True)
|
||||
|
@ -217,11 +234,11 @@ class RF():
|
|||
|
||||
# --------------------------------------------------------------------------------------------------------
|
||||
def mkfifo_read_callback(self):
|
||||
while 1:
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
# -----read
|
||||
data_in48k = bytes()
|
||||
with open(RXCHANNEL, 'rb') as fifo:
|
||||
with open(RXCHANNEL, "rb") as fifo:
|
||||
for line in fifo:
|
||||
data_in48k += line
|
||||
|
||||
|
@ -241,7 +258,7 @@ class RF():
|
|||
self.datac3_buffer.push(x)
|
||||
|
||||
def mkfifo_write_callback(self):
|
||||
while 1:
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
|
||||
# -----write
|
||||
|
@ -251,9 +268,8 @@ class RF():
|
|||
|
||||
else:
|
||||
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.flush()
|
||||
|
||||
|
@ -268,8 +284,6 @@ class RF():
|
|||
time:
|
||||
status:
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
x = np.frombuffer(data_in48k, dtype=np.int16)
|
||||
x = self.resampler.resample48_to_8(x)
|
||||
|
@ -284,35 +298,31 @@ class RF():
|
|||
static.BUFFER_OVERFLOW_COUNTER[0] += 1
|
||||
|
||||
# Avoid buffer overflow by filling only if buffer not full and selected datachannel mode
|
||||
if not self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size:
|
||||
if RECEIVE_DATAC1:
|
||||
self.datac1_buffer.push(x)
|
||||
else:
|
||||
if self.datac1_buffer.nbuffer + length_x > self.datac1_buffer.size:
|
||||
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
|
||||
if not self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size:
|
||||
if RECEIVE_DATAC3:
|
||||
self.datac3_buffer.push(x)
|
||||
else:
|
||||
if self.datac3_buffer.nbuffer + length_x > self.datac3_buffer.size:
|
||||
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
|
||||
if not self.fsk_ldpc_buffer_0.nbuffer + length_x > self.fsk_ldpc_buffer_0.size:
|
||||
if static.ENABLE_FSK:
|
||||
self.fsk_ldpc_buffer_0.push(x)
|
||||
else:
|
||||
if self.fsk_ldpc_buffer_0.nbuffer + length_x > self.fsk_ldpc_buffer_0.size:
|
||||
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
|
||||
if not self.fsk_ldpc_buffer_1.nbuffer + length_x > self.fsk_ldpc_buffer_1.size:
|
||||
if RECEIVE_FSK_LDPC_1 and static.ENABLE_FSK:
|
||||
self.fsk_ldpc_buffer_1.push(x)
|
||||
else:
|
||||
if self.fsk_ldpc_buffer_1.nbuffer + length_x > self.fsk_ldpc_buffer_1.size:
|
||||
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 not self.modoutqueue or self.mod_out_locked:
|
||||
|
||||
data_out48k = np.zeros(frames, dtype=np.int16)
|
||||
self.fft_data = x
|
||||
else:
|
||||
|
@ -322,7 +332,7 @@ class RF():
|
|||
try:
|
||||
outdata[:] = data_out48k[:frames]
|
||||
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)
|
||||
|
||||
|
@ -336,10 +346,8 @@ class RF():
|
|||
repeat_delay:
|
||||
frames:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
structlog.get_logger("structlog").debug("[MDM] transmit", mode=mode)
|
||||
self.log.debug("[MDM] transmit", mode=mode)
|
||||
static.TRANSMITTING = True
|
||||
# Toggle ptt early to save some time and send ptt state via socket
|
||||
static.PTT_STATE = self.hamlib.set_ptt(True)
|
||||
|
@ -373,11 +381,11 @@ class RF():
|
|||
mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
|
||||
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):
|
||||
# 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
|
||||
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
txbuffer += bytes(mod_out_preamble)
|
||||
|
@ -390,8 +398,9 @@ class RF():
|
|||
|
||||
# Create crc for data frame - we are using the crc function shipped with codec2 to avoid
|
||||
# CRC algorithm incompatibilities
|
||||
crc = ctypes.c_ushort(codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)) # Generate CRC16
|
||||
crc = crc.value.to_bytes(2, byteorder='big') # Convert crc to 2 byte hex string
|
||||
crc = ctypes.c_ushort(
|
||||
codec2.api.freedv_gen_crc16(bytes(buffer), payload_bytes_per_frame)) # Generate CRC16
|
||||
crc = crc.value.to_bytes(2, byteorder="big") # Convert crc to 2 byte hex string
|
||||
buffer += crc # Append crc16 to buffer
|
||||
|
||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||
|
@ -399,7 +408,7 @@ class RF():
|
|||
txbuffer += bytes(mod_out)
|
||||
|
||||
# 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
|
||||
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
# Append postamble to txbuffer
|
||||
|
@ -428,7 +437,7 @@ class RF():
|
|||
delta = chunk_length - len(c)
|
||||
delta_zeros = np.zeros(delta, dtype=np.int16)
|
||||
c = np.append(c, delta_zeros)
|
||||
#structlog.get_logger("structlog").debug("[MDM] mod out shorter than audio buffer", delta=delta)
|
||||
# self.log.debug("[MDM] mod out shorter than audio buffer", delta=delta)
|
||||
|
||||
self.modoutqueue.append(c)
|
||||
|
||||
|
@ -460,11 +469,13 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac0_buffer.nbuffer >= self.datac0_nin:
|
||||
# demodulate audio
|
||||
nbytes_datac0 = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out, self.datac0_buffer.buffer.ctypes)
|
||||
nbytes_datac0 = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out,
|
||||
self.datac0_buffer.buffer.ctypes)
|
||||
self.datac0_buffer.pop(self.datac0_nin)
|
||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
||||
if nbytes_datac0 == self.datac0_bytes_per_frame:
|
||||
self.modem_received_queue.put([self.datac0_bytes_out, self.datac0_freedv, self.datac0_bytes_per_frame])
|
||||
self.modem_received_queue.put(
|
||||
[self.datac0_bytes_out, self.datac0_freedv, self.datac0_bytes_per_frame])
|
||||
# self.get_scatter(self.datac0_freedv)
|
||||
self.calculate_snr(self.datac0_freedv)
|
||||
|
||||
|
@ -475,11 +486,13 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
||||
# demodulate audio
|
||||
nbytes_datac1 = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out, self.datac1_buffer.buffer.ctypes)
|
||||
nbytes_datac1 = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out,
|
||||
self.datac1_buffer.buffer.ctypes)
|
||||
self.datac1_buffer.pop(self.datac1_nin)
|
||||
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||
if nbytes_datac1 == self.datac1_bytes_per_frame:
|
||||
self.modem_received_queue.put([self.datac1_bytes_out, self.datac1_freedv, self.datac1_bytes_per_frame])
|
||||
self.modem_received_queue.put(
|
||||
[self.datac1_bytes_out, self.datac1_freedv, self.datac1_bytes_per_frame])
|
||||
# self.get_scatter(self.datac1_freedv)
|
||||
self.calculate_snr(self.datac1_freedv)
|
||||
|
||||
|
@ -490,11 +503,13 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.datac3_buffer.nbuffer >= self.datac3_nin:
|
||||
# demodulate audio
|
||||
nbytes_datac3 = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out, self.datac3_buffer.buffer.ctypes)
|
||||
nbytes_datac3 = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out,
|
||||
self.datac3_buffer.buffer.ctypes)
|
||||
self.datac3_buffer.pop(self.datac3_nin)
|
||||
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||
if nbytes_datac3 == self.datac3_bytes_per_frame:
|
||||
self.modem_received_queue.put([self.datac3_bytes_out, self.datac3_freedv, self.datac3_bytes_per_frame])
|
||||
self.modem_received_queue.put(
|
||||
[self.datac3_bytes_out, self.datac3_freedv, self.datac3_bytes_per_frame])
|
||||
# self.get_scatter(self.datac3_freedv)
|
||||
self.calculate_snr(self.datac3_freedv)
|
||||
|
||||
|
@ -505,11 +520,13 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.fsk_ldpc_buffer_0.nbuffer >= self.fsk_ldpc_nin_0:
|
||||
# demodulate audio
|
||||
nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_buffer_0.buffer.ctypes)
|
||||
nbytes_fsk_ldpc_0 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_out_0,
|
||||
self.fsk_ldpc_buffer_0.buffer.ctypes)
|
||||
self.fsk_ldpc_buffer_0.pop(self.fsk_ldpc_nin_0)
|
||||
self.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0)
|
||||
if nbytes_fsk_ldpc_0 == self.fsk_ldpc_bytes_per_frame_0:
|
||||
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_per_frame_0])
|
||||
self.modem_received_queue.put(
|
||||
[self.fsk_ldpc_bytes_out_0, self.fsk_ldpc_freedv_0, self.fsk_ldpc_bytes_per_frame_0])
|
||||
# self.get_scatter(self.fsk_ldpc_freedv_0)
|
||||
self.calculate_snr(self.fsk_ldpc_freedv_0)
|
||||
|
||||
|
@ -520,11 +537,13 @@ class RF():
|
|||
threading.Event().wait(0.01)
|
||||
while self.fsk_ldpc_buffer_1.nbuffer >= self.fsk_ldpc_nin_1:
|
||||
# demodulate audio
|
||||
nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_buffer_1.buffer.ctypes)
|
||||
nbytes_fsk_ldpc_1 = codec2.api.freedv_rawdatarx(self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_out_1,
|
||||
self.fsk_ldpc_buffer_1.buffer.ctypes)
|
||||
self.fsk_ldpc_buffer_1.pop(self.fsk_ldpc_nin_1)
|
||||
self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1)
|
||||
if nbytes_fsk_ldpc_1 == self.fsk_ldpc_bytes_per_frame_1:
|
||||
self.modem_received_queue.put([self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_per_frame_1])
|
||||
self.modem_received_queue.put(
|
||||
[self.fsk_ldpc_bytes_out_1, self.fsk_ldpc_freedv_1, self.fsk_ldpc_bytes_per_frame_1])
|
||||
# self.get_scatter(self.fsk_ldpc_freedv_1)
|
||||
self.calculate_snr(self.fsk_ldpc_freedv_1)
|
||||
|
||||
|
@ -534,7 +553,7 @@ class RF():
|
|||
while True:
|
||||
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.modem_transmit_queue.task_done()
|
||||
|
||||
|
@ -555,8 +574,6 @@ class RF():
|
|||
Args:
|
||||
freedv:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
modemStats = codec2.MODEMSTATS()
|
||||
self.c_lib.freedv_get_modem_extended_stats.restype = None
|
||||
|
@ -571,8 +588,6 @@ class RF():
|
|||
Args:
|
||||
freedv:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
if not static.ENABLE_SCATTER:
|
||||
return
|
||||
|
@ -607,8 +622,6 @@ class RF():
|
|||
Args:
|
||||
freedv:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
try:
|
||||
modem_stats_snr = ctypes.c_float()
|
||||
|
@ -619,12 +632,12 @@ class RF():
|
|||
modem_stats_sync = modem_stats_sync.value
|
||||
|
||||
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, -128, 128) # limit to max value of -128/128 as a possible fix of #188
|
||||
return static.SNR
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error(f"[MDM] calculate_snr: Exception: {e}")
|
||||
except Exception as err:
|
||||
self.log.error(f"[MDM] calculate_snr: Exception: {err}")
|
||||
static.SNR = 0
|
||||
return static.SNR
|
||||
|
||||
|
@ -633,10 +646,10 @@ class RF():
|
|||
while True:
|
||||
# time.sleep(1.5)
|
||||
threading.Event().wait(0.5)
|
||||
# (static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data()
|
||||
# (static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWIDTH, static.PTT_STATE) = self.hamlib.get_rig_data()
|
||||
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
|
||||
static.HAMLIB_MODE = self.hamlib.get_mode()
|
||||
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith()
|
||||
static.HAMLIB_BANDWIDTH = self.hamlib.get_bandwidth()
|
||||
|
||||
def calculate_fft(self):
|
||||
""" """
|
||||
|
@ -689,9 +702,9 @@ class RF():
|
|||
dfftlist = dfft.tolist()
|
||||
|
||||
static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error(f"[MDM] calculate_fft: Exception: {e}")
|
||||
structlog.get_logger("structlog").debug("[MDM] Setting fft=0")
|
||||
except Exception as err:
|
||||
self.log.error(f"[MDM] calculate_fft: Exception: {err}")
|
||||
self.log.debug("[MDM] Setting fft=0")
|
||||
# else 0
|
||||
static.FFT = [0]
|
||||
|
||||
|
@ -701,22 +714,23 @@ class RF():
|
|||
Args:
|
||||
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.datac3_freedv, n_frames_per_burst)
|
||||
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, n_frames_per_burst)
|
||||
|
||||
|
||||
def open_codec2_instance(mode):
|
||||
""" Return a codec2 instance """
|
||||
if mode in ['FSK_LDPC_0', 200]:
|
||||
if mode in ["FSK_LDPC_0", 200]:
|
||||
return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
|
||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)), ctypes.c_void_p)
|
||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV)),
|
||||
ctypes.c_void_p)
|
||||
|
||||
if mode in ['FSK_LDPC_1', 201]:
|
||||
if mode in ["FSK_LDPC_1", 201]:
|
||||
return ctypes.cast(codec2.api.freedv_open_advanced(codec2.api.FREEDV_MODE_FSK_LDPC,
|
||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)), ctypes.c_void_p)
|
||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV)),
|
||||
ctypes.c_void_p)
|
||||
|
||||
return ctypes.cast(codec2.api.freedv_open(mode), ctypes.c_void_p)
|
||||
|
||||
|
@ -728,8 +742,6 @@ def get_bytes_per_frame(mode):
|
|||
Args:
|
||||
mode:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
freedv = open_codec2_instance(mode)
|
||||
|
||||
|
|
121
tnc/rig.py
121
tnc/rig.py
|
@ -1,11 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
import structlog
|
||||
import atexit
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import structlog
|
||||
|
||||
# set global hamlib version
|
||||
hamlib_version = 0
|
||||
|
@ -20,26 +21,26 @@ else:
|
|||
# try importing hamlib
|
||||
try:
|
||||
# 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
|
||||
#sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
||||
# sys.path.append("/usr/local/lib/python"+ python_version +"/site-packages")
|
||||
|
||||
# installation path for Ubuntu 20.10 +
|
||||
sys.path.append('/usr/local/lib/')
|
||||
sys.path.append("/usr/local/lib/")
|
||||
|
||||
# installation path for Suse
|
||||
sys.path.append('/usr/local/lib64/python'+ python_version +'/site-packages')
|
||||
sys.path.append(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
|
||||
sys.path.append('/usr/local/lib/python3.6/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.7/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.8/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.9/site-packages')
|
||||
sys.path.append('/usr/local/lib/python3.10/site-packages')
|
||||
sys.path.append("/usr/local/lib/python3.6/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.7/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.8/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.9/site-packages")
|
||||
sys.path.append("/usr/local/lib/python3.10/site-packages")
|
||||
|
||||
sys.path.append('lib/hamlib/linux/python3.8/site-packages')
|
||||
sys.path.append("lib/hamlib/linux/python3.8/site-packages")
|
||||
import Hamlib
|
||||
|
||||
# https://stackoverflow.com/a/4703409
|
||||
|
@ -51,21 +52,23 @@ try:
|
|||
structlog.get_logger("structlog").info("[RIG] Hamlib found", version=hamlib_version)
|
||||
else:
|
||||
structlog.get_logger("structlog").warning("[RIG] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=e)
|
||||
except Exception as err:
|
||||
structlog.get_logger("structlog").warning("[RIG] Python Hamlib binding not found", error=err)
|
||||
|
||||
try:
|
||||
structlog.get_logger("structlog").warning("[RIG] Trying to open rigctl")
|
||||
rigctl = subprocess.Popen("rigctl -V", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
||||
hamlib_version = rigctl.stdout.readline()
|
||||
hamlib_version = hamlib_version.split(' ')
|
||||
|
||||
if hamlib_version[1] == 'Hamlib':
|
||||
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()
|
||||
else:
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=e)
|
||||
except Exception as err1:
|
||||
structlog.get_logger("structlog").critical("[RIG] HAMLIB NOT INSTALLED", error=err1)
|
||||
|
||||
hamlib_version = 0
|
||||
sys.exit()
|
||||
|
||||
|
@ -73,16 +76,16 @@ except Exception as e:
|
|||
class radio:
|
||||
""" """
|
||||
def __init__(self):
|
||||
self.devicename = ''
|
||||
self.devicenumber = ''
|
||||
self.deviceport = ''
|
||||
self.serialspeed = ''
|
||||
self.hamlib_ptt_type = ''
|
||||
self.my_rig = ''
|
||||
self.pttport = ''
|
||||
self.data_bits = ''
|
||||
self.stop_bits = ''
|
||||
self.handshake = ''
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
self.deviceport = ""
|
||||
self.serialspeed = ""
|
||||
self.hamlib_ptt_type = ""
|
||||
self.my_rig = ""
|
||||
self.pttport = ""
|
||||
self.data_bits = ""
|
||||
self.stop_bits = ""
|
||||
self.handshake = ""
|
||||
|
||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_port, rigctld_ip):
|
||||
"""
|
||||
|
@ -118,7 +121,7 @@ class radio:
|
|||
# get devicenumber by looking for deviceobject in Hamlib module
|
||||
try:
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except:
|
||||
except Exception:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
|
||||
self.devicenumber = 0
|
||||
|
||||
|
@ -131,42 +134,42 @@ class radio:
|
|||
self.my_rig.set_conf("data_bits", self.data_bits)
|
||||
self.my_rig.set_conf("ptt_pathname", self.pttport)
|
||||
|
||||
if self.hamlib_ptt_type == 'RIG':
|
||||
if self.hamlib_ptt_type == "RIG":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
||||
self.my_rig.set_conf("ptt_type", 'RIG')
|
||||
self.my_rig.set_conf("ptt_type", "RIG")
|
||||
|
||||
elif self.hamlib_ptt_type == 'USB':
|
||||
elif self.hamlib_ptt_type == "USB":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PORT_USB
|
||||
self.my_rig.set_conf("ptt_type", 'USB')
|
||||
self.my_rig.set_conf("ptt_type", "USB")
|
||||
|
||||
elif self.hamlib_ptt_type == 'DTR-H':
|
||||
elif self.hamlib_ptt_type == "DTR-H":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "HIGH")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
elif self.hamlib_ptt_type == 'DTR-L':
|
||||
elif self.hamlib_ptt_type == "DTR-L":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||
self.my_rig.set_conf("dtr_state", "LOW")
|
||||
self.my_rig.set_conf("ptt_type", "DTR")
|
||||
|
||||
elif self.hamlib_ptt_type == 'RTS':
|
||||
elif self.hamlib_ptt_type == "RTS":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
||||
self.my_rig.set_conf("dtr_state", "OFF")
|
||||
self.my_rig.set_conf("ptt_type", "RTS")
|
||||
|
||||
elif self.hamlib_ptt_type == 'PARALLEL':
|
||||
elif self.hamlib_ptt_type == "PARALLEL":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
||||
|
||||
elif self.hamlib_ptt_type == 'MICDATA':
|
||||
elif self.hamlib_ptt_type == "MICDATA":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
||||
|
||||
elif self.hamlib_ptt_type == 'CM108':
|
||||
elif self.hamlib_ptt_type == "CM108":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
||||
|
||||
elif self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
||||
elif self.hamlib_ptt_type == "RIG_PTT_NONE":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||
|
||||
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
||||
else: # self.hamlib_ptt_type == "RIG_PTT_NONE":
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||
|
||||
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname"))
|
||||
|
@ -176,16 +179,16 @@ class radio:
|
|||
|
||||
try:
|
||||
# lets determine the error message when opening rig
|
||||
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
|
||||
error = error[1].split('err=')
|
||||
error = str(Hamlib.rigerror(self.my_rig.error_status)).splitlines()
|
||||
error = error[1].split("err=")
|
||||
error = error[1]
|
||||
|
||||
if error == 'Permission denied':
|
||||
if error == "Permission denied":
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib has no permissions", e = error)
|
||||
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions'
|
||||
help_url = "https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions"
|
||||
structlog.get_logger("structlog").error("[RIG] HELP:", check = help_url)
|
||||
except:
|
||||
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status='SUCCESS')
|
||||
except Exception:
|
||||
structlog.get_logger("structlog").info("[RIG] Hamlib device opened", status="SUCCESS")
|
||||
|
||||
# set ptt to false if ptt is stuck for some reason
|
||||
self.set_ptt(False)
|
||||
|
@ -196,8 +199,8 @@ class radio:
|
|||
# self.my_rig.set_mode(Hamlib.RIG_MODE_PKTUSB)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=e, e=sys.exc_info()[0])
|
||||
except Exception as err2:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0])
|
||||
return False
|
||||
|
||||
def get_frequency(self):
|
||||
|
@ -206,13 +209,13 @@ class radio:
|
|||
|
||||
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)
|
||||
|
||||
def get_bandwith(self):
|
||||
def get_bandwidth(self):
|
||||
""" """
|
||||
(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
return bandwith
|
||||
(hamlib_mode, bandwidth) = self.my_rig.get_mode()
|
||||
return bandwidth
|
||||
|
||||
# not needed yet beacuse of some possible problems
|
||||
# def set_mode(self, mode):
|
||||
|
|
|
@ -23,16 +23,17 @@ hamlib_version = 0
|
|||
class radio:
|
||||
""" """
|
||||
def __init__(self):
|
||||
self.devicename = ''
|
||||
self.devicenumber = ''
|
||||
self.deviceport = ''
|
||||
self.serialspeed = ''
|
||||
self.hamlib_ptt_type = ''
|
||||
self.my_rig = ''
|
||||
self.pttport = ''
|
||||
self.data_bits = ''
|
||||
self.stop_bits = ''
|
||||
self.handshake = ''
|
||||
self.devicename = ""
|
||||
self.devicenumber = ""
|
||||
self.deviceport = ""
|
||||
self.serialspeed = ""
|
||||
self.hamlib_ptt_type = ""
|
||||
self.my_rig = ""
|
||||
self.pttport = ""
|
||||
self.data_bits = ""
|
||||
self.stop_bits = ""
|
||||
self.handshake = ""
|
||||
self.cmd = ""
|
||||
|
||||
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port):
|
||||
"""
|
||||
|
@ -71,26 +72,26 @@ class radio:
|
|||
try:
|
||||
import Hamlib
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
if int(self.devicename):
|
||||
self.devicenumber = int(self.devicename)
|
||||
else:
|
||||
self.devicenumber = 6 # dummy
|
||||
structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=e)
|
||||
structlog.get_logger("structlog").warning("[RIGCTL] Radio not found. Using DUMMY!", error=err)
|
||||
|
||||
# set deviceport to dummy port, if we selected dummy model
|
||||
if self.devicenumber == 1 or self.devicenumber == 6:
|
||||
self.deviceport = '/dev/ttyUSB0'
|
||||
if self.devicenumber in {1, 6}:
|
||||
self.deviceport = "/dev/ttyUSB0"
|
||||
|
||||
print(self.devicenumber, self.deviceport, self.serialspeed)
|
||||
|
||||
# select precompiled executable for win32/win64 rigctl
|
||||
# this is really a hack...somewhen we need a native hamlib integration for windows
|
||||
if sys.platform 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))
|
||||
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))
|
||||
|
||||
else:
|
||||
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
||||
self.cmd = "rigctl -m %d -r %s -s %d " % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
|
||||
|
||||
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
|
||||
# il set e t per il get
|
||||
|
@ -101,33 +102,33 @@ class radio:
|
|||
|
||||
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)
|
||||
time.sleep(0.5)
|
||||
freq = sw_proc.communicate()[0]
|
||||
#print('get_frequency', freq, sw_proc.communicate())
|
||||
# print("get_frequency", freq, sw_proc.communicate())
|
||||
try:
|
||||
return int(freq)
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
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)
|
||||
try:
|
||||
return 'PKTUSB'
|
||||
except:
|
||||
return "PKTUSB"
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_bandwith(self):
|
||||
def get_bandwidth(self):
|
||||
""" """
|
||||
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||
bandwith = 2700
|
||||
# (hamlib_mode, bandwidth) = self.my_rig.get_mode()
|
||||
bandwidth = 2700
|
||||
|
||||
try:
|
||||
return bandwith
|
||||
except:
|
||||
return bandwidth
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def set_mode(self, mode):
|
||||
|
@ -144,14 +145,14 @@ class radio:
|
|||
|
||||
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)
|
||||
time.sleep(0.5)
|
||||
status = sw_proc.communicate()[0]
|
||||
|
||||
try:
|
||||
return status
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def set_ptt(self, state):
|
||||
|
@ -163,18 +164,15 @@ class radio:
|
|||
Returns:
|
||||
|
||||
"""
|
||||
cmd = self.cmd + ' T '
|
||||
print('set_ptt', state)
|
||||
if state:
|
||||
cmd = cmd + '1'
|
||||
else:
|
||||
cmd = cmd + '0'
|
||||
print('set_ptt', cmd)
|
||||
cmd = f"{self.cmd} T "
|
||||
print("set_ptt", state)
|
||||
cmd = f"{cmd}1" if state else f"{cmd}0"
|
||||
print("set_ptt", cmd)
|
||||
|
||||
sw_proc = subprocess.Popen(cmd, shell=True, text=True)
|
||||
try:
|
||||
return state
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def close_rig(self):
|
||||
|
|
|
@ -10,9 +10,6 @@ import time
|
|||
|
||||
import structlog
|
||||
|
||||
import log_handler
|
||||
import static
|
||||
|
||||
# set global hamlib version
|
||||
hamlib_version = 0
|
||||
|
||||
|
@ -22,7 +19,7 @@ class radio():
|
|||
# Note: This is a massive hack.
|
||||
|
||||
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
||||
""" Open a connection to rotctld, and test it for validity """
|
||||
""" Open a connection to rigctld, and test it for validity """
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# self.sock.settimeout(timeout)
|
||||
|
||||
|
@ -67,10 +64,10 @@ class radio():
|
|||
self.connected = True
|
||||
structlog.get_logger("structlog").info("[RIGCTLD] Connected to rigctld!", ip=self.hostname, port=self.port)
|
||||
return True
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
# ConnectionRefusedError: [Errno 111] Connection refused
|
||||
self.close_rig()
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=e)
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Connection to rigctld refused! Reconnect...", ip=self.hostname, port=self.port, e=err)
|
||||
return False
|
||||
|
||||
def close_rig(self):
|
||||
|
@ -78,7 +75,7 @@ class radio():
|
|||
self.sock.close()
|
||||
self.connected = False
|
||||
|
||||
def send_command(self, command):
|
||||
def send_command(self, command) -> bytes:
|
||||
"""Send a command to the connected rotctld instance,
|
||||
and return the return value.
|
||||
|
||||
|
@ -90,14 +87,14 @@ class radio():
|
|||
"""
|
||||
if self.connected:
|
||||
try:
|
||||
self.connection.sendall(command+b'\n')
|
||||
except:
|
||||
self.connection.sendall(command + b"\n")
|
||||
except Exception:
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] Command not executed!", command=command, ip=self.hostname, port=self.port)
|
||||
self.connected = False
|
||||
|
||||
try:
|
||||
return self.connection.recv(1024)
|
||||
except:
|
||||
except Exception:
|
||||
structlog.get_logger("structlog").warning("[RIGCTLD] No command response!", command=command, ip=self.hostname, port=self.port)
|
||||
self.connected = False
|
||||
else:
|
||||
|
@ -106,24 +103,26 @@ class radio():
|
|||
time.sleep(0.5)
|
||||
self.connect()
|
||||
|
||||
return b""
|
||||
|
||||
def get_mode(self):
|
||||
""" """
|
||||
try:
|
||||
data = self.send_command(b"m")
|
||||
data = data.split(b'\n')
|
||||
data = data.split(b"\n")
|
||||
mode = data[0]
|
||||
return mode.decode("utf-8")
|
||||
except:
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def get_bandwith(self):
|
||||
def get_bandwidth(self):
|
||||
""" """
|
||||
try:
|
||||
data = self.send_command(b"m")
|
||||
data = data.split(b'\n')
|
||||
bandwith = data[1]
|
||||
return bandwith.decode("utf-8")
|
||||
except:
|
||||
data = data.split(b"\n")
|
||||
bandwidth = data[1]
|
||||
return bandwidth.decode("utf-8")
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def get_frequency(self):
|
||||
|
@ -131,14 +130,14 @@ class radio():
|
|||
try:
|
||||
frequency = self.send_command(b"f")
|
||||
return frequency.decode("utf-8")
|
||||
except:
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def get_ptt(self):
|
||||
""" """
|
||||
try:
|
||||
return self.send_command(b"t")
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def set_ptt(self, state):
|
||||
|
@ -156,5 +155,5 @@ class radio():
|
|||
else:
|
||||
self.send_command(b"T 0")
|
||||
return state
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import structlog
|
||||
|
||||
hamlib_version = 0
|
||||
|
||||
|
||||
class radio:
|
||||
""" """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
@ -29,7 +28,7 @@ class radio:
|
|||
""" """
|
||||
return None
|
||||
|
||||
def get_bandwith(self):
|
||||
def get_bandwidth(self):
|
||||
""" """
|
||||
return None
|
||||
|
||||
|
|
266
tnc/sock.py
266
tnc/sock.py
|
@ -17,27 +17,20 @@ Created on Fri Dec 25 21:25:14 2020
|
|||
# "type" : "..."
|
||||
# "dxcallsign" : "..."
|
||||
# "data" : "..."
|
||||
|
||||
"""
|
||||
import atexit
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import socketserver
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import psutil
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
import audio
|
||||
import data_handler
|
||||
import helpers
|
||||
import log_handler
|
||||
import static
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
SOCKET_QUEUE = queue.Queue()
|
||||
DAEMON_QUEUE = queue.Queue()
|
||||
|
@ -45,6 +38,8 @@ DAEMON_QUEUE = queue.Queue()
|
|||
CONNECTED_CLIENTS = set()
|
||||
CLOSE_SIGNAL = False
|
||||
|
||||
log = structlog.get_logger("sock")
|
||||
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
"""
|
||||
|
@ -62,7 +57,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
function called by socket handler
|
||||
send data to a network client if available
|
||||
"""
|
||||
tempdata = b''
|
||||
tempdata = b""
|
||||
while self.connection_alive and not CLOSE_SIGNAL:
|
||||
# send tnc state as network stream
|
||||
# check server port against daemon port and send corresponding data
|
||||
|
@ -80,17 +75,16 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
while not SOCKET_QUEUE.empty():
|
||||
data = SOCKET_QUEUE.get()
|
||||
sock_data = bytes(data, 'utf-8')
|
||||
sock_data += b'\n' # append line limiter
|
||||
sock_data = bytes(data, "utf-8")
|
||||
sock_data += b"\n" # append line limiter
|
||||
|
||||
# send data to all clients
|
||||
# try:
|
||||
for client in CONNECTED_CLIENTS:
|
||||
try:
|
||||
client.send(sock_data)
|
||||
except Exception as e:
|
||||
# print("connection lost...")
|
||||
structlog.get_logger("structlog").info("[SCK] Connection lost", e=e)
|
||||
except Exception as err:
|
||||
log.info("[SCK] Connection lost", e=err)
|
||||
self.connection_alive = False
|
||||
|
||||
# we want to transmit scatter data only once to reduce network traffic
|
||||
|
@ -111,15 +105,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
chunk = self.request.recv(1024)
|
||||
data += chunk
|
||||
|
||||
if chunk == b'':
|
||||
if chunk == b"":
|
||||
# print("connection broken. Closing...")
|
||||
self.connection_alive = False
|
||||
|
||||
if data.startswith(b'{') and data.endswith(b'}\n'):
|
||||
if data.startswith(b"{") and data.endswith(b"}\n"):
|
||||
# split data by \n if we have multiple commands in socket buffer
|
||||
data = data.split(b'\n')
|
||||
data = data.split(b"\n")
|
||||
# remove empty data
|
||||
data.remove(b'')
|
||||
data.remove(b"")
|
||||
|
||||
# iterate thorugh data list
|
||||
for commands in data:
|
||||
|
@ -137,8 +131,9 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
# finally delete our rx buffer to be ready for new commands
|
||||
data = bytes()
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").info("[SCK] Connection closed", ip=self.client_address[0], port=self.client_address[1], e=e)
|
||||
except Exception as err:
|
||||
log.info("[SCK] Connection closed", ip=self.client_address[0],
|
||||
port=self.client_address[1], e=err)
|
||||
self.connection_alive = False
|
||||
|
||||
def handle(self):
|
||||
|
@ -147,11 +142,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
"""
|
||||
CONNECTED_CLIENTS.add(self.request)
|
||||
|
||||
structlog.get_logger("structlog").debug("[SCK] Client connected", ip=self.client_address[0], port=self.client_address[1])
|
||||
log.debug("[SCK] Client connected", ip=self.client_address[0],
|
||||
port=self.client_address[1])
|
||||
self.connection_alive = True
|
||||
|
||||
self.sendThread = threading.Thread(target=self.send_to_client, args=[],daemon=True).start()
|
||||
self.receiveThread = threading.Thread(target=self.receive_from_client, args=[],daemon=True).start()
|
||||
self.send_thread = threading.Thread(target=self.send_to_client, args=[], daemon=True)
|
||||
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
|
||||
while self.connection_alive and not CLOSE_SIGNAL:
|
||||
|
@ -159,11 +157,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
def finish(self):
|
||||
""" """
|
||||
structlog.get_logger("structlog").warning("[SCK] Closing client socket", ip=self.client_address[0], port=self.client_address[1])
|
||||
log.warning("[SCK] Closing client socket", ip=self.client_address[0],
|
||||
port=self.client_address[1])
|
||||
try:
|
||||
CONNECTED_CLIENTS.remove(self.request)
|
||||
except:
|
||||
structlog.get_logger("structlog").warning("[SCK] client connection already removed from client list", client=self.request)
|
||||
except Exception as err:
|
||||
log.warning("[SCK] client connection already removed from client list",
|
||||
client=self.request, e=err)
|
||||
|
||||
|
||||
def process_tnc_commands(data):
|
||||
"""
|
||||
|
@ -179,60 +180,60 @@ def process_tnc_commands(data):
|
|||
try:
|
||||
# convert data to json object
|
||||
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 -----------------------------------------------------
|
||||
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level":
|
||||
try:
|
||||
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
||||
command_response("tx_audio_level", True)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 -----------------------------------------------------
|
||||
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['SEND_TEST_FRAME'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
||||
command_response("send_test_frame", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 -----------------------------------------------------
|
||||
if received_json["command"] == "cqcqcq":
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["CQ"])
|
||||
command_response("cqcqcq", True)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 -----------------------------------------------------
|
||||
if received_json["command"] == "start_beacon":
|
||||
try:
|
||||
static.BEACON_STATE = True
|
||||
interval = int(received_json["parameter"])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
||||
command_response("start_beacon", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 -----------------------------------------------------
|
||||
if received_json["command"] == "stop_beacon":
|
||||
try:
|
||||
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
|
||||
log.warning("[TNC] Stopping beacon!")
|
||||
static.BEACON_STATE = False
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
||||
command_response("stop_beacon", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 ----------------------------------------------------------
|
||||
if received_json["type"] == 'ping' and received_json["command"] == "ping":
|
||||
if received_json["type"] == "ping" and received_json["command"] == "ping":
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
dxcallsign = received_json["dxcallsign"]
|
||||
|
@ -243,14 +244,14 @@ def process_tnc_commands(data):
|
|||
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["PING", dxcallsign])
|
||||
command_response("ping", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "connect":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "connect":
|
||||
static.BEACON_PAUSE = True
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
|
@ -265,24 +266,24 @@ def process_tnc_commands(data):
|
|||
static.DXCALLSIGN = 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)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "disconnect":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "disconnect":
|
||||
# send ping frame and wait for ACK
|
||||
try:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['DISCONNECT'])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
||||
command_response("disconnect", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 -------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "send_raw":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "send_raw":
|
||||
static.BEACON_PAUSE = True
|
||||
try:
|
||||
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
|
||||
try:
|
||||
mycallsign = received_json["parameter"][0]["mycallsign"]
|
||||
except:
|
||||
except Exception:
|
||||
mycallsign = static.MYCALLSIGN
|
||||
|
||||
# check if transmission uuid provided else set no-uuid
|
||||
try:
|
||||
arq_uuid = received_json["uuid"]
|
||||
except:
|
||||
arq_uuid = 'no-uuid'
|
||||
except Exception:
|
||||
arq_uuid = "no-uuid"
|
||||
|
||||
if not len(base64data) % 4:
|
||||
binarydata = base64.b64decode(base64data)
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', binarydata, mode, n_frames, arq_uuid, mycallsign])
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["ARQ_RAW", binarydata, mode, n_frames, arq_uuid, mycallsign])
|
||||
else:
|
||||
raise TypeError
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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 ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission":
|
||||
if received_json["type"] == "arq" and received_json["command"] == "stop_transmission":
|
||||
try:
|
||||
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP'])
|
||||
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
|
||||
static.TNC_STATE = 'IDLE'
|
||||
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(["STOP"])
|
||||
log.warning("[TNC] Stopping transmission!")
|
||||
static.TNC_STATE = "IDLE"
|
||||
static.ARQ_STATE = False
|
||||
command_response("stop_transmission", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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:
|
||||
output = {
|
||||
"command": "rx_buffer",
|
||||
|
@ -349,34 +350,37 @@ def process_tnc_commands(data):
|
|||
# print(static.RX_BUFFER[i][4])
|
||||
# rawdata = json.loads(static.RX_BUFFER[i][4])
|
||||
base64_data = static.RX_BUFFER[i][4]
|
||||
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": base64_data})
|
||||
output["data-array"].append({"uuid": static.RX_BUFFER[i][0], "timestamp": static.RX_BUFFER[i][1],
|
||||
"dxcallsign": str(static.RX_BUFFER[i][2], "utf-8"),
|
||||
"dxgrid": str(static.RX_BUFFER[i][3], "utf-8"), "data": base64_data})
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
# self.request.sendall(bytes(jsondata, encoding))
|
||||
SOCKET_QUEUE.put(jsondata)
|
||||
command_response("rx_buffer", True)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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:
|
||||
static.RX_BUFFER = []
|
||||
command_response("del_rx_buffer", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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():
|
||||
"""
|
||||
send the tnc state to network
|
||||
"""
|
||||
encoding = 'utf-8'
|
||||
encoding = "utf-8"
|
||||
|
||||
output = {
|
||||
"command": "tnc_state",
|
||||
|
@ -390,7 +394,7 @@ def send_tnc_state():
|
|||
"frequency": str(static.HAMLIB_FREQUENCY),
|
||||
"speed_level": str(static.ARQ_SPEED_LEVEL),
|
||||
"mode": str(static.HAMLIB_MODE),
|
||||
"bandwith": str(static.HAMLIB_BANDWITH),
|
||||
"bandwidth": str(static.HAMLIB_BANDWIDTH),
|
||||
"fft": str(static.FFT),
|
||||
"channel_busy": str(static.CHANNEL_BUSY),
|
||||
"scatter": static.SCATTER,
|
||||
|
@ -412,8 +416,8 @@ def send_tnc_state():
|
|||
# add heard stations to heard stations object
|
||||
for heard in static.HEARD_STATIONS:
|
||||
output["stations"].append({
|
||||
"dxcallsign": str(heard[0], 'utf-8'),
|
||||
"dxgrid": str(heard[1], 'utf-8'),
|
||||
"dxcallsign": str(heard[0], "utf-8"),
|
||||
"dxgrid": str(heard[1], "utf-8"),
|
||||
"timestamp": heard[2],
|
||||
"datatype": heard[3],
|
||||
"snr": heard[4],
|
||||
|
@ -422,6 +426,9 @@ def send_tnc_state():
|
|||
|
||||
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):
|
||||
"""
|
||||
process daemon commands
|
||||
|
@ -434,39 +441,41 @@ def process_daemon_commands(data):
|
|||
"""
|
||||
# convert data to json object
|
||||
received_json = json.loads(data)
|
||||
structlog.get_logger("structlog").debug("[SCK] CMD", command=received_json)
|
||||
if received_json["type"] == 'set' and received_json["command"] == 'mycallsign':
|
||||
log.debug("[SCK] CMD", command=received_json)
|
||||
if received_json["type"] == "set" and received_json["command"] == "mycallsign":
|
||||
try:
|
||||
callsign = received_json["parameter"]
|
||||
|
||||
if bytes(callsign, 'utf-8') == b'':
|
||||
self.request.sendall(b'INVALID CALLSIGN')
|
||||
structlog.get_logger("structlog").warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
||||
if bytes(callsign, "utf-8") == b"":
|
||||
self.request.sendall(b"INVALID CALLSIGN")
|
||||
log.warning("[DMN] SET MYCALL FAILED", call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC)
|
||||
else:
|
||||
static.MYCALLSIGN = bytes(callsign, 'utf-8')
|
||||
static.MYCALLSIGN = bytes(callsign, "utf-8")
|
||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
||||
|
||||
command_response("mycallsign", True)
|
||||
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
|
||||
except Exception as e:
|
||||
log.info("[DMN] SET MYCALL", call=static.MYCALLSIGN,
|
||||
crc=static.MYCALLSIGN_CRC)
|
||||
except Exception as err:
|
||||
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:
|
||||
mygrid = received_json["parameter"]
|
||||
|
||||
if bytes(mygrid, 'utf-8') == b'':
|
||||
self.request.sendall(b'INVALID GRID')
|
||||
if bytes(mygrid, "utf-8") == b"":
|
||||
self.request.sendall(b"INVALID GRID")
|
||||
else:
|
||||
static.MYGRID = bytes(mygrid, 'utf-8')
|
||||
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID)
|
||||
static.MYGRID = bytes(mygrid, "utf-8")
|
||||
log.info("[SCK] SET MYGRID", grid=static.MYGRID)
|
||||
command_response("mygrid", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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:
|
||||
mycall = str(received_json["parameter"][0]["mycall"])
|
||||
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_fft = str(received_json["parameter"][0]["enable_fft"])
|
||||
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_fmax = str(received_json["parameter"][0]["tuning_range_fmax"])
|
||||
tx_audio_level = str(received_json["parameter"][0]["tx_audio_level"])
|
||||
|
@ -494,9 +503,9 @@ def process_daemon_commands(data):
|
|||
|
||||
# print some debugging parameters
|
||||
for item in received_json["parameter"][0]:
|
||||
structlog.get_logger("structlog").debug("[DMN] TNC Startup Config : " + item, value=received_json["parameter"][0][item])
|
||||
log.debug(f"[DMN] TNC Startup Config : {item}", value=received_json["parameter"][0][item])
|
||||
|
||||
DAEMON_QUEUE.put(['STARTTNC',
|
||||
DAEMON_QUEUE.put(["STARTTNC",
|
||||
mycall,
|
||||
mygrid,
|
||||
rx_audio,
|
||||
|
@ -514,7 +523,7 @@ def process_daemon_commands(data):
|
|||
rigctld_port,
|
||||
enable_scatter,
|
||||
enable_fft,
|
||||
low_bandwith_mode,
|
||||
low_bandwidth_mode,
|
||||
tuning_range_fmin,
|
||||
tuning_range_fmax,
|
||||
enable_fsk,
|
||||
|
@ -523,11 +532,11 @@ def process_daemon_commands(data):
|
|||
])
|
||||
command_response("start_tnc", True)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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:
|
||||
devicename = str(received_json["parameter"][0]["devicename"])
|
||||
deviceport = str(received_json["parameter"][0]["deviceport"])
|
||||
|
@ -541,7 +550,7 @@ def process_daemon_commands(data):
|
|||
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
||||
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||
|
||||
DAEMON_QUEUE.put(['TEST_HAMLIB',
|
||||
DAEMON_QUEUE.put(["TEST_HAMLIB",
|
||||
devicename,
|
||||
deviceport,
|
||||
serialspeed,
|
||||
|
@ -555,22 +564,23 @@ def process_daemon_commands(data):
|
|||
rigctld_port,
|
||||
])
|
||||
command_response("test_hamlib", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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:
|
||||
static.TNCPROCESS.kill()
|
||||
# unregister process from atexit to avoid process zombies
|
||||
atexit.unregister(static.TNCPROCESS.kill)
|
||||
|
||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
||||
log.warning("[DMN] Stopping TNC")
|
||||
static.TNCSTARTED = False
|
||||
command_response("stop_tnc", True)
|
||||
except Exception as e:
|
||||
except Exception as err:
|
||||
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():
|
||||
"""
|
||||
|
@ -580,16 +590,16 @@ def send_daemon_state():
|
|||
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
||||
|
||||
output = {
|
||||
'command': 'daemon_state',
|
||||
'daemon_state': [],
|
||||
'python_version': str(python_version),
|
||||
'hamlib_version': static.HAMLIB_VERSION,
|
||||
'input_devices': static.AUDIO_INPUT_DEVICES,
|
||||
'output_devices': static.AUDIO_OUTPUT_DEVICES,
|
||||
'serial_devices': static.SERIAL_DEVICES,
|
||||
#'cpu': str(psutil.cpu_percent()),
|
||||
#'ram': str(psutil.virtual_memory().percent),
|
||||
'version': '0.1'
|
||||
"command": "daemon_state",
|
||||
"daemon_state": [],
|
||||
"python_version": str(python_version),
|
||||
"hamlib_version": static.HAMLIB_VERSION,
|
||||
"input_devices": static.AUDIO_INPUT_DEVICES,
|
||||
"output_devices": static.AUDIO_OUTPUT_DEVICES,
|
||||
"serial_devices": static.SERIAL_DEVICES,
|
||||
# "cpu": str(psutil.cpu_percent()),
|
||||
# "ram": str(psutil.virtual_memory().percent),
|
||||
"version": "0.1"
|
||||
}
|
||||
|
||||
if static.TNCSTARTED:
|
||||
|
@ -597,13 +607,13 @@ def send_daemon_state():
|
|||
else:
|
||||
output["daemon_state"].append({"status": "stopped"})
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
return json.dumps(output)
|
||||
|
||||
return jsondata
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] error", e=e)
|
||||
except Exception as err:
|
||||
log.warning("[SCK] error", e=err)
|
||||
return None
|
||||
|
||||
|
||||
def command_response(command, status):
|
||||
s_status = "OK" if status else "Failed"
|
||||
jsondata = {"command_response": command, "status": s_status}
|
||||
|
|
151
tnc/static.py
151
tnc/static.py
|
@ -8,115 +8,118 @@ Here we are saving application wide variables and stats, which have to be access
|
|||
Not nice, suggestions are appreciated :-)
|
||||
"""
|
||||
|
||||
VERSION = '0.4.0-alpha'
|
||||
import subprocess
|
||||
|
||||
VERSION = "0.4.0-alpha"
|
||||
|
||||
# DAEMON
|
||||
DAEMONPORT = 3001
|
||||
TNCSTARTED = False
|
||||
TNCPROCESS = 0
|
||||
DAEMONPORT: int = 3001
|
||||
TNCSTARTED: bool = False
|
||||
TNCPROCESS: subprocess.Popen
|
||||
|
||||
# Operator Defaults
|
||||
MYCALLSIGN = b'AA0AA'
|
||||
MYCALLSIGN_CRC = b'A'
|
||||
MYCALLSIGN: bytes = b"AA0AA"
|
||||
MYCALLSIGN_CRC: bytes = b"A"
|
||||
|
||||
DXCALLSIGN = b'AA0AA'
|
||||
DXCALLSIGN_CRC = b'A'
|
||||
DXCALLSIGN: bytes = b"AA0AA"
|
||||
DXCALLSIGN_CRC: bytes = b"A"
|
||||
|
||||
MYGRID = b''
|
||||
DXGRID = b''
|
||||
MYGRID: bytes = 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
|
||||
HOST = "0.0.0.0"
|
||||
PORT = 3000
|
||||
SOCKET_TIMEOUT = 1 # seconds
|
||||
HOST: str = "0.0.0.0"
|
||||
PORT: int = 3000
|
||||
SOCKET_TIMEOUT: int = 1 # seconds
|
||||
# ---------------------------------
|
||||
SERIAL_DEVICES = []
|
||||
SERIAL_DEVICES: list = []
|
||||
# ---------------------------------
|
||||
|
||||
PTT_STATE = False
|
||||
TRANSMITTING = False
|
||||
PTT_STATE: bool = False
|
||||
TRANSMITTING: bool = False
|
||||
|
||||
HAMLIB_VERSION = '0'
|
||||
HAMLIB_PTT_TYPE = 'RTS'
|
||||
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
|
||||
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
|
||||
HAMLIB_SERIAL_SPEED = '9600'
|
||||
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
|
||||
HAMLIB_STOP_BITS = '1'
|
||||
HAMLIB_DATA_BITS = '8'
|
||||
HAMLIB_HANDSHAKE = 'None'
|
||||
HAMLIB_RADIOCONTROL = 'direct'
|
||||
HAMLIB_RIGCTLD_IP = '127.0.0.1'
|
||||
HAMLIB_RIGCTLD_PORT = '4532'
|
||||
HAMLIB_VERSION: str = "0"
|
||||
HAMLIB_PTT_TYPE: str = "RTS"
|
||||
HAMLIB_DEVICE_NAME: str = "RIG_MODEL_DUMMY_NOVFO"
|
||||
HAMLIB_DEVICE_PORT: str = "/dev/ttyUSB0"
|
||||
HAMLIB_SERIAL_SPEED: str = "9600"
|
||||
HAMLIB_PTT_PORT: str = "/dev/ttyUSB0"
|
||||
HAMLIB_STOP_BITS: str = "1"
|
||||
HAMLIB_DATA_BITS: str = "8"
|
||||
HAMLIB_HANDSHAKE: str = "None"
|
||||
HAMLIB_RADIOCONTROL: str = "direct"
|
||||
HAMLIB_RIGCTLD_IP: str = "127.0.0.1"
|
||||
HAMLIB_RIGCTLD_PORT: str = "4532"
|
||||
|
||||
HAMLIB_FREQUENCY = 0
|
||||
HAMLIB_MODE = ''
|
||||
HAMLIB_BANDWITH = 0
|
||||
HAMLIB_FREQUENCY: int = 0
|
||||
HAMLIB_MODE: str = ""
|
||||
HAMLIB_BANDWIDTH: int = 0
|
||||
# -------------------------
|
||||
# FreeDV Defaults
|
||||
|
||||
SNR = 0
|
||||
FREQ_OFFSET = 0
|
||||
SCATTER = []
|
||||
ENABLE_SCATTER = False
|
||||
ENABLE_FSK = False
|
||||
RESPOND_TO_CQ = False
|
||||
SNR: float = 0
|
||||
FREQ_OFFSET: float = 0
|
||||
SCATTER: list = []
|
||||
ENABLE_SCATTER: bool = False
|
||||
ENABLE_FSK: bool = False
|
||||
RESPOND_TO_CQ: bool = False
|
||||
# ---------------------------------
|
||||
|
||||
# Audio Defaults
|
||||
TX_AUDIO_LEVEL = 50
|
||||
AUDIO_INPUT_DEVICES = []
|
||||
AUDIO_OUTPUT_DEVICES = []
|
||||
AUDIO_INPUT_DEVICE = -2
|
||||
AUDIO_OUTPUT_DEVICE = -2
|
||||
BUFFER_OVERFLOW_COUNTER = [0,0,0,0,0]
|
||||
TX_AUDIO_LEVEL: int = 50
|
||||
AUDIO_INPUT_DEVICES: list = []
|
||||
AUDIO_OUTPUT_DEVICES: list = []
|
||||
AUDIO_INPUT_DEVICE: int = -2
|
||||
AUDIO_OUTPUT_DEVICE: int = -2
|
||||
BUFFER_OVERFLOW_COUNTER: list = [0, 0, 0, 0, 0]
|
||||
|
||||
AUDIO_RMS = 0
|
||||
FFT = [0]
|
||||
ENABLE_FFT = False
|
||||
CHANNEL_BUSY = None
|
||||
AUDIO_RMS: int = 0
|
||||
FFT: list = [0]
|
||||
ENABLE_FFT: bool = False
|
||||
CHANNEL_BUSY: bool = False
|
||||
|
||||
# ARQ PROTOCOL VERSION
|
||||
ARQ_PROTOCOL_VERSION = 1
|
||||
ARQ_PROTOCOL_VERSION: int = 1
|
||||
|
||||
# ARQ statistics
|
||||
ARQ_BYTES_PER_MINUTE_BURST = 0
|
||||
ARQ_BYTES_PER_MINUTE = 0
|
||||
ARQ_BITS_PER_SECOND_BURST = 0
|
||||
ARQ_BITS_PER_SECOND = 0
|
||||
ARQ_COMPRESSION_FACTOR = 0
|
||||
ARQ_TRANSMISSION_PERCENT = 0
|
||||
ARQ_SPEED_LEVEL = 0
|
||||
TOTAL_BYTES = 0
|
||||
ARQ_BYTES_PER_MINUTE_BURST: int = 0
|
||||
ARQ_BYTES_PER_MINUTE: int = 0
|
||||
ARQ_BITS_PER_SECOND_BURST: int = 0
|
||||
ARQ_BITS_PER_SECOND: int = 0
|
||||
ARQ_COMPRESSION_FACTOR: int = 0
|
||||
ARQ_TRANSMISSION_PERCENT: int = 0
|
||||
ARQ_SPEED_LEVEL: int = 0
|
||||
TOTAL_BYTES: int = 0
|
||||
|
||||
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
TNC_STATE = 'IDLE'
|
||||
ARQ_STATE = False
|
||||
ARQ_SESSION = False
|
||||
ARQ_SESSION_STATE = 'disconnected' # disconnected, connecting, connected, disconnecting, failed
|
||||
TNC_STATE: str = "IDLE"
|
||||
ARQ_STATE: bool = False
|
||||
ARQ_SESSION: bool = False
|
||||
# disconnected, connecting, connected, disconnecting, failed
|
||||
ARQ_SESSION_STATE: str = "disconnected"
|
||||
|
||||
# BEACON STATE
|
||||
BEACON_STATE = False
|
||||
BEACON_PAUSE = False
|
||||
BEACON_STATE: bool = False
|
||||
BEACON_PAUSE: bool = False
|
||||
|
||||
# ------- RX BUFFER
|
||||
RX_BUFFER = []
|
||||
RX_MSG_BUFFER = []
|
||||
RX_BURST_BUFFER = []
|
||||
RX_FRAME_BUFFER = b''
|
||||
#RX_BUFFER_SIZE = 0
|
||||
RX_BUFFER: list = []
|
||||
RX_MSG_BUFFER: list = []
|
||||
RX_BURST_BUFFER: list = []
|
||||
RX_FRAME_BUFFER: bytes = b""
|
||||
# RX_BUFFER_SIZE: int = 0
|
||||
|
||||
# ------- HEARD STATIOS BUFFER
|
||||
HEARD_STATIONS = []
|
||||
# ------- HEARD STATIONS BUFFER
|
||||
HEARD_STATIONS: list = []
|
||||
|
||||
# ------- INFO MESSAGE BUFFER
|
||||
INFO = []
|
||||
INFO: list = []
|
||||
|
||||
# ------- CODEC2 SETTINGS
|
||||
TUNING_RANGE_FMIN = -50.0
|
||||
TUNING_RANGE_FMAX = 50.0
|
||||
TUNING_RANGE_FMIN: float = -50.0
|
||||
TUNING_RANGE_FMAX: float = 50.0
|
||||
|
|
|
@ -6,19 +6,14 @@ import pyaudio
|
|||
|
||||
def list_audio_devices():
|
||||
p = pyaudio.PyAudio()
|
||||
devices = []
|
||||
print("--------------------------------------------------------------------")
|
||||
for x in range(0, p.get_device_count()):
|
||||
devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}")
|
||||
devices = [
|
||||
f"{x} - {p.get_device_info_by_index(x)['name']}"
|
||||
for x in range(p.get_device_count())
|
||||
]
|
||||
|
||||
for line in devices:
|
||||
print(line)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
list_audio_devices()
|
||||
|
|
|
@ -11,9 +11,6 @@ import sys
|
|||
import argparse
|
||||
import time
|
||||
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
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)
|
||||
|
|
|
@ -6,13 +6,14 @@ Created on Fri Dec 11 21:53:35 2020
|
|||
@author: parallels
|
||||
"""
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import argparse
|
||||
import random
|
||||
import socket
|
||||
|
||||
|
||||
#https://www.askpython.com/python/examples/generate-random-strings-in-python
|
||||
def create_string(length):
|
||||
# https://www.askpython.com/python/examples/generate-random-strings-in-python
|
||||
|
||||
random_string = ''
|
||||
for _ in range(length):
|
||||
# Considering only upper and lowercase letters
|
||||
|
@ -22,34 +23,22 @@ def create_string(length):
|
|||
random_integer = random_integer - 32 if flip_bit == 1 else random_integer
|
||||
# Keep appending random characters using chr(x)
|
||||
random_string += (chr(random_integer))
|
||||
print("STR:" + str(random_string))
|
||||
print(f"STR: {random_string!s}")
|
||||
|
||||
return random_string
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
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('--data', dest="data", default=False, help="data", type=str)
|
||||
parser.add_argument('--random', dest="datalength", default=False, help="data", type=int)
|
||||
|
||||
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
data = create_string(args.datalength)
|
||||
data = bytes("ARQ:DATA:" + "" + data + "" + "\n", "utf-8")
|
||||
|
||||
|
||||
|
||||
#print(data)
|
||||
|
||||
|
||||
HOST, PORT = "localhost", args.socket_port
|
||||
# data = args.data
|
||||
|
||||
|
@ -62,7 +51,4 @@ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|||
# Receive data from the server and shut down
|
||||
received = str(sock.recv(1024), "utf-8")
|
||||
|
||||
print("Sent: {}".format(data))
|
||||
|
||||
|
||||
|
||||
print(f"Sent: {data}")
|
||||
|
|
Loading…
Reference in a new issue