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