mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #93 from DJ2LS/ls-gui-optimization
This commit is contained in:
commit
b564ab7291
8 changed files with 214 additions and 323 deletions
|
@ -100,6 +100,8 @@ daemon.on('data', function(data) {
|
||||||
let Data = {
|
let Data = {
|
||||||
input_devices: data['INPUT_DEVICES'],
|
input_devices: data['INPUT_DEVICES'],
|
||||||
output_devices: data['OUTPUT_DEVICES'],
|
output_devices: data['OUTPUT_DEVICES'],
|
||||||
|
python_version: data['PYTHON_VERSION'],
|
||||||
|
hamlib_version: data['HAMLIB_VERSION'],
|
||||||
serial_devices: data['SERIAL_DEVICES'],
|
serial_devices: data['SERIAL_DEVICES'],
|
||||||
tnc_running_state: data['DAEMON_STATE'][0]['STATUS'],
|
tnc_running_state: data['DAEMON_STATE'][0]['STATUS'],
|
||||||
ram_usage: data['RAM'],
|
ram_usage: data['RAM'],
|
||||||
|
|
18
gui/main.js
18
gui/main.js
|
@ -155,14 +155,20 @@ app.whenReady().then(() => {
|
||||||
|
|
||||||
// start daemon
|
// start daemon
|
||||||
// https://stackoverflow.com/a/5775120
|
// https://stackoverflow.com/a/5775120
|
||||||
console.log("Starting Daemon")
|
console.log("Trying to start daemon binary")
|
||||||
daemonProcess = exec('./daemon', function callback(error, stdout, stderr) {
|
daemonProcess = exec('./daemon', function callback(err, stdout, stderr) {
|
||||||
// result
|
if (err) {
|
||||||
console.log(stdout)
|
console.error("Can't start daemon binary");
|
||||||
console.log(error)
|
console.error("--> this is only working with the app bundle and a precompiled binaries");
|
||||||
console.log(stderr)
|
return;
|
||||||
|
}
|
||||||
|
console.log(stdout);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow()
|
createWindow()
|
||||||
|
|
10
gui/package-lock.json
generated
10
gui/package-lock.json
generated
|
@ -384,16 +384,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansi-regex": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ansi-styles": {
|
"node_modules/ansi-styles": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@ const {
|
||||||
bearingDistance,
|
bearingDistance,
|
||||||
latLngToLocator
|
latLngToLocator
|
||||||
} = require('qth-locator');
|
} = require('qth-locator');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
// https://stackoverflow.com/a/26227660
|
// https://stackoverflow.com/a/26227660
|
||||||
var appDataFolder = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME + "/.config")
|
var appDataFolder = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME + "/.config")
|
||||||
|
@ -321,10 +322,11 @@ advancedHamlibSettingsModal
|
||||||
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
||||||
collapseFirstRow.hide()
|
collapseFirstRow.hide()
|
||||||
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
||||||
collapseSecondRow.show()
|
collapseSecondRow.hide()
|
||||||
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
||||||
collapseThirdRow.show()
|
collapseThirdRow.show()
|
||||||
|
var collapseFourthRow = new bootstrap.Collapse(document.getElementById('collapseFourthRow'), {toggle: false})
|
||||||
|
collapseFourthRow.show()
|
||||||
|
|
||||||
daemon.startTNC(rx_audio, tx_audio, deviceid, deviceport, pttprotocol, pttport, serialspeed, pttspeed, data_bits, stop_bits, handshake)
|
daemon.startTNC(rx_audio, tx_audio, deviceid, deviceport, pttprotocol, pttport, serialspeed, pttspeed, data_bits, stop_bits, handshake)
|
||||||
|
|
||||||
|
@ -350,9 +352,16 @@ advancedHamlibSettingsModal
|
||||||
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
||||||
collapseFirstRow.show()
|
collapseFirstRow.show()
|
||||||
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
||||||
collapseSecondRow.hide()
|
collapseSecondRow.show()
|
||||||
|
|
||||||
|
|
||||||
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
||||||
collapseThirdRow.hide()
|
collapseThirdRow.hide()
|
||||||
|
var collapseFourthRow = new bootstrap.Collapse(document.getElementById('collapseFourthRow'), {toggle: false})
|
||||||
|
collapseFourthRow.hide()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -967,6 +976,27 @@ ipcRenderer.on('action-update-daemon-state', (event, arg) => {
|
||||||
document.getElementById("progressbar_cpu").setAttribute("style", "width:" + arg.cpu_usage + "%;")
|
document.getElementById("progressbar_cpu").setAttribute("style", "width:" + arg.cpu_usage + "%;")
|
||||||
document.getElementById("progressbar_cpu_value").innerHTML = arg.cpu_usage + "%"
|
document.getElementById("progressbar_cpu_value").innerHTML = arg.cpu_usage + "%"
|
||||||
*/
|
*/
|
||||||
|
document.getElementById("ram_load").innerHTML = "RAM " + arg.ram_usage + "%"
|
||||||
|
document.getElementById("cpu_load").innerHTML = "CPU " + arg.cpu_usage + "%"
|
||||||
|
|
||||||
|
// OPERATING SYSTEM
|
||||||
|
|
||||||
|
document.getElementById("operating_system").innerHTML = "OS " + os.type()
|
||||||
|
|
||||||
|
|
||||||
|
// PYTHON VERSION
|
||||||
|
document.getElementById("python_version").innerHTML = "Python " + arg.python_version
|
||||||
|
document.getElementById("python_version").className = "btn btn-sm btn-success";
|
||||||
|
|
||||||
|
// HAMLIB VERSION
|
||||||
|
document.getElementById("hamlib_version").innerHTML = "Hamlib " + arg.hamlib_version
|
||||||
|
document.getElementById("hamlib_version").className = "btn btn-sm btn-success";
|
||||||
|
|
||||||
|
// NODE VERSION
|
||||||
|
document.getElementById("node_version").innerHTML = "Node " + process.version
|
||||||
|
document.getElementById("node_version").className = "btn btn-sm btn-success";
|
||||||
|
|
||||||
|
|
||||||
// UPDATE AUDIO INPUT
|
// UPDATE AUDIO INPUT
|
||||||
if (arg.tnc_running_state == "stopped") {
|
if (arg.tnc_running_state == "stopped") {
|
||||||
if (document.getElementById("audio_input_selectbox").length != arg.input_devices.length) {
|
if (document.getElementById("audio_input_selectbox").length != arg.input_devices.length) {
|
||||||
|
@ -1054,10 +1084,11 @@ ipcRenderer.on('action-update-daemon-state', (event, arg) => {
|
||||||
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
||||||
collapseFirstRow.hide()
|
collapseFirstRow.hide()
|
||||||
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
||||||
collapseSecondRow.show()
|
collapseSecondRow.hide()
|
||||||
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
||||||
collapseThirdRow.show()
|
collapseThirdRow.show()
|
||||||
|
var collapseFourthRow = new bootstrap.Collapse(document.getElementById('collapseFourthRow'), {toggle: false})
|
||||||
|
collapseFourthRow.show()
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('hamlib_deviceid').disabled = false
|
document.getElementById('hamlib_deviceid').disabled = false
|
||||||
document.getElementById('hamlib_deviceport').disabled = false
|
document.getElementById('hamlib_deviceport').disabled = false
|
||||||
|
@ -1081,10 +1112,11 @@ ipcRenderer.on('action-update-daemon-state', (event, arg) => {
|
||||||
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
var collapseFirstRow = new bootstrap.Collapse(document.getElementById('collapseFirstRow'), {toggle: false})
|
||||||
collapseFirstRow.show()
|
collapseFirstRow.show()
|
||||||
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
var collapseSecondRow = new bootstrap.Collapse(document.getElementById('collapseSecondRow'), {toggle: false})
|
||||||
collapseSecondRow.hide()
|
collapseSecondRow.show()
|
||||||
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
|
||||||
collapseThirdRow.hide()
|
collapseThirdRow.hide()
|
||||||
|
var collapseFourthRow = new bootstrap.Collapse(document.getElementById('collapseFourthRow'), {toggle: false})
|
||||||
|
collapseFourthRow.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -622,10 +622,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
--></div>
|
--></div>
|
||||||
|
<div class="row collapse multi-collapse show mt-2" id="collapseSecondRow">
|
||||||
|
<div class="col">
|
||||||
|
<div class="card text-dark bg-light mb-0">
|
||||||
|
<div class="card-header p-1">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-motherboard" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.5 2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5Zm2 0a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5Zm-10 8a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1h-6Zm0 2a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1h-6ZM5 3a1 1 0 0 0-1 1h-.5a.5.5 0 0 0 0 1H4v1h-.5a.5.5 0 0 0 0 1H4a1 1 0 0 0 1 1v.5a.5.5 0 0 0 1 0V8h1v.5a.5.5 0 0 0 1 0V8a1 1 0 0 0 1-1h.5a.5.5 0 0 0 0-1H9V5h.5a.5.5 0 0 0 0-1H9a1 1 0 0 0-1-1v-.5a.5.5 0 0 0-1 0V3H6v-.5a.5.5 0 0 0-1 0V3Zm0 1h3v3H5V4Zm6.5 7a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-2Z" />
|
||||||
|
<path d="M1 2a2 2 0 0 1 2-2h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-2H.5a.5.5 0 0 1-.5-.5v-1A.5.5 0 0 1 .5 9H1V8H.5a.5.5 0 0 1-.5-.5v-1A.5.5 0 0 1 .5 6H1V5H.5a.5.5 0 0 1-.5-.5v-2A.5.5 0 0 1 .5 2H1Zm1 11a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v11Z" />
|
||||||
|
</svg> <strong>SYSTEM STATUS</strong>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 mb-1">
|
||||||
|
<button class="btn btn-secondary btn-sm" id="python_version" type="button" disabled>Python</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="node_version" type="button" disabled>Node</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="hamlib_version" type="button" disabled>Hamlib</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="operating_system" type="button" disabled>OS</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="cpu_load" type="button" disabled>CPU</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="ram_load" type="button" disabled>RAM</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--<hr class="m-1">-->
|
<!--<hr class="m-1">-->
|
||||||
<div class="container mt-2 p-0">
|
<div class="container mt-2 p-0">
|
||||||
<div class="row collapse multi-collapse" id="collapseSecondRow">
|
<div class="row collapse multi-collapse" id="collapseThirdRow">
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<div class="card text-dark bg-light mb-1">
|
<div class="card text-dark bg-light mb-1">
|
||||||
<div class="card-header p-1"><strong>MY STATION</strong>
|
<div class="card-header p-1"><strong>MY STATION</strong>
|
||||||
|
@ -717,7 +737,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row collapse multi-collapse" id="collapseThirdRow">
|
<div class="row collapse multi-collapse" id="collapseFourthRow">
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<div class="card text-dark bg-light mb-1">
|
<div class="card text-dark bg-light mb-1">
|
||||||
<div class="card-header p-1">
|
<div class="card-header p-1">
|
||||||
|
|
|
@ -29,8 +29,8 @@ def freedv_get_mode(mode):
|
||||||
libname = ["libcodec2.so", \
|
libname = ["libcodec2.so", \
|
||||||
pathlib.Path("codec2/build_linux/src/libcodec2.so.1.0"), \
|
pathlib.Path("codec2/build_linux/src/libcodec2.so.1.0"), \
|
||||||
pathlib.Path("lib/codec2/linux/libcodec2.so.1.0"), \
|
pathlib.Path("lib/codec2/linux/libcodec2.so.1.0"), \
|
||||||
pathlib.Path("../../tnc/codec2/build_linux/src/libcodec2.so.1.0"), \
|
pathlib.Path("../tnc/codec2/build_linux/src/libcodec2.so.1.0"), \
|
||||||
pathlib.Path("../../tnc/lib/codec2/linux/libcodec2.so.1.0"), \
|
pathlib.Path("../tnc/lib/codec2/linux/libcodec2.so.1.0"), \
|
||||||
]
|
]
|
||||||
# iterate through codec2 search pathes
|
# iterate through codec2 search pathes
|
||||||
for i in libname:
|
for i in libname:
|
||||||
|
@ -175,9 +175,8 @@ class resampler:
|
||||||
in48_mem[:self.MEM48] = self.filter_mem48
|
in48_mem[:self.MEM48] = self.filter_mem48
|
||||||
in48_mem[self.MEM48:] = in48
|
in48_mem[self.MEM48:] = in48
|
||||||
|
|
||||||
# In C: pin48=&in48[MEM48]
|
# In C: pin48=&in48_mem[MEM48]
|
||||||
pin48,flag = in48_mem.__array_interface__['data']
|
pin48 = byref(np.ctypeslib.as_ctypes(in48_mem), 2*self.MEM48)
|
||||||
pin48 += 2*self.MEM48
|
|
||||||
n8 = int(len(in48) / api.FDMDV_OS_48)
|
n8 = int(len(in48) / api.FDMDV_OS_48)
|
||||||
out8 = np.zeros(n8, dtype=np.int16)
|
out8 = np.zeros(n8, dtype=np.int16)
|
||||||
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8);
|
api.fdmdv_48_to_8_short(out8.ctypes, pin48, n8);
|
||||||
|
@ -195,9 +194,8 @@ class resampler:
|
||||||
in8_mem[:self.MEM8] = self.filter_mem8
|
in8_mem[:self.MEM8] = self.filter_mem8
|
||||||
in8_mem[self.MEM8:] = in8
|
in8_mem[self.MEM8:] = in8
|
||||||
|
|
||||||
# In C: pin8=&in8[MEM8]
|
# In C: pin8=&in8_mem[MEM8]
|
||||||
pin8,flag = in8_mem.__array_interface__['data']
|
pin8 = byref(np.ctypeslib.as_ctypes(in8_mem), 2*self.MEM8)
|
||||||
pin8 += 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));
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,14 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
|
|
||||||
if received_json["type"] == 'GET' and received_json["command"] == 'DAEMON_STATE':
|
if received_json["type"] == 'GET' and received_json["command"] == 'DAEMON_STATE':
|
||||||
|
|
||||||
data = {'COMMAND': 'DAEMON_STATE', 'DAEMON_STATE': [], 'INPUT_DEVICES': [], 'OUTPUT_DEVICES': [], 'SERIAL_DEVICES': [
|
data = {
|
||||||
|
'COMMAND': 'DAEMON_STATE',
|
||||||
|
'DAEMON_STATE': [],
|
||||||
|
'PYTHON_VERSION': str(python_version),
|
||||||
|
'HAMLIB_VERSION': str(hamlib_version),
|
||||||
|
'INPUT_DEVICES': [],
|
||||||
|
'OUTPUT_DEVICES': [],
|
||||||
|
'SERIAL_DEVICES': [
|
||||||
], "CPU": str(psutil.cpu_percent()), "RAM": str(psutil.virtual_memory().percent), "VERSION": "0.1-prototype"}
|
], "CPU": str(psutil.cpu_percent()), "RAM": str(psutil.virtual_memory().percent), "VERSION": "0.1-prototype"}
|
||||||
|
|
||||||
if static.TNCSTARTED:
|
if static.TNCSTARTED:
|
||||||
|
|
398
tnc/modem.py
398
tnc/modem.py
|
@ -20,7 +20,7 @@ import helpers
|
||||||
import static
|
import static
|
||||||
import data_handler
|
import data_handler
|
||||||
import re
|
import re
|
||||||
|
import queue
|
||||||
import codec2
|
import codec2
|
||||||
|
|
||||||
# option for testing miniaudio instead of audioop for sample rate conversion
|
# option for testing miniaudio instead of audioop for sample rate conversion
|
||||||
|
@ -118,54 +118,41 @@ class RF():
|
||||||
# TODO: we need to change the entire modem module to integrate codec2 module
|
# TODO: we need to change the entire modem module to integrate codec2 module
|
||||||
self.c_lib = codec2.api
|
self.c_lib = codec2.api
|
||||||
self.resampler = codec2.resampler()
|
self.resampler = codec2.resampler()
|
||||||
'''
|
|
||||||
# -------------------------------------------- LOAD FREEDV
|
|
||||||
try:
|
|
||||||
# we check at first for libcodec2 compiled from source
|
|
||||||
# this happens, if we want to run it beeing build in a dev environment
|
|
||||||
# libname = pathlib.Path().absolute() / "codec2/build_linux/src/libcodec2.so.1.0"
|
|
||||||
libname = pathlib.Path("codec2/build_linux/src/libcodec2.so.1.0")
|
|
||||||
if libname.is_file():
|
|
||||||
self.c_lib = ctypes.CDLL(libname)
|
|
||||||
structlog.get_logger("structlog").info("[TNC] Codec2 found", path=libname, origin="source")
|
|
||||||
else:
|
|
||||||
structlog.get_logger("structlog").critical("[TNC] Codec2 not loaded")
|
|
||||||
raise UnboundLocalError
|
|
||||||
|
|
||||||
except:
|
# init FIFO queue to store received frames in
|
||||||
# this is the normal behavior. Run codec2 from lib folder
|
self.dataqueue = queue.Queue()
|
||||||
#libname = pathlib.Path().absolute() / "lib/codec2/linux/libcodec2.so.1.0"
|
|
||||||
libname = pathlib.Path("lib/codec2/linux/libcodec2.so.1.0")
|
|
||||||
if libname.is_file():
|
|
||||||
self.c_lib = ctypes.CDLL(libname)
|
|
||||||
structlog.get_logger("structlog").info("[TNC] Codec2 found", path=libname, origin="precompiled")
|
|
||||||
else:
|
|
||||||
structlog.get_logger("structlog").critical("[TNC] Codec2 not found")
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
# --------------------------------------------CTYPES FUNCTION INIT
|
|
||||||
# TODO: WE STILL HAVE SOME MISSING FUNCTIONS!
|
|
||||||
|
|
||||||
self.c_lib.freedv_open.argype = [c_int]
|
|
||||||
self.c_lib.freedv_open.restype = c_void_p
|
|
||||||
|
|
||||||
self.c_lib.freedv_nin.argtype = [c_void_p]
|
# open codec2 instance
|
||||||
self.c_lib.freedv_nin.restype = c_int
|
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
|
||||||
|
self.datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv)/8)
|
||||||
|
self.datac0_payload_per_frame = self.datac0_bytes_per_frame -2
|
||||||
|
self.datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(self.datac0_freedv)
|
||||||
|
self.datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(self.datac0_freedv)
|
||||||
|
self.datac0_n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.datac0_freedv)
|
||||||
|
self.datac0_n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.datac0_freedv)
|
||||||
|
self.datac0_bytes_out = create_string_buffer(self.datac0_bytes_per_frame)
|
||||||
|
codec2.api.freedv_set_frames_per_burst(self.datac0_freedv,1)
|
||||||
|
self.datac0_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||||
|
|
||||||
self.c_lib.freedv_rawdatarx.argtype = [c_void_p, c_char_p, c_char_p]
|
self.datac1_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p)
|
||||||
self.c_lib.freedv_rawdatarx.restype = c_int
|
self.datac1_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv)/8)
|
||||||
|
self.datac1_bytes_out = create_string_buffer(self.datac1_bytes_per_frame)
|
||||||
|
codec2.api.freedv_set_frames_per_burst(self.datac1_freedv,1)
|
||||||
|
self.datac1_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||||
|
|
||||||
self.c_lib.freedv_get_sync.argtype = [c_void_p]
|
self.datac3_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p)
|
||||||
self.c_lib.freedv_get_sync.restype = c_int
|
self.datac3_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv)/8)
|
||||||
|
self.datac3_bytes_out = create_string_buffer(self.datac3_bytes_per_frame)
|
||||||
|
codec2.api.freedv_set_frames_per_burst(self.datac3_freedv,1)
|
||||||
|
self.datac3_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
||||||
|
|
||||||
self.c_lib.freedv_get_bits_per_modem_frame.argtype = [c_void_p]
|
# initial nin values
|
||||||
self.c_lib.freedv_get_bits_per_modem_frame.restype = c_int
|
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
||||||
|
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||||
|
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||||
|
|
||||||
self.c_lib.freedv_set_frames_per_burst.argtype = [c_void_p, c_int]
|
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
||||||
self.c_lib.freedv_set_frames_per_burst.restype = c_int
|
|
||||||
'''
|
|
||||||
|
|
||||||
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
|
||||||
try:
|
try:
|
||||||
# we need to "try" this, because sometimes libasound.so isn't in the default place
|
# we need to "try" this, because sometimes libasound.so isn't in the default place
|
||||||
# try to supress error messages
|
# try to supress error messages
|
||||||
|
@ -175,7 +162,8 @@ class RF():
|
||||||
except:
|
except:
|
||||||
self.p = pyaudio.PyAudio()
|
self.p = pyaudio.PyAudio()
|
||||||
atexit.register(self.p.terminate)
|
atexit.register(self.p.terminate)
|
||||||
# --------------------------------------------OPEN AUDIO CHANNEL RX
|
|
||||||
|
# --------------------------------------------OPEN RX AUDIO CHANNEL
|
||||||
# optional auto selection of loopback device if using in testmode
|
# optional auto selection of loopback device if using in testmode
|
||||||
if static.AUDIO_INPUT_DEVICE == -2:
|
if static.AUDIO_INPUT_DEVICE == -2:
|
||||||
loopback_list = []
|
loopback_list = []
|
||||||
|
@ -186,15 +174,16 @@ class RF():
|
||||||
AUDIO_INPUT_DEVICE = loopback_list[0] #0 = RX 1 = TX
|
AUDIO_INPUT_DEVICE = loopback_list[0] #0 = RX 1 = TX
|
||||||
print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
|
print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
self.stream_rx = self.p.open(format=pyaudio.paInt16,
|
self.stream_rx = self.p.open(format=pyaudio.paInt16,
|
||||||
channels=self.AUDIO_CHANNELS,
|
channels=self.AUDIO_CHANNELS,
|
||||||
rate=self.AUDIO_SAMPLE_RATE_RX,
|
rate=self.AUDIO_SAMPLE_RATE_RX,
|
||||||
frames_per_buffer=self.AUDIO_FRAMES_PER_BUFFER_RX,
|
frames_per_buffer=self.AUDIO_FRAMES_PER_BUFFER_RX,
|
||||||
input=True,
|
input=True,
|
||||||
input_device_index=static.AUDIO_INPUT_DEVICE
|
output=False,
|
||||||
|
input_device_index=static.AUDIO_INPUT_DEVICE,
|
||||||
|
stream_callback=self.callback
|
||||||
)
|
)
|
||||||
# --------------------------------------------OPEN AUDIO CHANNEL TX
|
# --------------------------------------------OPEN TX AUDIO CHANNEL
|
||||||
# optional auto selection of loopback device if using in testmode
|
# optional auto selection of loopback device if using in testmode
|
||||||
if static.AUDIO_OUTPUT_DEVICE == -2:
|
if static.AUDIO_OUTPUT_DEVICE == -2:
|
||||||
loopback_list = []
|
loopback_list = []
|
||||||
|
@ -220,8 +209,8 @@ class RF():
|
||||||
DECODER_THREAD = threading.Thread(target=self.receive, name="DECODER_THREAD")
|
DECODER_THREAD = threading.Thread(target=self.receive, name="DECODER_THREAD")
|
||||||
DECODER_THREAD.start()
|
DECODER_THREAD.start()
|
||||||
|
|
||||||
#PLAYBACK_THREAD = threading.Thread(target=self.play_audio, name="PLAYBACK_THREAD")
|
WORKER_THREAD = threading.Thread(target=self.worker, name="WORKER_THREAD")
|
||||||
#PLAYBACK_THREAD.start()
|
WORKER_THREAD.start()
|
||||||
|
|
||||||
self.fft_data = bytes()
|
self.fft_data = bytes()
|
||||||
FFT_THREAD = threading.Thread(target=self.calculate_fft, name="FFT_THREAD")
|
FFT_THREAD = threading.Thread(target=self.calculate_fft, name="FFT_THREAD")
|
||||||
|
@ -299,7 +288,57 @@ class RF():
|
||||||
structlog.get_logger("structlog").error("[TNC] Hamlib - can't open rig", e=sys.exc_info()[0])
|
structlog.get_logger("structlog").error("[TNC] Hamlib - can't open rig", e=sys.exc_info()[0])
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
|
def callback(self, data_in48k, frame_count, time_info, status):
|
||||||
|
|
||||||
|
x = np.frombuffer(data_in48k, dtype=np.int16)
|
||||||
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
|
||||||
|
self.datac0_buffer.push(x)
|
||||||
|
self.datac1_buffer.push(x)
|
||||||
|
self.datac3_buffer.push(x)
|
||||||
|
|
||||||
|
# refill fft_data buffer so we can plot a fft
|
||||||
|
if len(self.fft_data) < 1024:
|
||||||
|
self.fft_data += bytes(x)
|
||||||
|
|
||||||
|
|
||||||
|
while self.datac0_buffer.nbuffer >= self.datac0_nin:
|
||||||
|
# demodulate audio
|
||||||
|
nbytes = codec2.api.freedv_rawdatarx(self.datac0_freedv, self.datac0_bytes_out, self.datac0_buffer.buffer.ctypes)
|
||||||
|
self.datac0_buffer.pop(self.datac0_nin)
|
||||||
|
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
||||||
|
if nbytes == self.datac0_bytes_per_frame:
|
||||||
|
print(len(self.datac0_bytes_out))
|
||||||
|
self.dataqueue.put([self.datac0_bytes_out, self.datac0_freedv ,self.datac0_bytes_per_frame])
|
||||||
|
self.get_scatter(self.datac0_freedv)
|
||||||
|
self.calculate_snr(self.datac0_freedv)
|
||||||
|
|
||||||
|
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
||||||
|
# demodulate audio
|
||||||
|
nbytes = codec2.api.freedv_rawdatarx(self.datac1_freedv, self.datac1_bytes_out, self.datac1_buffer.buffer.ctypes)
|
||||||
|
self.datac1_buffer.pop(self.datac1_nin)
|
||||||
|
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||||
|
if nbytes == self.datac1_bytes_per_frame:
|
||||||
|
self.dataqueue.put([self.datac1_bytes_out, self.datac1_freedv ,self.datac1_bytes_per_frame])
|
||||||
|
self.get_scatter(self.datac1_freedv)
|
||||||
|
self.calculate_snr(self.datac1_freedv)
|
||||||
|
|
||||||
|
while self.datac3_buffer.nbuffer >= self.datac3_nin:
|
||||||
|
# demodulate audio
|
||||||
|
nbytes = codec2.api.freedv_rawdatarx(self.datac3_freedv, self.datac3_bytes_out, self.datac3_buffer.buffer.ctypes)
|
||||||
|
self.datac3_buffer.pop(self.datac3_nin)
|
||||||
|
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||||
|
if nbytes == self.datac3_bytes_per_frame:
|
||||||
|
self.dataqueue.put([self.datac3_bytes_out, self.datac3_freedv ,self.datac3_bytes_per_frame])
|
||||||
|
self.get_scatter(self.datac3_freedv)
|
||||||
|
self.calculate_snr(self.datac3_freedv)
|
||||||
|
|
||||||
|
self.dataqueue.join()
|
||||||
|
|
||||||
|
return (None, pyaudio.paContinue)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ptt_and_wait(self, state):
|
def ptt_and_wait(self, state):
|
||||||
static.PTT_STATE = state
|
static.PTT_STATE = state
|
||||||
|
@ -329,38 +368,24 @@ class RF():
|
||||||
state_before_transmit = static.CHANNEL_STATE
|
state_before_transmit = static.CHANNEL_STATE
|
||||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
||||||
|
|
||||||
freedv_signalling_mode = 14
|
mod_out = create_string_buffer(self.datac0_n_tx_modem_samples * 2)
|
||||||
|
mod_out_preamble = create_string_buffer(self.datac0_n_tx_preamble_modem_samples * 2)
|
||||||
|
mod_out_postamble = create_string_buffer(self.datac0_n_tx_postamble_modem_samples * 2)
|
||||||
|
|
||||||
freedv = cast(self.c_lib.freedv_open(freedv_signalling_mode), c_void_p)
|
buffer = bytearray(self.datac0_payload_per_frame)
|
||||||
|
|
||||||
self.c_lib.freedv_set_clip(freedv, 1)
|
|
||||||
self.c_lib.freedv_set_tx_bpf(freedv, 1)
|
|
||||||
|
|
||||||
bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
|
||||||
payload_per_frame = bytes_per_frame - 2
|
|
||||||
n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(freedv)
|
|
||||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv)
|
|
||||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
|
||||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(freedv)
|
|
||||||
|
|
||||||
mod_out = create_string_buffer(n_tx_modem_samples * 2)
|
|
||||||
mod_out_preamble = create_string_buffer(n_tx_preamble_modem_samples * 2)
|
|
||||||
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
|
|
||||||
|
|
||||||
buffer = bytearray(payload_per_frame)
|
|
||||||
# set buffersize to length of data which will be send
|
# set buffersize to length of data which will be send
|
||||||
buffer[:len(data_out)] = data_out
|
buffer[:len(data_out)] = data_out
|
||||||
|
|
||||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16
|
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), self.datac0_payload_per_frame)) # generate CRC16
|
||||||
# convert crc to 2 byte hex string
|
# convert crc to 2 byte hex string
|
||||||
crc = crc.value.to_bytes(2, byteorder='big')
|
crc = crc.value.to_bytes(2, byteorder='big')
|
||||||
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 * self.datac0_bytes_per_frame).from_buffer_copy(buffer)
|
||||||
|
|
||||||
# modulate DATA and safe it into mod_out pointer
|
# modulate DATA and safe it into mod_out pointer
|
||||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
self.c_lib.freedv_rawdatapreambletx(self.datac0_freedv, mod_out_preamble)
|
||||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data)
|
self.c_lib.freedv_rawdatatx(self.datac0_freedv, mod_out, data)
|
||||||
self.c_lib.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
self.c_lib.freedv_rawdatapostambletx(self.datac0_freedv, mod_out_postamble)
|
||||||
|
|
||||||
self.streambuffer = bytearray()
|
self.streambuffer = bytearray()
|
||||||
self.streambuffer += bytes(mod_out_preamble)
|
self.streambuffer += bytes(mod_out_preamble)
|
||||||
|
@ -388,14 +413,11 @@ class RF():
|
||||||
|
|
||||||
|
|
||||||
# we have a problem with the receiving state
|
# we have a problem with the receiving state
|
||||||
##static.CHANNEL_STATE = state_before_transmit
|
|
||||||
if state_before_transmit != 'RECEIVING_DATA':
|
if state_before_transmit != 'RECEIVING_DATA':
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||||
else:
|
else:
|
||||||
static.CHANNEL_STATE = state_before_transmit
|
static.CHANNEL_STATE = state_before_transmit
|
||||||
|
|
||||||
self.c_lib.freedv_close(freedv)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
# GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT
|
# GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT
|
||||||
|
@ -475,219 +497,29 @@ class RF():
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def receive(self):
|
def receive(self):
|
||||||
'''
|
try:
|
||||||
freedv_mode_datac0 = 14
|
print(f"starting pyaudio callback", file=sys.stderr)
|
||||||
freedv_mode_datac1 = 10
|
self.stream_rx.start_stream()
|
||||||
freedv_mode_datac3 = 12
|
except Exception as e:
|
||||||
'''
|
print(f"pyAudio error: {e}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
# open codec2 instance
|
while self.stream_rx.is_active():
|
||||||
datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
|
time.sleep(1)
|
||||||
datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac0_freedv)/8)
|
|
||||||
datac0_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac0_freedv)
|
|
||||||
datac0_bytes_out = create_string_buffer(datac0_bytes_per_frame * 2)
|
|
||||||
codec2.api.freedv_set_frames_per_burst(datac0_freedv,1)
|
|
||||||
datac0_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
|
||||||
datac0_modem_stats_snr = c_float()
|
|
||||||
datac0_modem_stats_sync = c_int()
|
|
||||||
static.FREEDV_SIGNALLING_BYTES_PER_FRAME = datac0_bytes_per_frame
|
|
||||||
static.FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = datac0_bytes_per_frame - 2
|
|
||||||
|
|
||||||
datac1_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), c_void_p)
|
# worker for FIFO queue for processing received frames
|
||||||
datac1_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac1_freedv)/8)
|
def worker(self):
|
||||||
datac1_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac1_freedv)
|
while True:
|
||||||
datac1_bytes_out = create_string_buffer(datac1_bytes_per_frame * 2)
|
time.sleep(0.01)
|
||||||
codec2.api.freedv_set_frames_per_burst(datac1_freedv,1)
|
data = self.dataqueue.get()
|
||||||
datac1_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
self.process_data(data[0], data[1], data[2])
|
||||||
datac1_modem_stats_snr = c_float()
|
self.dataqueue.task_done()
|
||||||
datac1_modem_stats_sync = c_int()
|
|
||||||
|
|
||||||
|
|
||||||
datac3_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), c_void_p)
|
|
||||||
datac3_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac3_freedv)/8)
|
|
||||||
datac3_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac3_freedv)
|
|
||||||
datac3_bytes_out = create_string_buffer(datac3_bytes_per_frame * 2)
|
|
||||||
codec2.api.freedv_set_frames_per_burst(datac3_freedv,1)
|
|
||||||
datac3_buffer = codec2.audio_buffer(2*self.AUDIO_FRAMES_PER_BUFFER_RX)
|
|
||||||
datac3_modem_stats_snr = c_float()
|
|
||||||
datac3_modem_stats_sync = c_int()
|
|
||||||
|
|
||||||
'''
|
|
||||||
# DATAC0
|
|
||||||
|
|
||||||
datac0_freedv = cast(self.c_lib.freedv_open(freedv_mode_datac0), c_void_p)
|
|
||||||
self.c_lib.freedv_get_bits_per_modem_frame(datac0_freedv)
|
|
||||||
datac0_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac0_freedv)/8)
|
|
||||||
datac0_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac0_freedv)
|
|
||||||
datac0_bytes_out = create_string_buffer(datac0_bytes_per_frame * 2)
|
|
||||||
self.c_lib.freedv_set_frames_per_burst(datac0_freedv, 1)
|
|
||||||
datac0_modem_stats_snr = c_float()
|
|
||||||
datac0_modem_stats_sync = c_int()
|
|
||||||
datac0_buffer = bytes()
|
|
||||||
|
|
||||||
static.FREEDV_SIGNALLING_BYTES_PER_FRAME = datac0_bytes_per_frame
|
|
||||||
static.FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = datac0_bytes_per_frame - 2
|
|
||||||
|
|
||||||
# DATAC1
|
|
||||||
datac1_freedv = cast(self.c_lib.freedv_open(freedv_mode_datac1), c_void_p)
|
|
||||||
datac1_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac1_freedv)/8)
|
|
||||||
datac1_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac1_freedv)
|
|
||||||
datac1_bytes_out = create_string_buffer(datac1_bytes_per_frame * 2)
|
|
||||||
self.c_lib.freedv_set_frames_per_burst(datac1_freedv, 0)
|
|
||||||
datac1_modem_stats_snr = c_float()
|
|
||||||
datac1_modem_stats_sync = c_int()
|
|
||||||
datac1_buffer = bytes()
|
|
||||||
|
|
||||||
# DATAC3
|
|
||||||
datac3_freedv = cast(self.c_lib.freedv_open(freedv_mode_datac3), c_void_p)
|
|
||||||
datac3_bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(datac3_freedv)/8)
|
|
||||||
datac3_n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(datac3_freedv)
|
|
||||||
datac3_bytes_out = create_string_buffer(datac3_bytes_per_frame * 2)
|
|
||||||
self.c_lib.freedv_set_frames_per_burst(datac3_freedv, 0)
|
|
||||||
datac3_modem_stats_snr = c_float()
|
|
||||||
datac3_modem_stats_sync = c_int()
|
|
||||||
datac3_buffer = bytes()
|
|
||||||
'''
|
|
||||||
|
|
||||||
fft_buffer = bytes()
|
|
||||||
receive = True
|
|
||||||
while receive:
|
|
||||||
|
|
||||||
try:
|
|
||||||
data_in48k = self.stream_rx.read(self.AUDIO_FRAMES_PER_BUFFER_RX, exception_on_overflow = True)
|
|
||||||
except OSError as err:
|
|
||||||
print(err, file=sys.stderr)
|
|
||||||
if str(err).find("Input overflowed") != -1:
|
|
||||||
nread_exceptions += 1
|
|
||||||
if str(err).find("Stream closed") != -1:
|
|
||||||
print("Ending...")
|
|
||||||
receive = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# insert samples in buffer
|
|
||||||
x = np.frombuffer(data_in48k, dtype=np.int16)
|
|
||||||
# x.tofile(frx)
|
|
||||||
if len(x) != self.AUDIO_FRAMES_PER_BUFFER_RX:
|
|
||||||
receive = False
|
|
||||||
x = self.resampler.resample48_to_8(x)
|
|
||||||
|
|
||||||
datac0_buffer.push(x)
|
|
||||||
datac1_buffer.push(x)
|
|
||||||
datac3_buffer.push(x)
|
|
||||||
|
|
||||||
# when we have enough samples call FreeDV Rx
|
|
||||||
while datac0_buffer.nbuffer >= datac0_nin:
|
|
||||||
# demodulate audio
|
|
||||||
nbytes = codec2.api.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_buffer.buffer.ctypes)
|
|
||||||
datac0_buffer.pop(datac0_nin)
|
|
||||||
datac0_nin = codec2.api.freedv_nin(datac0_freedv)
|
|
||||||
if nbytes == datac0_bytes_per_frame:
|
|
||||||
datac0_task = threading.Thread(target=self.process_data, args=[datac0_bytes_out, datac0_freedv, datac0_bytes_per_frame])
|
|
||||||
datac0_task.start()
|
|
||||||
|
|
||||||
while datac1_buffer.nbuffer >= datac1_nin:
|
|
||||||
# demodulate audio
|
|
||||||
nbytes = codec2.api.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_buffer.buffer.ctypes)
|
|
||||||
datac1_buffer.pop(datac1_nin)
|
|
||||||
datac1_nin = codec2.api.freedv_nin(datac1_freedv)
|
|
||||||
if nbytes == datac1_bytes_per_frame:
|
|
||||||
datac1_task = threading.Thread(target=self.process_data, args=[datac1_bytes_out, datac1_freedv, datac1_bytes_per_frame])
|
|
||||||
datac1_task.start()
|
|
||||||
|
|
||||||
while datac3_buffer.nbuffer >= datac3_nin:
|
|
||||||
# demodulate audio
|
|
||||||
nbytes = codec2.api.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_buffer.buffer.ctypes)
|
|
||||||
datac3_buffer.pop(datac3_nin)
|
|
||||||
datac3_nin = codec2.api.freedv_nin(datac3_freedv)
|
|
||||||
if nbytes == datac3_bytes_per_frame:
|
|
||||||
datac3_task = threading.Thread(target=self.process_data, args=[datac3_bytes_out, datac1_freedv, datac1_bytes_per_frame])
|
|
||||||
datac3_task.start()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
data_in = bytes()
|
|
||||||
data_in = self.stream_rx.read(self.AUDIO_CHUNKS, exception_on_overflow=False)
|
|
||||||
data_in = audioop.ratecv(data_in, 2, 1, self.AUDIO_SAMPLE_RATE_RX, self.MODEM_SAMPLE_RATE, None)
|
|
||||||
data_in = data_in[0]#.rstrip(b'\x00')
|
|
||||||
|
|
||||||
# we need to set nin * 2 beause of byte size in array handling
|
|
||||||
datac0_nin = self.c_lib.freedv_nin(datac0_freedv) * 2
|
|
||||||
datac1_nin = self.c_lib.freedv_nin(datac1_freedv) * 2
|
|
||||||
datac3_nin = self.c_lib.freedv_nin(datac3_freedv) * 2
|
|
||||||
|
|
||||||
|
|
||||||
datac0_buffer += data_in
|
|
||||||
datac1_buffer += data_in
|
|
||||||
datac3_buffer += data_in
|
|
||||||
|
|
||||||
# refill fft_data buffer so we can plot a fft
|
|
||||||
if len(self.fft_data) < 1024:
|
|
||||||
self.fft_data += data_in
|
|
||||||
|
|
||||||
# DECODING DATAC0
|
|
||||||
if len(datac0_buffer) >= (datac0_nin):
|
|
||||||
datac0_audio = datac0_buffer[:datac0_nin]
|
|
||||||
datac0_buffer = datac0_buffer[datac0_nin:]
|
|
||||||
nbytes = self.c_lib.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_audio) # demodulate audio
|
|
||||||
sync = self.c_lib.freedv_get_rx_status(datac0_freedv)
|
|
||||||
|
|
||||||
self.get_scatter(datac0_freedv)
|
|
||||||
|
|
||||||
if sync != 0 and nbytes != 0:
|
|
||||||
print("----------DECODE----------------")
|
|
||||||
|
|
||||||
# calculate snr and scatter
|
|
||||||
self.get_scatter(datac0_freedv)
|
|
||||||
self.calculate_snr(datac0_freedv)
|
|
||||||
|
|
||||||
datac0_task = threading.Thread(target=self.process_data, args=[datac0_bytes_out, datac0_freedv, datac0_bytes_per_frame])
|
|
||||||
datac0_task.start()
|
|
||||||
|
|
||||||
|
|
||||||
# DECODING DATAC1
|
|
||||||
if len(datac1_buffer) >= (datac1_nin):
|
|
||||||
datac1_audio = datac1_buffer[:datac1_nin]
|
|
||||||
datac1_buffer = datac1_buffer[datac1_nin:]
|
|
||||||
nbytes = self.c_lib.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_audio) # demodulate audio
|
|
||||||
|
|
||||||
sync = self.c_lib.freedv_get_rx_status(datac1_freedv)
|
|
||||||
if sync != 0 and nbytes != 0:
|
|
||||||
print("----------DECODE----------------")
|
|
||||||
frame = int.from_bytes(bytes(datac1_bytes_out[:1]), "big") - 10
|
|
||||||
n_frames_per_burst = int.from_bytes(bytes(datac1_bytes_out[1:2]), "big")
|
|
||||||
print("frame: {0}, N_frames_per_burst: {1}".format(frame, n_frames_per_burst))
|
|
||||||
|
|
||||||
# calculate snr and scatter
|
|
||||||
self.get_scatter(datac1_freedv)
|
|
||||||
self.calculate_snr(datac1_freedv)
|
|
||||||
|
|
||||||
datac1_task = threading.Thread(target=self.process_data, args=[datac1_bytes_out, datac1_freedv, datac1_bytes_per_frame])
|
|
||||||
datac1_task.start()
|
|
||||||
|
|
||||||
|
|
||||||
# DECODING DATAC3
|
|
||||||
if len(datac3_buffer) >= (datac3_nin):
|
|
||||||
datac3_audio = datac3_buffer[:datac3_nin]
|
|
||||||
datac3_buffer = datac3_buffer[datac3_nin:]
|
|
||||||
nbytes = self.c_lib.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_audio) # demodulate audio
|
|
||||||
|
|
||||||
sync = self.c_lib.freedv_get_rx_status(datac3_freedv)
|
|
||||||
if sync != 0 and nbytes != 0:
|
|
||||||
print("----------DECODE----------------")
|
|
||||||
# calculate snr and scatter
|
|
||||||
self.get_scatter(datac3_freedv)
|
|
||||||
self.calculate_snr(datac3_freedv)
|
|
||||||
|
|
||||||
datac3_task = threading.Thread(target=self.process_data, args=[datac3_bytes_out, datac3_freedv, datac3_bytes_per_frame])
|
|
||||||
datac3_task.start()
|
|
||||||
'''
|
|
||||||
# forward data only if broadcast or we are the receiver
|
# forward data only if broadcast or we are the receiver
|
||||||
# bytes_out[1:2] == callsign check for signalling frames,
|
# bytes_out[1:2] == callsign check for signalling frames,
|
||||||
# bytes_out[6:7] == callsign check for data frames,
|
# bytes_out[6:7] == callsign check for data frames,
|
||||||
# bytes_out[1:2] == b'\x01' --> broadcasts like CQ
|
# bytes_out[1:2] == b'\x01' --> broadcasts like CQ with n frames per_burst = 1
|
||||||
# we could also create an own function, which returns True.
|
# we could also create an own function, which returns True.
|
||||||
def process_data(self, bytes_out, freedv, bytes_per_frame):
|
def process_data(self, bytes_out, freedv, bytes_per_frame):
|
||||||
|
|
||||||
|
@ -697,7 +529,7 @@ class RF():
|
||||||
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
||||||
frame = frametype - 10
|
frame = frametype - 10
|
||||||
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
||||||
#self.c_lib.freedv_set_frames_per_burst(freedv, n_frames_per_burst);
|
self.c_lib.freedv_set_frames_per_burst(freedv, n_frames_per_burst);
|
||||||
|
|
||||||
#frequency_offset = self.get_frequency_offset(freedv)
|
#frequency_offset = self.get_frequency_offset(freedv)
|
||||||
#print("Freq-Offset: " + str(frequency_offset))
|
#print("Freq-Offset: " + str(frequency_offset))
|
||||||
|
@ -777,6 +609,10 @@ class RF():
|
||||||
logging.debug("BEACON RECEIVED")
|
logging.debug("BEACON RECEIVED")
|
||||||
data_handler.received_beacon(bytes_out[:-2])
|
data_handler.received_beacon(bytes_out[:-2])
|
||||||
|
|
||||||
|
elif frametype == 255:
|
||||||
|
structlog.get_logger("structlog").debug("TESTFRAME RECEIVED", frame=bytes_out[:])
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").warning("[TNC] ARQ - other frame type", frametype=frametype)
|
structlog.get_logger("structlog").warning("[TNC] ARQ - other frame type", frametype=frametype)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue