mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
500hz mode, protocol improvements....
...and a lot of different changes. Also deactivated single mode transmission. This needs to be optimised another day...Time is the missing ressource...
This commit is contained in:
parent
92cf30225e
commit
35d95bbb14
12 changed files with 709 additions and 693 deletions
|
@ -32,7 +32,7 @@ function connectDAEMON() {
|
|||
//client.setTimeout(5000);
|
||||
}
|
||||
|
||||
daemon.on('connect', function(data) {
|
||||
daemon.on('connect', function(err) {
|
||||
console.log('DAEMON connection established')
|
||||
let Data = {
|
||||
daemon_connection: daemon.readyState,
|
||||
|
@ -41,8 +41,10 @@ daemon.on('connect', function(data) {
|
|||
|
||||
})
|
||||
|
||||
daemon.on('error', function(data) {
|
||||
daemon.on('error', function(err) {
|
||||
console.log('DAEMON connection error');
|
||||
console.log(err)
|
||||
daemon.destroy();
|
||||
setTimeout(connectDAEMON, 2000)
|
||||
let Data = {
|
||||
daemon_connection: daemon.readyState,
|
||||
|
@ -64,7 +66,8 @@ client.on('close', function(data) {
|
|||
|
||||
daemon.on('end', function(data) {
|
||||
console.log('DAEMON connection ended');
|
||||
setTimeout(connectDAEMON, 2000)
|
||||
daemon.destroy();
|
||||
setTimeout(connectDAEMON, 500)
|
||||
let Data = {
|
||||
daemon_connection: daemon.readyState,
|
||||
};
|
||||
|
@ -198,7 +201,7 @@ exports.getDaemonState = function() {
|
|||
// START TNC
|
||||
// ` `== multi line string
|
||||
|
||||
exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter) {
|
||||
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) {
|
||||
var json_command = JSON.stringify({
|
||||
type: 'set',
|
||||
command: 'start_tnc',
|
||||
|
@ -219,7 +222,8 @@ exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, de
|
|||
rigctld_port: rigctld_port,
|
||||
rigctld_ip: rigctld_ip,
|
||||
enable_scatter: enable_scatter,
|
||||
enable_fft: enable_fft
|
||||
enable_fft: enable_fft,
|
||||
low_bandwith_mode : low_bandwith_mode
|
||||
}]
|
||||
})
|
||||
|
||||
|
|
35
gui/main.js
35
gui/main.js
|
@ -2,15 +2,15 @@ const {
|
|||
app,
|
||||
BrowserWindow,
|
||||
ipcMain
|
||||
} = require('electron')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
} = require('electron');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
app.setName("FreeDATA");
|
||||
|
||||
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");
|
||||
var configFolder = path.join(appDataFolder, "FreeDATA");
|
||||
var configPath = path.join(configFolder, 'config.json')
|
||||
var configPath = path.join(configFolder, 'config.json');
|
||||
|
||||
// create config folder if not exists
|
||||
if (!fs.existsSync(configFolder)) {
|
||||
|
@ -44,6 +44,7 @@ var configContent = `
|
|||
"rigctld_ip" : "127.0.0.1",
|
||||
"enable_scatter" : "False",
|
||||
"enable_fft" : "False",
|
||||
"low_bandwith_mode" : "False"
|
||||
|
||||
}
|
||||
`;
|
||||
|
@ -67,7 +68,7 @@ var configContent = `
|
|||
}
|
||||
`;
|
||||
if (!fs.existsSync(chatDB)) {
|
||||
fs.writeFileSync(chatDB, configContent)
|
||||
fs.writeFileSync(chatDB, configContent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,8 +135,8 @@ function createWindow() {
|
|||
}
|
||||
})
|
||||
|
||||
chat.loadFile('src/chat-module.html')
|
||||
chat.setMenuBarVisibility(false)
|
||||
chat.loadFile('src/chat-module.html');
|
||||
chat.setMenuBarVisibility(false);
|
||||
|
||||
|
||||
// Emitted when the window is closed.
|
||||
|
@ -158,13 +159,13 @@ function createWindow() {
|
|||
// https://stackoverflow.com/questions/44258831/only-hide-the-window-when-closing-it-electron
|
||||
chat.on('close', function(evt) {
|
||||
evt.preventDefault();
|
||||
chat.hide()
|
||||
chat.hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
createWindow();
|
||||
|
||||
// start daemon by checking os
|
||||
// https://stackoverflow.com/a/5775120
|
||||
|
@ -173,8 +174,8 @@ app.whenReady().then(() => {
|
|||
if(os.platform()=='linux' || os.platform()=='darwin'){
|
||||
daemonProcess = exec('./tnc/daemon', function callback(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.log(os.platform())
|
||||
console.error(err)
|
||||
console.log(os.platform());
|
||||
console.error(err);
|
||||
console.error("Can't start daemon binary");
|
||||
console.error("--> this is only working with the app bundle and a precompiled binaries");
|
||||
return;
|
||||
|
@ -186,8 +187,8 @@ app.whenReady().then(() => {
|
|||
if(os.platform()=='win32' || os.platform()=='win64'){
|
||||
daemonProcess = exec('./tnc/daemon.exe', function callback(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.log(os.platform())
|
||||
console.error(err)
|
||||
console.log(os.platform());
|
||||
console.error(err);
|
||||
console.error("Can't start daemon binary");
|
||||
console.error("--> this is only working with the app bundle and a precompiled binaries");
|
||||
return;
|
||||
|
@ -200,7 +201,7 @@ app.whenReady().then(() => {
|
|||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
createWindow();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -210,14 +211,14 @@ app.on('window-all-closed', () => {
|
|||
daemonProcess.kill('SIGINT');
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
app.quit();
|
||||
}
|
||||
})
|
||||
|
||||
// IPC HANDLER
|
||||
|
||||
ipcMain.on('request-show-chat-window', (event, arg) => {
|
||||
chat.show()
|
||||
chat.show();
|
||||
});
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
20
gui/sock.js
20
gui/sock.js
|
@ -57,8 +57,8 @@ client.on('error', function(data) {
|
|||
|
||||
};
|
||||
ipcRenderer.send('request-update-tnc-state', Data);
|
||||
|
||||
setTimeout(connectTNC, 2000)
|
||||
client.destroy();
|
||||
setTimeout(connectTNC, 500)
|
||||
// setTimeout( function() { exports.connectTNC(tnc_host, tnc_port); }, 2000 );
|
||||
|
||||
});
|
||||
|
@ -72,32 +72,26 @@ client.on('close', function(data) {
|
|||
|
||||
client.on('end', function(data) {
|
||||
console.log('TNC connection ended');
|
||||
//setTimeout(connectTNC, 2000)
|
||||
setTimeout(connectTNC, 0)
|
||||
|
||||
// setTimeout( function() { exports.connectTNC(tnc_host, tnc_port); }, 2000 );
|
||||
client.destroy();
|
||||
setTimeout(connectTNC, 500)
|
||||
|
||||
});
|
||||
|
||||
//exports.writeTncCommand = function(command){
|
||||
writeTncCommand = function(command) {
|
||||
|
||||
//console.log(command)
|
||||
// we use the writingCommand function to update our TCPIP state because we are calling this function a lot
|
||||
// if socket openend, we are able to run commands
|
||||
if (client.readyState == 'open') {
|
||||
//uiMain.setTNCconnection('open')
|
||||
client.write(command + '\n');
|
||||
}
|
||||
|
||||
if (client.readyState == 'closed') {
|
||||
//uiMain.setTNCconnection('closed')
|
||||
//console.log("CLOSED!!!!!")
|
||||
console.log("CLOSED!")
|
||||
}
|
||||
|
||||
if (client.readyState == 'opening') {
|
||||
//uiMain.setTNCconnection('opening')
|
||||
//console.log("OPENING!!!!!")
|
||||
console.log('connecting to TNC...')
|
||||
}
|
||||
}
|
||||
|
@ -238,12 +232,12 @@ client.on('data', function(socketdata) {
|
|||
|
||||
if(splitted_data[0] == 'f'){
|
||||
dataArray.push(data['data-array'][i])
|
||||
//dataArray.push(splitted_data)
|
||||
|
||||
}
|
||||
|
||||
if(splitted_data[0] == 'm'){
|
||||
messageArray.push(data['data-array'][i])
|
||||
//messageArray.push(splitted_data)
|
||||
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
|
|
|
@ -722,13 +722,16 @@
|
|||
<label class="form-check-label" for="scatterSwitch">Scatter</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-check form-switch form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="500HzModeSwitch">
|
||||
<label class="form-check-label" for="500HzModeSwitch">500Hz</label>
|
||||
</div>
|
||||
|
||||
<!--<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_button" type="button" disabled>
|
||||
<!--<button class="btn btn-secondary btn-sm" id="cpu_load_button" type="button" disabled>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cpu" viewBox="0 0 16 16">
|
||||
<path d="M5 0a.5.5 0 0 1 .5.5V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2A2.5 2.5 0 0 1 14 4.5h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14a2.5 2.5 0 0 1-2.5 2.5v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14A2.5 2.5 0 0 1 2 11.5H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2A2.5 2.5 0 0 1 4.5 2V.5A.5.5 0 0 1 5 0zm-.5 3A1.5 1.5 0 0 0 3 4.5v7A1.5 1.5 0 0 0 4.5 13h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 11.5 3h-7zM5 6.5A1.5 1.5 0 0 1 6.5 5h3A1.5 1.5 0 0 1 11 6.5v3A1.5 1.5 0 0 1 9.5 11h-3A1.5 1.5 0 0 1 5 9.5v-3zM6.5 6a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z" />
|
||||
</svg> <span id="cpu_load">---</span>
|
||||
|
@ -738,12 +741,13 @@
|
|||
<path d="M1 3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4.586a1 1 0 0 0 .707-.293l.353-.353a.5.5 0 0 1 .708 0l.353.353a1 1 0 0 0 .707.293H15a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H1Zm.5 1h3a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5Zm5 0h3a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5Zm4.5.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-4ZM2 10v2H1v-2h1Zm2 0v2H3v-2h1Zm2 0v2H5v-2h1Zm3 0v2H8v-2h1Zm2 0v2h-1v-2h1Zm2 0v2h-1v-2h1Zm2 0v2h-1v-2h1Z" />
|
||||
</svg> <span id="ram_load">---</span>
|
||||
</button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<hr class="m-1">-->
|
||||
|
||||
<div class="container mt-2 p-0">
|
||||
<div class="row collapse multi-collapse" id="collapseThirdRow">
|
||||
<div class="col-5">
|
||||
|
@ -964,19 +968,18 @@
|
|||
<div class="card-body p-2">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="input-group input-group-sm"> <span class="input-group-text" id="basic-addon1">Mode</span>
|
||||
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="datamode">
|
||||
<!--<option value="14">low SNR (DC0)</option>-->
|
||||
<div class="input-group input-group-sm"> <span class="input-group-text" id="basic-addon1" >Mode</span>
|
||||
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="datamode" disabled>
|
||||
<option selected value="255">AUTO</option>
|
||||
<option value="10">HIGH SNR (DC1)</option>
|
||||
<option value="12">MED SNR (DC3)</option>
|
||||
<option value="14">LOW SNR (DC0)</option>
|
||||
<!--<option value="232">HIGH SNR (DC1)</option>-->
|
||||
<!--<option value="231">MED SNR (DC3)</option>-->
|
||||
<!--<option value="230">LOW SNR (DC0)</option>-->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="input-group input-group-sm"> <span class="input-group-text" id="basic-addon1">Frames</span>
|
||||
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="framesperburst">
|
||||
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="framesperburst" disabled>
|
||||
<option selected value="1">1</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -146,7 +146,7 @@ class audio_buffer:
|
|||
# a buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
||||
# self.nbuffer is the current number of samples in the buffer
|
||||
def __init__(self, size):
|
||||
print("create audio_buffer: ", size)
|
||||
structlog.get_logger("structlog").debug("[C2 ] creating audio buffer", size=size)
|
||||
self.size = size
|
||||
self.buffer = np.zeros(size, dtype=np.int16)
|
||||
self.nbuffer = 0
|
||||
|
@ -180,7 +180,7 @@ class resampler:
|
|||
MEM48 = api.FDMDV_OS_TAPS_48K
|
||||
|
||||
def __init__(self):
|
||||
print("create 48<->8 kHz resampler")
|
||||
structlog.get_logger("structlog").debug("[C2 ] create 48<->8 kHz resampler")
|
||||
self.filter_mem8 = np.zeros(self.MEM8, dtype=np.int16)
|
||||
self.filter_mem48 = np.zeros(self.MEM48)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import os
|
|||
import queue
|
||||
import audio
|
||||
import sock
|
||||
|
||||
import atexit
|
||||
|
||||
class DAEMON():
|
||||
def __init__(self):
|
||||
|
@ -89,6 +89,7 @@ class DAEMON():
|
|||
# data[15] rigctld_port
|
||||
# data[16] send_scatter
|
||||
# data[17] send_fft
|
||||
# data[18] low_bandwith_mode
|
||||
|
||||
if data[0] == 'STARTTNC':
|
||||
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||
|
@ -150,6 +151,9 @@ class DAEMON():
|
|||
if data[17] == 'True':
|
||||
options.append('--fft')
|
||||
|
||||
if data[18] == 'True':
|
||||
options.append('--500hz')
|
||||
|
||||
# try running tnc from binary, else run from source
|
||||
# this helps running the tnc in a developer environment
|
||||
try:
|
||||
|
@ -161,6 +165,8 @@ class DAEMON():
|
|||
|
||||
command += options
|
||||
p = subprocess.Popen(command)
|
||||
atexit.register(p.kill)
|
||||
|
||||
structlog.get_logger("structlog").info("[DMN] TNC started", path="binary")
|
||||
except:
|
||||
command = []
|
||||
|
@ -176,7 +182,14 @@ class DAEMON():
|
|||
|
||||
static.TNCPROCESS = p # .pid
|
||||
static.TNCSTARTED = True
|
||||
|
||||
'''
|
||||
# WE HAVE THIS PART in SOCKET
|
||||
if data[0] == 'STOPTNC':
|
||||
static.TNCPROCESS.kill()
|
||||
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
|
||||
#os.kill(static.TNCPROCESS, signal.SIGKILL)
|
||||
static.TNCSTARTED = False
|
||||
'''
|
||||
# data[1] devicename
|
||||
# data[2] deviceport
|
||||
# data[3] serialspeed
|
||||
|
|
|
@ -32,8 +32,6 @@ class DATA():
|
|||
|
||||
def __init__(self):
|
||||
|
||||
print("init DATA handler...")
|
||||
|
||||
self.data_queue_transmit = DATA_QUEUE_TRANSMIT
|
||||
self.data_queue_received = DATA_QUEUE_RECEIVED
|
||||
|
||||
|
@ -48,10 +46,30 @@ class DATA():
|
|||
self.data_frame_bof = b'BOF' # 2 bytes for the BOF End of File indicator in a data frame
|
||||
self.data_frame_eof = b'EOF' # 2 bytes for the EOF End of File indicator in a data frame
|
||||
|
||||
#self.mode_list = [14,14,14,12,10] # mode list of available modes, each mode will be used 2times per speed level
|
||||
self.mode_list = [14,12,10] # mode list of available modes, each mode will be used 2times per speed level
|
||||
self.time_list = [3, 6, 7] # list for time to wait for correspinding mode in seconds
|
||||
self.rx_n_max_retries_per_burst = 10
|
||||
self.n_retries_per_burst = 0
|
||||
|
||||
self.received_low_bandwith_mode = False # indicator if we recevied a low bandwith mode channel ope ner
|
||||
|
||||
self.data_channel_max_retries = 3
|
||||
|
||||
self.mode_list_low_bw = [14,12]
|
||||
self.time_list_low_bw = [3,6]
|
||||
|
||||
self.mode_list_high_bw = [14,12,10] # mode list of available modes, each mode will be used 2times per speed level
|
||||
self.time_list_high_bw = [3, 6, 7] # list for time to wait for correspinding mode in seconds
|
||||
|
||||
# mode list for selecting between low bandwith ( 500Hz ) and normal modes with higher bandwith
|
||||
if static.LOW_BANDWITH_MODE:
|
||||
self.mode_list = self.mode_list_low_bw # mode list of available modes, each mode will be used 2times per speed level
|
||||
self.time_list = self.time_list_low_bw # list for time to wait for correspinding mode in seconds
|
||||
|
||||
else:
|
||||
self.mode_list = self.mode_list_high_bw # mode list of available modes, each mode will be used 2times per speed level
|
||||
self.time_list = self.time_list_high_bw # list for time to wait for correspinding mode in seconds
|
||||
|
||||
self.speed_level = len(self.mode_list) - 1 # speed level for selecting mode
|
||||
|
||||
self.is_IRS = False
|
||||
self.burst_nack = False
|
||||
self.burst_nack_counter = 0
|
||||
|
@ -60,7 +78,7 @@ class DATA():
|
|||
self.rx_frame_bof_received = False
|
||||
self.rx_frame_eof_received = False
|
||||
|
||||
self.transmission_timeout = 120 # transmission timeout in seconds
|
||||
self.transmission_timeout = 30 # transmission timeout in seconds
|
||||
|
||||
worker_thread_transmit = threading.Thread(target=self.worker_transmit, name="worker thread transmit")
|
||||
worker_thread_transmit.start()
|
||||
|
@ -222,24 +240,31 @@ class DATA():
|
|||
self.received_ping_ack(bytes_out[:-2])
|
||||
|
||||
# ARQ FILE TRANSFER RECEIVED!
|
||||
elif frametype == 225:
|
||||
elif frametype == 225 or frametype == 227:
|
||||
structlog.get_logger("structlog").debug("ARQ arq_received_data_channel_opener")
|
||||
self.arq_received_data_channel_opener(bytes_out[:-2])
|
||||
|
||||
# ARQ CHANNEL IS OPENED
|
||||
elif frametype == 226:
|
||||
elif frametype == 226 or frametype == 228:
|
||||
structlog.get_logger("structlog").debug("ARQ arq_received_channel_is_open")
|
||||
self.arq_received_channel_is_open(bytes_out[:-2])
|
||||
|
||||
|
||||
|
||||
# ARQ MANUAL MODE TRANSMISSION
|
||||
elif 230 <= frametype <= 240 :
|
||||
structlog.get_logger("structlog").debug("ARQ manual mode ")
|
||||
self.arq_received_data_channel_opener(bytes_out[:-2])
|
||||
|
||||
|
||||
# ARQ STOP TRANSMISSION
|
||||
elif frametype == 227:
|
||||
elif frametype == 249:
|
||||
structlog.get_logger("structlog").debug("ARQ received stop transmission")
|
||||
self.received_stop_transmission()
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
# this is outdated and we may remove it
|
||||
elif frametype == 230:
|
||||
elif frametype == 250:
|
||||
structlog.get_logger("structlog").debug("BEACON RECEIVED")
|
||||
self.received_beacon(bytes_out[:-2])
|
||||
|
||||
|
@ -283,7 +308,6 @@ class DATA():
|
|||
if len(static.RX_BURST_BUFFER) != RX_N_FRAMES_PER_BURST:
|
||||
static.RX_BURST_BUFFER = [None] * RX_N_FRAMES_PER_BURST
|
||||
|
||||
|
||||
# append data to rx burst buffer
|
||||
static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = data_in[6:] # [frame_type][n_frames_per_burst][CRC16][CRC16]
|
||||
|
||||
|
@ -320,7 +344,7 @@ class DATA():
|
|||
self.speed_level = len(self.mode_list) - 1
|
||||
|
||||
# updated modes we are listening to
|
||||
self.set_listening_modes()
|
||||
self.set_listening_modes(self.mode_list[self.speed_level])
|
||||
|
||||
|
||||
# create an ack frame
|
||||
|
@ -381,8 +405,6 @@ class DATA():
|
|||
structlog.get_logger("structlog").error("we shouldnt reach this point...", frame=RX_N_FRAME_OF_BURST, frames=RX_N_FRAMES_PER_BURST)
|
||||
|
||||
|
||||
|
||||
|
||||
# We have a BOF and EOF flag in our data. If we received both we received our frame.
|
||||
# In case of loosing data but we received already a BOF and EOF we need to make sure, we
|
||||
# received the complete last burst by checking it for Nones
|
||||
|
@ -391,9 +413,15 @@ class DATA():
|
|||
|
||||
# get total bytes per transmission information as soon we recevied a frame with a BOF
|
||||
if bof_position >=0:
|
||||
crc_position = bof_position+len(self.data_frame_bof)
|
||||
size_position = crc_position + 4
|
||||
static.TOTAL_BYTES = int.from_bytes(bytes(static.RX_FRAME_BUFFER[size_position:size_position + 4]), "big") # Bytes
|
||||
|
||||
payload = static.RX_FRAME_BUFFER[bof_position+len(self.data_frame_bof):eof_position]
|
||||
frame_length = int.from_bytes(payload[4:8], "big") #4:8 4bytes
|
||||
static.TOTAL_BYTES = frame_length
|
||||
compression_factor = int.from_bytes(payload[8:9], "big") #4:8 4bytes
|
||||
static.ARQ_COMPRESSION_FACTOR = compression_factor / 10
|
||||
self.calculate_transfer_rate_rx(self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER))
|
||||
|
||||
|
||||
if bof_position >= 0 and eof_position > 0 and not None in static.RX_BURST_BUFFER:
|
||||
print(f"bof_position {bof_position} / eof_position {eof_position}")
|
||||
self.rx_frame_bof_received = True
|
||||
|
@ -402,11 +430,13 @@ class DATA():
|
|||
#now extract raw data from buffer
|
||||
payload = static.RX_FRAME_BUFFER[bof_position+len(self.data_frame_bof):eof_position]
|
||||
# get the data frame crc
|
||||
data_frame_crc = payload[:4] #0:4 4bytes
|
||||
frame_length = int.from_bytes(payload[4:8], "big") #4:8 4bytes
|
||||
static.TOTAL_BYTES = frame_length
|
||||
# 8:9 = compression factor
|
||||
|
||||
data_frame_crc = payload[:4]
|
||||
frame_length = int.from_bytes(bytes(static.RX_FRAME_BUFFER[size_position:size_position + 4]), "big")
|
||||
data_frame = payload[9:]
|
||||
|
||||
data_frame = payload[8:]
|
||||
data_frame_crc_received = helpers.get_crc_32(data_frame)
|
||||
# check if data_frame_crc is equal with received crc
|
||||
if data_frame_crc == data_frame_crc_received:
|
||||
|
@ -501,7 +531,6 @@ class DATA():
|
|||
|
||||
self.speed_level = len(self.mode_list) - 1 # speed level for selecting mode
|
||||
|
||||
|
||||
TX_N_SENT_BYTES = 0 # already sent bytes per data frame
|
||||
self.tx_n_retry_of_burst = 0 # retries we already sent data
|
||||
TX_N_MAX_RETRIES_PER_BURST = 50 # max amount of retries we sent before frame is lost
|
||||
|
@ -524,7 +553,10 @@ class DATA():
|
|||
|
||||
# compression
|
||||
data_frame_compressed = zlib.compress(data_out)
|
||||
static.ARQ_COMPRESSION_FACTOR = len(data_out) / len(data_frame_compressed)
|
||||
compression_factor = len(data_out) / len(data_frame_compressed)
|
||||
static.ARQ_COMPRESSION_FACTOR = compression_factor
|
||||
compression_factor = bytes([int(static.ARQ_COMPRESSION_FACTOR * 10)])
|
||||
|
||||
data_out = data_frame_compressed
|
||||
|
||||
# reset statistics
|
||||
|
@ -534,7 +566,7 @@ class DATA():
|
|||
# append a crc and beginn and end of file indicators
|
||||
frame_payload_crc = helpers.get_crc_32(data_out)
|
||||
# data_out = self.data_frame_bof + frame_payload_crc + data_out + self.data_frame_eof
|
||||
data_out = self.data_frame_bof + frame_payload_crc + frame_total_size + data_out + self.data_frame_eof
|
||||
data_out = self.data_frame_bof + frame_payload_crc + frame_total_size + compression_factor + data_out + self.data_frame_eof
|
||||
|
||||
#initial bufferposition is 0
|
||||
bufferposition = 0
|
||||
|
@ -559,17 +591,25 @@ class DATA():
|
|||
# as soon as we received an ACK for the current burst, speed_level will increase
|
||||
# by 1.
|
||||
# the can be optimised by checking the optimal speed level for the current conditions
|
||||
|
||||
'''
|
||||
if not self.tx_n_retry_of_burst % 2 and self.tx_n_retry_of_burst > 0:
|
||||
self.speed_level -= 1
|
||||
if self.speed_level < 0:
|
||||
self.speed_level = 0
|
||||
'''
|
||||
|
||||
#if self.tx_n_retry_of_burst <= 1:
|
||||
# self.speed_level += 1
|
||||
# if self.speed_level >= len(self.mode_list)-1:
|
||||
# self.speed_level = len(self.mode_list)-1
|
||||
|
||||
# if speed level is greater than our available modes, set speed level to maximum = lenght of mode list -1
|
||||
|
||||
print(self.mode_list)
|
||||
if self.speed_level >= len(self.mode_list):
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
data_mode = self.mode_list[self.speed_level]
|
||||
|
||||
structlog.get_logger("structlog").debug("Speed-level", level=self.speed_level, retry=self.tx_n_retry_of_burst)
|
||||
|
||||
|
||||
|
@ -625,11 +665,14 @@ class DATA():
|
|||
time.sleep(0.01)
|
||||
|
||||
# after transmission finished wait for an ACK or RPT frame
|
||||
'''
|
||||
burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS + 100
|
||||
while not self.burst_ack and not self.burst_nack and not self.rpt_request_received and not self.data_frame_ack_received and time.time() < burstacktimeout and static.ARQ_STATE:
|
||||
time.sleep(0.01)
|
||||
#structlog.get_logger("structlog").debug("[TNC] waiting for ack", burst_ack=self.burst_ack, frame_ack = self.data_frame_ack_received, arq_state = static.ARQ_STATE, overflows=static.BUFFER_OVERFLOW_COUNTER)
|
||||
|
||||
'''
|
||||
#burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS + 100
|
||||
while not self.burst_ack and not self.burst_nack and not self.rpt_request_received and not self.data_frame_ack_received and static.ARQ_STATE:
|
||||
time.sleep(0.01)
|
||||
|
||||
# once we received a burst ack, reset its state and break the RETRIES loop
|
||||
if self.burst_ack:
|
||||
|
@ -782,38 +825,35 @@ class DATA():
|
|||
return False
|
||||
|
||||
def arq_open_data_channel(self, mode:int, n_frames_per_burst:int):
|
||||
|
||||
self.is_IRS = False
|
||||
|
||||
DATA_CHANNEL_MAX_RETRIES = 5 # N attempts for connecting to another station
|
||||
self.data_channel_last_received = int(time.time())
|
||||
|
||||
# devide by 1024 for getting Bytes -> kBytes
|
||||
#data_len = int(data_len / 1024)
|
||||
if static.LOW_BANDWITH_MODE and mode == 255:
|
||||
frametype = bytes([227])
|
||||
structlog.get_logger("structlog").debug("requesting low bandwith mode")
|
||||
|
||||
# multiply compression factor for reducing it from float to int
|
||||
compression_factor = int(static.ARQ_COMPRESSION_FACTOR * 10)
|
||||
else:
|
||||
frametype = bytes([225])
|
||||
structlog.get_logger("structlog").debug("requesting high bandwith mode")
|
||||
|
||||
|
||||
if 230 <= mode <= 240:
|
||||
structlog.get_logger("structlog").debug("requesting manual mode --> not yet implemented ")
|
||||
frametype = bytes([mode])
|
||||
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = bytes([225])
|
||||
connection_frame[:1] = frametype
|
||||
connection_frame[1:3] = static.DXCALLSIGN_CRC
|
||||
connection_frame[3:5] = static.MYCALLSIGN_CRC
|
||||
connection_frame[5:11] = static.MYCALLSIGN
|
||||
connection_frame[11:12] = bytes([mode])
|
||||
#connection_frame[10:12] = data_len.to_bytes(2, byteorder='big')
|
||||
connection_frame[12:13] = bytes([compression_factor])
|
||||
connection_frame[13:14] = bytes([n_frames_per_burst])
|
||||
|
||||
|
||||
while not static.ARQ_STATE:
|
||||
time.sleep(0.01)
|
||||
for attempt in range(1,DATA_CHANNEL_MAX_RETRIES+1):
|
||||
for attempt in range(1,self.data_channel_max_retries+1):
|
||||
static.INFO.append("DATACHANNEL;OPENING")
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | TX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]", attempt=str(attempt) + "/" + str(DATA_CHANNEL_MAX_RETRIES))
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | TX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]", attempt=str(attempt) + "/" + str(self.data_channel_max_retries))
|
||||
txbuffer = [connection_frame]
|
||||
|
||||
static.TRANSMITTING = True
|
||||
modem.MODEM_TRANSMIT_QUEUE.put([14,1,0,txbuffer])
|
||||
# wait while transmitting
|
||||
|
@ -829,7 +869,7 @@ class DATA():
|
|||
if static.ARQ_STATE:
|
||||
break
|
||||
|
||||
if not static.ARQ_STATE and attempt == DATA_CHANNEL_MAX_RETRIES:
|
||||
if not static.ARQ_STATE and attempt == self.data_channel_max_retries:
|
||||
static.INFO.append("DATACHANNEL;FAILED")
|
||||
|
||||
structlog.get_logger("structlog").warning("[TNC] ARQ | TX | DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>X<<[" + str(static.DXCALLSIGN, 'utf-8') + "]")
|
||||
|
@ -840,59 +880,60 @@ class DATA():
|
|||
return False
|
||||
#sys.exit() # close thread and so connection attempts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def arq_received_data_channel_opener(self, data_in:bytes):
|
||||
|
||||
self.is_IRS = True
|
||||
|
||||
static.INFO.append("DATACHANNEL;RECEIVEDOPENER")
|
||||
static.DXCALLSIGN_CRC = bytes(data_in[3:5])
|
||||
static.DXCALLSIGN = bytes(data_in[5:11]).rstrip(b'\x00')
|
||||
static.ARQ_COMPRESSION_FACTOR = float(int.from_bytes(bytes(data_in[12:13]), "big") / 10)
|
||||
n_frames_per_burst = int.from_bytes(bytes(data_in[13:14]), "big")
|
||||
mode = int.from_bytes(bytes(data_in[11:12]), "big")
|
||||
frametype = int.from_bytes(bytes(data_in[:1]), "big")
|
||||
#check if we received low bandwith mode
|
||||
if frametype == 225:
|
||||
self.received_low_bandwith_mode = False
|
||||
self.mode_list = self.mode_list_high_bw
|
||||
self.time_list = self.time_list_high_bw
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
else:
|
||||
self.received_low_bandwith_mode = True
|
||||
self.mode_list = self.mode_list_low_bw
|
||||
self.time_list = self.time_list_low_bw
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
|
||||
|
||||
if 230 <= frametype <= 240:
|
||||
print("manual mode request")
|
||||
|
||||
# updated modes we are listening to
|
||||
self.set_listening_modes()
|
||||
'''
|
||||
# set modes we want to listening to
|
||||
mode_name = codec2.freedv_get_mode_name_by_value(mode)
|
||||
if mode_name == 'datac1':
|
||||
modem.RECEIVE_DATAC1 = True
|
||||
elif mode_name == 'datac3':
|
||||
modem.RECEIVE_DATAC3 = True
|
||||
elif mode_name == 'allmodes':
|
||||
pass
|
||||
#modem.RECEIVE_DATAC1 = True
|
||||
#modem.RECEIVE_DATAC3 = True
|
||||
'''
|
||||
|
||||
|
||||
|
||||
#we need to find a way how to do this. this isn't working anymore since we mode to a class based module
|
||||
#modem.set_frames_per_burst(n_frames_per_burst)
|
||||
self.set_listening_modes(self.mode_list[self.speed_level])
|
||||
|
||||
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'DATA-CHANNEL', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | RX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]")
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | RX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]", bandwith="wide")
|
||||
|
||||
static.ARQ_STATE = True
|
||||
static.TNC_STATE = 'BUSY'
|
||||
|
||||
# reset ARQ statistics
|
||||
static.ARQ_BYTES_PER_MINUTE_BURST = 0
|
||||
static.ARQ_BYTES_PER_MINUTE = 0
|
||||
static.ARQ_BITS_PER_SECOND_BURST = 0
|
||||
static.ARQ_BITS_PER_SECOND = 0
|
||||
static.ARQ_TRANSMISSION_PERCENT = 0
|
||||
static.TOTAL_BYTES = 0
|
||||
|
||||
self.reset_statistics()
|
||||
|
||||
self.data_channel_last_received = int(time.time())
|
||||
# check if we are in low bandwith mode
|
||||
if static.LOW_BANDWITH_MODE or self.received_low_bandwith_mode:
|
||||
frametype = bytes([228])
|
||||
structlog.get_logger("structlog").debug("responding with low bandwith mode")
|
||||
else:
|
||||
frametype = bytes([226])
|
||||
structlog.get_logger("structlog").debug("responding with high bandwith mode")
|
||||
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = bytes([226])
|
||||
connection_frame[:1] = frametype
|
||||
connection_frame[1:3] = static.DXCALLSIGN_CRC
|
||||
connection_frame[3:5] = static.MYCALLSIGN_CRC
|
||||
#connection_frame[5:11] = static.MYCALLSIGN
|
||||
connection_frame[13:14] = bytes([static.ARQ_PROTOCOL_VERSION]) #crc8 of version for checking protocol version
|
||||
|
||||
txbuffer = [connection_frame]
|
||||
|
||||
|
@ -901,28 +942,46 @@ class DATA():
|
|||
# wait while transmitting
|
||||
while static.TRANSMITTING:
|
||||
time.sleep(0.01)
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | RX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | RX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", bandwith="wide", snr=static.SNR)
|
||||
|
||||
# set start of transmission for our statistics
|
||||
self.rx_start_of_transmission = time.time()
|
||||
|
||||
|
||||
|
||||
def arq_received_channel_is_open(self, data_in:bytes):
|
||||
protocol_version = int.from_bytes(bytes(data_in[13:14]), "big")
|
||||
if protocol_version == static.ARQ_PROTOCOL_VERSION:
|
||||
static.INFO.append("DATACHANNEL;OPEN")
|
||||
static.DXCALLSIGN_CRC = bytes(data_in[3:5])
|
||||
frametype = int.from_bytes(bytes(data_in[:1]), "big")
|
||||
|
||||
static.INFO.append("DATACHANNEL;OPEN")
|
||||
static.DXCALLSIGN_CRC = bytes(data_in[3:5])
|
||||
#static.DXCALLSIGN = bytes(data_in[5:11]).rstrip(b'\x00')
|
||||
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'DATA-CHANNEL', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
|
||||
|
||||
self.data_channel_last_received = int(time.time())
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | TX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||
|
||||
# as soon as we set ARQ_STATE to DATA, transmission starts
|
||||
static.ARQ_STATE = True
|
||||
self.data_channel_last_received = int(time.time())
|
||||
if frametype == 228:
|
||||
self.received_low_bandwith_mode = True
|
||||
self.mode_list = self.mode_list_low_bw
|
||||
self.time_list = self.time_list_low_bw
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
structlog.get_logger("structlog").debug("low bandwith mode", modes=self.mode_list)
|
||||
else:
|
||||
self.received_low_bandwith_mode = False
|
||||
self.mode_list = self.mode_list_high_bw
|
||||
self.time_list = self.time_list_high_bw
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
structlog.get_logger("structlog").debug("high bandwith mode", modes=self.mode_list)
|
||||
|
||||
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'DATA-CHANNEL', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
|
||||
|
||||
structlog.get_logger("structlog").info("[TNC] ARQ | DATA | TX | [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||
|
||||
# as soon as we set ARQ_STATE to DATA, transmission starts
|
||||
static.ARQ_STATE = True
|
||||
self.data_channel_last_received = int(time.time())
|
||||
else:
|
||||
static.TNC_STATE = 'IDLE'
|
||||
static.ARQ_STATE = False
|
||||
static.INFO.append("PROTOCOL;VERSION_MISSMATCH")
|
||||
structlog.get_logger("structlog").warning("protocol version missmatch", received=protocol_version, own=static.ARQ_PROTOCOL_VERSION)
|
||||
self.arq_cleanup()
|
||||
|
||||
|
||||
# ---------- PING
|
||||
|
@ -986,7 +1045,7 @@ class DATA():
|
|||
def stop_transmission(self):
|
||||
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
|
||||
stop_frame = bytearray(14)
|
||||
stop_frame[:1] = bytes([227])
|
||||
stop_frame[:1] = bytes([249])
|
||||
stop_frame[1:3] = static.DXCALLSIGN_CRC
|
||||
stop_frame[3:5] = static.MYCALLSIGN_CRC
|
||||
|
||||
|
@ -1017,7 +1076,7 @@ class DATA():
|
|||
while static.BEACON_STATE and not static.ARQ_STATE:
|
||||
|
||||
beacon_frame = bytearray(14)
|
||||
beacon_frame[:1] = bytes([230])
|
||||
beacon_frame[:1] = bytes([250])
|
||||
beacon_frame[1:2] = b'\x01'
|
||||
beacon_frame[2:8] = static.MYCALLSIGN
|
||||
beacon_frame[8:14] = static.MYGRID
|
||||
|
@ -1099,6 +1158,14 @@ class DATA():
|
|||
|
||||
|
||||
|
||||
def reset_statistics(self):
|
||||
# reset ARQ statistics
|
||||
static.ARQ_BYTES_PER_MINUTE_BURST = 0
|
||||
static.ARQ_BYTES_PER_MINUTE = 0
|
||||
static.ARQ_BITS_PER_SECOND_BURST = 0
|
||||
static.ARQ_BITS_PER_SECOND = 0
|
||||
static.ARQ_TRANSMISSION_PERCENT = 0
|
||||
static.TOTAL_BYTES = 0
|
||||
|
||||
def calculate_transfer_rate_tx(self, tx_start_of_transmission:float, sentbytes:int, tx_buffer_length:int) -> list:
|
||||
|
||||
|
@ -1156,6 +1223,14 @@ class DATA():
|
|||
self.frame_received_counter = 0
|
||||
self.speed_level = len(self.mode_list) - 1
|
||||
|
||||
# low bandwith mode indicator
|
||||
self.received_low_bandwith_mode = False
|
||||
|
||||
# reset retry counter for rx channel / burst
|
||||
self.n_retries_per_burst = 0
|
||||
|
||||
|
||||
|
||||
def arq_reset_ack(self,state:bool):
|
||||
|
||||
self.burst_ack = state
|
||||
|
@ -1163,16 +1238,21 @@ class DATA():
|
|||
self.data_frame_ack_received = state
|
||||
|
||||
|
||||
def set_listening_modes(self):
|
||||
# set modes we want to listening to
|
||||
mode_name = codec2.freedv_get_mode_name_by_value(self.mode_list[self.speed_level])
|
||||
def set_listening_modes(self, mode):
|
||||
# set modes we want listening to
|
||||
|
||||
mode_name = codec2.freedv_get_mode_name_by_value(mode)
|
||||
if mode_name == 'datac1':
|
||||
modem.RECEIVE_DATAC1 = True
|
||||
structlog.get_logger("structlog").debug("changing listening data mode", mode="datac1")
|
||||
|
||||
elif mode_name == 'datac3':
|
||||
modem.RECEIVE_DATAC3 = True
|
||||
structlog.get_logger("structlog").debug("changing listening data mode", mode="datac3")
|
||||
elif mode_name == 'allmodes':
|
||||
modem.RECEIVE_DATAC1 = True
|
||||
modem.RECEIVE_DATAC3 = True
|
||||
structlog.get_logger("structlog").debug("changing listening data mode", mode="datac1/datac3")
|
||||
|
||||
|
||||
# ------------------------- WATCHDOG FUNCTIONS FOR TIMER
|
||||
|
@ -1188,20 +1268,12 @@ class DATA():
|
|||
self.burst_watchdog()
|
||||
|
||||
def burst_watchdog(self):
|
||||
'''
|
||||
# ISS SIDE WE ALSO NEED TO CHECK TIME SO WE ARE SENDING IN CORRECT MODE IF WE MISSED A NACK FRAME
|
||||
if static.ARQ_STATE and static.TNC_STATE == 'BUSY' and not self.is_IRS:
|
||||
if self.data_channel_last_received + self.time_list[self.speed_level] < time.time():
|
||||
self.speed_level -= 1
|
||||
if self.speed_level <= 0:
|
||||
self.speed_level = 0
|
||||
self.data_channel_last_received = time.time()
|
||||
'''
|
||||
|
||||
# IRS SIDE
|
||||
if static.ARQ_STATE and static.TNC_STATE == 'BUSY' and self.is_IRS:
|
||||
if self.data_channel_last_received + self.time_list[self.speed_level] > time.time():
|
||||
print((self.data_channel_last_received + self.time_list[self.speed_level])-time.time())
|
||||
#pass
|
||||
#print((self.data_channel_last_received + self.time_list[self.speed_level])-time.time())
|
||||
pass
|
||||
else:
|
||||
print("TIMEOUT")
|
||||
self.frame_received_counter = 0
|
||||
|
@ -1210,7 +1282,7 @@ class DATA():
|
|||
self.speed_level = 0
|
||||
|
||||
# updated modes we are listening to
|
||||
self.set_listening_modes()
|
||||
self.set_listening_modes(self.mode_list[self.speed_level])
|
||||
|
||||
# BUILDING NACK FRAME FOR DATA FRAME
|
||||
burst_nack_frame = bytearray(14)
|
||||
|
@ -1229,6 +1301,12 @@ class DATA():
|
|||
# #time.sleep(0.01)
|
||||
# self.data_channel_last_received = time.time()
|
||||
self.data_channel_last_received = time.time()
|
||||
self.n_retries_per_burst += 1
|
||||
|
||||
if self.n_retries_per_burst >= self.rx_n_max_retries_per_burst:
|
||||
self.arq_cleanup()
|
||||
print("RX TIMEOUT!!!!")
|
||||
#print(self.n_retries_per_burst)
|
||||
|
||||
def data_channel_keep_alive_watchdog(self):
|
||||
"""
|
||||
|
@ -1241,6 +1319,7 @@ class DATA():
|
|||
time.sleep(0.01)
|
||||
if self.data_channel_last_received + self.transmission_timeout > time.time():
|
||||
time.sleep(0.01)
|
||||
#print(self.data_channel_last_received + self.transmission_timeout - time.time())
|
||||
#pass
|
||||
else:
|
||||
self.data_channel_last_received = 0
|
||||
|
|
|
@ -42,7 +42,7 @@ if __name__ == '__main__':
|
|||
PARSER.add_argument('--rigctld_ip', dest="rigctld_ip", default="direct", help="Set rigctld ip")
|
||||
PARSER.add_argument('--scatter', dest="send_scatter", action="store_true", help="Send scatter information via network")
|
||||
PARSER.add_argument('--fft', dest="send_fft", action="store_true", help="Send fft information via network")
|
||||
|
||||
PARSER.add_argument('--500hz', dest="low_bandwith_mode", action="store_true", help="Enable low bandwith mode ( 500 Hz only )")
|
||||
|
||||
|
||||
|
||||
|
@ -67,6 +67,11 @@ if __name__ == '__main__':
|
|||
static.HAMLIB_RGICTLD_PORT = ARGS.rigctld_port
|
||||
static.ENABLE_SCATTER = ARGS.send_scatter
|
||||
static.ENABLE_FFT = ARGS.send_fft
|
||||
static.LOW_BANDWITH_MODE = ARGS.low_bandwith_mode
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
||||
import sock
|
||||
|
|
11
tnc/rig.py
11
tnc/rig.py
|
@ -106,7 +106,6 @@ class radio:
|
|||
# get devicenumber by looking for deviceobject in Hamlib module
|
||||
try:
|
||||
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||
print(self.devicenumber)
|
||||
except:
|
||||
structlog.get_logger("structlog").error("[RIG] Hamlib: rig not supported...")
|
||||
self.devicenumber = 0
|
||||
|
@ -122,14 +121,6 @@ class radio:
|
|||
self.my_rig.set_conf("ptt_pathname", self.pttport)
|
||||
|
||||
|
||||
print(self.my_rig.get_conf("rig_pathname"))
|
||||
print(self.my_rig.get_conf("retry"))
|
||||
print(self.my_rig.get_conf("serial_speed"))
|
||||
print(self.my_rig.get_conf("serial_handshake"))
|
||||
print(self.my_rig.get_conf("stop_bits"))
|
||||
print(self.my_rig.get_conf("data_bits"))
|
||||
print(self.my_rig.get_conf("ptt_pathname"))
|
||||
|
||||
|
||||
|
||||
if self.hamlib_ptt_type == 'RIG':
|
||||
|
@ -168,6 +159,8 @@ class radio:
|
|||
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||
|
||||
structlog.get_logger("structlog").info("[RIG] Opening...", device=self.devicenumber, path=self.my_rig.get_conf("rig_pathname"), serial_speed=self.my_rig.get_conf("serial_speed"), serial_handshake=self.my_rig.get_conf("serial_handshake"), stop_bits=self.my_rig.get_conf("stop_bits"), data_bits=self.my_rig.get_conf("data_bits"), ptt_pathname=self.my_rig.get_conf("ptt_pathname"))
|
||||
|
||||
|
||||
self.my_rig.open()
|
||||
atexit.register(self.my_rig.close)
|
||||
|
|
140
tnc/sock.py
140
tnc/sock.py
|
@ -50,16 +50,21 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
|
||||
|
||||
def send_to_client(self):
|
||||
tempdata = b''
|
||||
while self.connection_alive:
|
||||
# send tnc state as network stream
|
||||
# check server port against daemon port and send corresponding data
|
||||
|
||||
if self.server.server_address[1] == static.PORT and not static.TNCSTARTED:
|
||||
data = send_tnc_state()
|
||||
SOCKET_QUEUE.put(data)
|
||||
if data != tempdata:
|
||||
tempdata = data
|
||||
SOCKET_QUEUE.put(data)
|
||||
else:
|
||||
data = send_daemon_state()
|
||||
SOCKET_QUEUE.put(data)
|
||||
if data != tempdata:
|
||||
tempdata = data
|
||||
SOCKET_QUEUE.put(data)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
|
@ -96,14 +101,20 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
#print("connection broken. Closing...")
|
||||
self.connection_alive = False
|
||||
|
||||
if data.startswith(b'{"type"') and data.endswith(b'}\n'):
|
||||
data = data[:-1] # remove b'\n'
|
||||
print(data)
|
||||
if self.server.server_address[1] == static.PORT:
|
||||
process_tnc_commands(data)
|
||||
else:
|
||||
process_daemon_commands(data)
|
||||
if data.startswith(b'{') and data.endswith(b'}\n'):
|
||||
# split data by \n if we have multiple commands in socket buffer
|
||||
data = data.split(b'\n')
|
||||
# remove empty data
|
||||
data.remove(b'')
|
||||
|
||||
# iterate thorugh data list
|
||||
for commands in data:
|
||||
if self.server.server_address[1] == static.PORT:
|
||||
process_tnc_commands(commands)
|
||||
else:
|
||||
process_daemon_commands(commands)
|
||||
|
||||
# finally delete our rx buffer to be ready for new commands
|
||||
data = bytes()
|
||||
|
||||
|
||||
|
@ -128,7 +139,6 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
|||
CONNECTED_CLIENTS.remove(self.request)
|
||||
except:
|
||||
print("client connection already removed from client list")
|
||||
print(CONNECTED_CLIENTS)
|
||||
|
||||
|
||||
def process_tnc_commands(data):
|
||||
|
@ -189,89 +199,6 @@ def process_tnc_commands(data):
|
|||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
# TRANSMIT FILE ----------------------------------------------------------
|
||||
'''
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "send_file":
|
||||
try:
|
||||
static.TNC_STATE = 'BUSY'
|
||||
|
||||
# on a new transmission we reset the timer
|
||||
static.ARQ_START_OF_TRANSMISSION = int(time.time())
|
||||
|
||||
dxcallsign = received_json["parameter"][0]["dxcallsign"]
|
||||
mode = int(received_json["parameter"][0]["mode"])
|
||||
n_frames = int(received_json["parameter"][0]["n_frames"])
|
||||
filename = received_json["parameter"][0]["filename"]
|
||||
filetype = received_json["parameter"][0]["filetype"]
|
||||
data = received_json["parameter"][0]["data"]
|
||||
checksum = received_json["parameter"][0]["checksum"]
|
||||
|
||||
|
||||
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
||||
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
|
||||
|
||||
# dt = datatype
|
||||
# --> f = file
|
||||
# --> m = message
|
||||
# fn = filename
|
||||
# ft = filetype
|
||||
# d = data
|
||||
# crc = checksum
|
||||
#rawdata = {"dt": "f", "fn": filename, "ft": filetype,"d": data, "crc": checksum}
|
||||
#dataframe = json.dumps(rawdata)
|
||||
#data_out = bytes(dataframe, 'utf-8')
|
||||
|
||||
rawdata = bytes()
|
||||
rawdata += bytes('f', 'utf-8')
|
||||
rawdata += bytes(';', 'utf-8')
|
||||
rawdata += bytes(filename, 'utf-8')
|
||||
rawdata += bytes(';', 'utf-8')
|
||||
rawdata += bytes(filetype, 'utf-8')
|
||||
rawdata += bytes(';', 'utf-8')
|
||||
rawdata += bytes(checksum, 'utf-8')
|
||||
rawdata += bytes(';', 'utf-8')
|
||||
rawdata += bytes(data, 'utf-8')
|
||||
|
||||
|
||||
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_FILE', data_out, mode, n_frames])
|
||||
print(data_handler.DATA_QUEUE_TRANSMIT.qsize())
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
# TRANSMIT MESSAGE ----------------------------------------------------------
|
||||
if received_json["type"] == 'arq' and received_json["command"] == "send_message":
|
||||
try:
|
||||
static.TNC_STATE = 'BUSY'
|
||||
print(received_json)
|
||||
# on a new transmission we reset the timer
|
||||
static.ARQ_START_OF_TRANSMISSION = int(time.time())
|
||||
|
||||
dxcallsign = received_json["parameter"][0]["dxcallsign"]
|
||||
mode = int(received_json["parameter"][0]["mode"])
|
||||
n_frames = int(received_json["parameter"][0]["n_frames"])
|
||||
data = received_json["parameter"][0]["data"] # d = data
|
||||
checksum = received_json["parameter"][0]["checksum"] # crc = checksum
|
||||
|
||||
|
||||
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
||||
static.DXCALLSIGN_CRC = helpers.get_crc_16(static.DXCALLSIGN)
|
||||
|
||||
# dt = datatype
|
||||
# --> f = file
|
||||
# --> m = message
|
||||
# fn = filename
|
||||
# ft = filetype
|
||||
# d = data
|
||||
# crc = checksum
|
||||
rawdata = {"dt": "m","d": data, "crc": checksum}
|
||||
dataframe = json.dumps(rawdata)
|
||||
data_out = bytes(dataframe, 'utf-8')
|
||||
|
||||
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_MESSAGE', data_out, mode, n_frames])
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
'''
|
||||
|
||||
|
||||
# STOP TRANSMISSION ----------------------------------------------------------
|
||||
|
@ -306,31 +233,13 @@ def process_tnc_commands(data):
|
|||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
'''
|
||||
if received_json["type"] == 'GET' and received_json["command"] == 'rx_msg_buffer':
|
||||
output = {
|
||||
"command": "rx_msg_buffer",
|
||||
"data-array": [],
|
||||
}
|
||||
for i in range(0, len(static.RX_MSG_BUFFER)):
|
||||
|
||||
rawdata = json.loads(static.RX_MSG_BUFFER[i][3])
|
||||
output["data-array"].append({"dxcallsign": str(static.RX_MSG_BUFFER[i][0], 'utf-8'), "dxgrid": str(static.RX_MSG_BUFFER[i][1], 'utf-8'), "timestamp": static.RX_MSG_BUFFER[i][2], "rxdata": [rawdata]})
|
||||
|
||||
jsondata = json.dumps(output)
|
||||
#self.request.sendall(bytes(jsondata, encoding))
|
||||
SOCKET_QUEUE.put(jsondata)
|
||||
'''
|
||||
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer':
|
||||
try:
|
||||
static.RX_BUFFER = []
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
|
||||
|
||||
'''
|
||||
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_msg_buffer':
|
||||
static.RX_MSG_BUFFER = []
|
||||
'''
|
||||
# exception, if JSON cant be decoded
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
|
||||
|
@ -427,6 +336,7 @@ def process_daemon_commands(data):
|
|||
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||
enable_scatter = str(received_json["parameter"][0]["enable_scatter"])
|
||||
enable_fft = str(received_json["parameter"][0]["enable_fft"])
|
||||
low_bandwith_mode = str(received_json["parameter"][0]["low_bandwith_mode"])
|
||||
|
||||
DAEMON_QUEUE.put(['STARTTNC', \
|
||||
mycall, \
|
||||
|
@ -445,7 +355,8 @@ def process_daemon_commands(data):
|
|||
rigctld_ip, \
|
||||
rigctld_port, \
|
||||
enable_scatter, \
|
||||
enable_fft \
|
||||
enable_fft, \
|
||||
low_bandwith_mode \
|
||||
])
|
||||
|
||||
except Exception as e:
|
||||
|
@ -465,6 +376,7 @@ def process_daemon_commands(data):
|
|||
radiocontrol = str(received_json["parameter"][0]["radiocontrol"])
|
||||
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
||||
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
||||
|
||||
DAEMON_QUEUE.put(['TEST_HAMLIB', \
|
||||
devicename, \
|
||||
deviceport, \
|
||||
|
@ -501,8 +413,8 @@ def send_daemon_state():
|
|||
'input_devices': static.AUDIO_INPUT_DEVICES,
|
||||
'output_devices': static.AUDIO_OUTPUT_DEVICES,
|
||||
'serial_devices': static.SERIAL_DEVICES,
|
||||
'cpu': str(psutil.cpu_percent()),
|
||||
'ram': str(psutil.virtual_memory().percent),
|
||||
#'cpu': str(psutil.cpu_percent()),
|
||||
#'ram': str(psutil.virtual_memory().percent),
|
||||
'version': '0.1'
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ Created on Wed Dec 23 11:13:57 2020
|
|||
Here we are saving application wide variables and stats, which have to be accessed everywhere.
|
||||
Not nice, tipps are appreciated :-)
|
||||
"""
|
||||
|
||||
VERSION = '0.1'
|
||||
|
||||
# DAEMON
|
||||
DAEMONPORT = 3001
|
||||
TNCSTARTED = False
|
||||
|
@ -23,6 +26,7 @@ DXCALLSIGN_CRC = b'A'
|
|||
MYGRID = b''
|
||||
DXGRID = b''
|
||||
|
||||
LOW_BANDWITH_MODE = False
|
||||
# ---------------------------------
|
||||
|
||||
# Server Defaults
|
||||
|
@ -73,6 +77,9 @@ AUDIO_RMS = 0
|
|||
FFT = [0]
|
||||
ENABLE_FFT = False
|
||||
|
||||
# ARQ PROTOCOL VERSION
|
||||
ARQ_PROTOCOL_VERSION = 0
|
||||
|
||||
# ARQ statistics
|
||||
ARQ_BYTES_PER_MINUTE_BURST = 0
|
||||
ARQ_BYTES_PER_MINUTE = 0
|
||||
|
|
Loading…
Reference in a new issue