From 19b18d071923ca6cca8fafa8900a61050c12a131 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Tue, 4 Oct 2022 10:55:42 +0200 Subject: [PATCH 01/47] fixed windows rigctld list command --- gui/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/main.js b/gui/main.js index dab66fc9..1683c873 100644 --- a/gui/main.js +++ b/gui/main.js @@ -829,7 +829,7 @@ ipcMain.on('request-check-rigctld',(data)=>{ try { if(os.platform()=='win32' || os.platform()=='win64'){ - var state = exec('tasklist', ['/svc', '/FI', 'ImageName eq rigctld*']) + var state = exec('tasklist', ['/svc', '/FI', '"ImageName eq rigctld*"']) state.on('close', function(code) { if(code == 0){ let Data = { From 9045746466ea9223bc0138791df52c439a86b9b2 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 10:56:58 +0200 Subject: [PATCH 02/47] another way of checking if process is running --- gui/main.js | 132 +++++++++++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 74 deletions(-) diff --git a/gui/main.js b/gui/main.js index 1683c873..e750b921 100644 --- a/gui/main.js +++ b/gui/main.js @@ -9,7 +9,9 @@ const { autoUpdater } = require('electron-updater'); const path = require('path'); const fs = require('fs'); const os = require('os'); -const exec = require('child_process').spawn; +const spawn = require('child_process').spawn; +const exec = require('child_process').exec; + const log = require('electron-log'); const mainLog = log.scope('main'); const daemonProcessLog = log.scope('freedata-daemon'); @@ -285,7 +287,7 @@ app.whenReady().then(() => { mainLog.info('Starting freedata-daemon binary'); if(os.platform()=='darwin'){ - daemonProcess = exec(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [], + daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [], { cwd: path.join(process.resourcesPath, 'tnc'), }); @@ -310,7 +312,7 @@ app.whenReady().then(() => { }); */ - daemonProcess = exec(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [], + daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [], { cwd: path.join(process.resourcesPath, 'tnc'), }); @@ -321,7 +323,7 @@ app.whenReady().then(() => { // for windows the relative path via path.join(__dirname) is not needed for some reason //daemonProcess = exec('\\tnc\\daemon.exe', []) - daemonProcess = exec(path.join(process.resourcesPath, 'tnc', 'freedata-daemon.exe'), [], + daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon.exe'), [], { cwd: path.join(process.resourcesPath, 'tnc'), }); @@ -735,20 +737,20 @@ function close_sub_processes(){ try { if(os.platform()=='win32' || os.platform()=='win64'){ - exec('Taskkill', ['/IM', 'freedata-tnc.exe', '/F']) - exec('Taskkill', ['/IM', 'freedata-daemon.exe', '/F']) + spawn('Taskkill', ['/IM', 'freedata-tnc.exe', '/F']) + spawn('Taskkill', ['/IM', 'freedata-daemon.exe', '/F']) } if(os.platform()=='linux'){ - exec('pkill', ['-9', 'freedata-tnc']) - exec('pkill', ['-9', 'freedata-daemon']) + spawn('pkill', ['-9', 'freedata-tnc']) + spawn('pkill', ['-9', 'freedata-daemon']) } if(os.platform()=='darwin'){ - exec('pkill', ['-9', 'freedata-tnc']) - exec('pkill', ['-9', 'freedata-daemon']) + spawn('pkill', ['-9', 'freedata-tnc']) + spawn('pkill', ['-9', 'freedata-daemon']) } } catch (e) { @@ -779,7 +781,7 @@ ipcMain.on('request-start-rigctld',(event, data)=>{ try{ - exec(data.path, data.parameters); + spawn(data.path, data.parameters); } catch (e) { console.log(e); } @@ -803,18 +805,18 @@ ipcMain.on('request-stop-rigctld',(event,data)=>{ try { if(os.platform()=='win32' || os.platform()=='win64'){ - exec('Taskkill', ['/IM', 'rigctld.exe', '/F']) + spawn('Taskkill', ['/IM', 'rigctld.exe', '/F']) } if(os.platform()=='linux'){ - exec('pkill', ['-9', 'rigctld']) + spawn('pkill', ['-9', 'rigctld']) } if(os.platform()=='darwin'){ - exec('pkill', ['-9', 'rigctld']) + spawn('pkill', ['-9', 'rigctld']) } } catch (e) { @@ -827,68 +829,50 @@ ipcMain.on('request-stop-rigctld',(event,data)=>{ // CHECK RIGCTLD ipcMain.on('request-check-rigctld',(data)=>{ try { + let Data = { + state: "unknown", + }; - if(os.platform()=='win32' || os.platform()=='win64'){ - var state = exec('tasklist', ['/svc', '/FI', '"ImageName eq rigctld*"']) - state.on('close', function(code) { - if(code == 0){ - let Data = { - state: "running", - }; - win.webContents.send('action-check-rigctld', Data); + isRunning('rigctld', (status) => { + if (status){ + Data["state"] = "running"; + } else { + Data["state"] = "unknown"; + } + win.webContents.send('action-check-rigctld', Data); + }) - } else { - let Data = { - state: "unknown", - }; - win.webContents.send('action-check-rigctld', Data); - - } - }); - } - - if(os.platform()=='linux'){ - - var state = exec('pgrep', ['rigctld']) - state.on('close', function(code) { - if(code == 0){ - let Data = { - state: "running", - }; - win.webContents.send('action-check-rigctld', Data); - - } else { - let Data = { - state: "unknown", - }; - win.webContents.send('action-check-rigctld', Data); - - } - }); - - } - - if(os.platform()=='darwin'){ - - var state = exec('pgrep', ['rigctld']) - state.on('close', function(code) { - if(code == 0){ - let Data = { - state: "running", - }; - win.webContents.send('action-check-rigctld', Data); - - } else { - let Data = { - state: "unknown", - }; - win.webContents.send('action-check-rigctld', Data); - - } - }); - - } } catch (e) { mainLog.error(e) } -}); \ No newline at end of file +}); + + + + +// https://stackoverflow.com/a/51084163 +// Function for checking if a process is running or not +/* +isRunning('rigctld', (status) => { + if (status){ + Data["state"] = "running"; + } else { + Data["state"] = "unknown"; + } + win.webContents.send('action-check-rigctld', Data); + }) +*/ +const isRunning = (query, cb) => { + let platform = process.platform; + let cmd = ''; + switch (platform) { + case 'win32' : cmd = `tasklist`; break; + case 'darwin' : cmd = `ps -ax | grep ${query}`; break; + case 'linux' : cmd = `ps -A`; break; + default: break; + } + exec(cmd, (err, stdout, stderr) => { + cb(stdout.toLowerCase().indexOf(query.toLowerCase()) > -1); + }); +} + From 3ef3af88e123a0d4797727065cf5cc015d9828bb Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 10:58:38 +0200 Subject: [PATCH 03/47] added stopped information --- gui/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/main.js b/gui/main.js index e750b921..269c84eb 100644 --- a/gui/main.js +++ b/gui/main.js @@ -837,7 +837,7 @@ ipcMain.on('request-check-rigctld',(data)=>{ if (status){ Data["state"] = "running"; } else { - Data["state"] = "unknown"; + Data["state"] = "unknown/stopped"; } win.webContents.send('action-check-rigctld', Data); }) From 35a45ab6419441764fe4522cebfcecbf5f615023 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 11:00:05 +0200 Subject: [PATCH 04/47] removed stderr --- gui/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/main.js b/gui/main.js index 269c84eb..48a1b3b1 100644 --- a/gui/main.js +++ b/gui/main.js @@ -871,7 +871,7 @@ const isRunning = (query, cb) => { case 'linux' : cmd = `ps -A`; break; default: break; } - exec(cmd, (err, stdout, stderr) => { + exec(cmd, (err, stdout) => { cb(stdout.toLowerCase().indexOf(query.toLowerCase()) > -1); }); } From 7fbae90e81bf41db82bbba6a95ac92bd19150c0c Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 12:19:28 +0200 Subject: [PATCH 05/47] changed 500Hz to 563Hz mode --- gui/src/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/src/index.html b/gui/src/index.html index 8d52e57c..31c72198 100644 --- a/gui/src/index.html +++ b/gui/src/index.html @@ -1185,11 +1185,11 @@
- +
From 5acaed0e7e64dc33c5d212ad4323b4bee70940ea Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 12:41:36 +0200 Subject: [PATCH 06/47] fixed tnc state --- gui/preload-main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/preload-main.js b/gui/preload-main.js index c0c52235..58b475bb 100644 --- a/gui/preload-main.js +++ b/gui/preload-main.js @@ -1788,7 +1788,7 @@ ipcRenderer.on('action-update-daemon-connection', (event, arg) => { }); -ipcRenderer.on('action-update-tnc-connection', (arg) => { +ipcRenderer.on('action-update-tnc-connection', (event, arg) => { if (arg.tnc_connection == "open") { /* From 3d044189ac1c70ae2d06fed0201f20da7cb7cec6 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 19:24:50 +0200 Subject: [PATCH 07/47] move to session id instead of crc --- tnc/data_handler.py | 87 +++++++++++++++++++++++++++++++-------------- tnc/helpers.py | 17 +++++++++ 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index f43449ec..c56ff058 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -13,7 +13,7 @@ import threading import time import uuid import zlib -from random import randrange +from random import randrange, randbytes import codec2 import helpers @@ -46,6 +46,9 @@ class DATA: # length of signalling frame self.length_sig_frame = 14 + # hold session id + self.session_id = bytes(1) + # ------- ARQ SESSION self.arq_file_transfer = False self.IS_ARQ_SESSION_MASTER = False @@ -278,11 +281,17 @@ class DATA: # bytes_out[2:5] == transmission # we could also create an own function, which returns True. frametype = int.from_bytes(bytes(bytes_out[:1]), "big") + + # check for callsign CRC _valid1, _ = helpers.check_callsign(self.mycallsign, bytes(bytes_out[1:4])) _valid2, _ = helpers.check_callsign(self.mycallsign, bytes(bytes_out[2:5])) + + # check for session ID + _valid3 = helpers.check_session_id(self.session_id, bytes(bytes_out[1:2])) if ( _valid1 or _valid2 + or _valid3 or frametype in [ FR_TYPE.CQ.value, @@ -394,8 +403,9 @@ class DATA: """Build and send ACK frame for burst DATA frame""" ack_frame = bytearray(self.length_sig_frame) ack_frame[:1] = bytes([FR_TYPE.BURST_ACK.value]) - ack_frame[1:4] = static.DXCALLSIGN_CRC - ack_frame[4:7] = static.MYCALLSIGN_CRC + #ack_frame[1:4] = static.DXCALLSIGN_CRC + #ack_frame[4:7] = static.MYCALLSIGN_CRC + ack_frame[1:2] = self.session_id ack_frame[7:8] = bytes([int(snr)]) ack_frame[8:9] = bytes([int(self.speed_level)]) @@ -406,8 +416,9 @@ class DATA: """Build and send ACK frame for received DATA frame""" ack_frame = bytearray(self.length_sig_frame) ack_frame[:1] = bytes([FR_TYPE.FR_ACK.value]) - ack_frame[1:4] = static.DXCALLSIGN_CRC - ack_frame[4:7] = static.MYCALLSIGN_CRC + ack_frame[1:2] = self.session_id + #ack_frame[1:4] = static.DXCALLSIGN_CRC + #ack_frame[4:7] = static.MYCALLSIGN_CRC ack_frame[7:8] = bytes([int(snr)]) ack_frame[8:9] = bytes([int(self.speed_level)]) @@ -433,8 +444,9 @@ class DATA: # then create a repeat frame rpt_frame = bytearray(self.length_sig_frame) rpt_frame[:1] = bytes([FR_TYPE.FR_REPEAT.value]) - rpt_frame[1:4] = static.DXCALLSIGN_CRC - rpt_frame[4:7] = static.MYCALLSIGN_CRC + rpt_frame[1:2] = self.session_id + #rpt_frame[1:4] = static.DXCALLSIGN_CRC + #rpt_frame[4:7] = static.MYCALLSIGN_CRC rpt_frame[7:13] = missing_frames self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) @@ -445,8 +457,9 @@ class DATA: """Build and send NACK frame for received DATA frame""" nack_frame = bytearray(self.length_sig_frame) nack_frame[:1] = bytes([FR_TYPE.FR_NACK.value]) - nack_frame[1:4] = static.DXCALLSIGN_CRC - nack_frame[4:7] = static.MYCALLSIGN_CRC + nack_frame[1:2] = self.session_id + #nack_frame[1:4] = static.DXCALLSIGN_CRC + #nack_frame[4:7] = static.MYCALLSIGN_CRC nack_frame[7:8] = bytes([int(snr)]) nack_frame[8:9] = bytes([int(self.speed_level)]) @@ -457,8 +470,9 @@ class DATA: """Build and send NACK frame for watchdog timeout""" nack_frame = bytearray(self.length_sig_frame) nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value]) - nack_frame[1:4] = static.DXCALLSIGN_CRC - nack_frame[4:7] = static.MYCALLSIGN_CRC + nack_frame[1:2] = self.session_id + #nack_frame[1:4] = static.DXCALLSIGN_CRC + #nack_frame[4:7] = static.MYCALLSIGN_CRC nack_frame[7:8] = bytes([int(snr)]) nack_frame[8:9] = bytes([int(self.speed_level)]) @@ -469,8 +483,9 @@ class DATA: """Build and send a disconnect frame""" disconnection_frame = bytearray(self.length_sig_frame) disconnection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_CLOSE.value]) - disconnection_frame[1:4] = static.DXCALLSIGN_CRC - disconnection_frame[4:7] = static.MYCALLSIGN_CRC + disconnection_frame[1:2] = self.session_id + #disconnection_frame[1:4] = static.DXCALLSIGN_CRC + #disconnection_frame[4:7] = static.MYCALLSIGN_CRC disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=250) @@ -914,8 +929,9 @@ class DATA: # arqheader[:1] = bytes([FR_TYPE.BURST_01.value + i]) arqheader[:1] = bytes([FR_TYPE.BURST_01.value]) arqheader[1:2] = bytes([TX_N_FRAMES_PER_BURST]) - arqheader[2:5] = static.DXCALLSIGN_CRC - arqheader[5:8] = static.MYCALLSIGN_CRC + arqheader[2:3] = self.session_id + #arqheader[2:5] = static.DXCALLSIGN_CRC + #arqheader[5:8] = static.MYCALLSIGN_CRC bufferposition_end = bufferposition + payload_per_frame - len(arqheader) @@ -1272,10 +1288,14 @@ class DATA: self.IS_ARQ_SESSION_MASTER = True static.ARQ_SESSION_STATE = "connecting" + # create a random session id + self.session_id = randbytes(1) + connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_OPEN.value]) - connection_frame[1:4] = static.DXCALLSIGN_CRC - connection_frame[4:7] = static.MYCALLSIGN_CRC + connection_frame[1:2] = self.session_id + #connection_frame[1:4] = static.DXCALLSIGN_CRC + #connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) while not static.ARQ_SESSION: @@ -1431,8 +1451,10 @@ class DATA: connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_HB.value]) - connection_frame[1:4] = static.DXCALLSIGN_CRC - connection_frame[4:7] = static.MYCALLSIGN_CRC + connection_frame[1:2] = self.session_id + #connection_frame[1:4] = static.DXCALLSIGN_CRC + #connection_frame[4:7] = static.MYCALLSIGN_CRC + self.enqueue_frame_for_tx(connection_frame) @@ -1443,9 +1465,9 @@ class DATA: data_in:bytes: """ - # Accept session data if the DXCALLSIGN_CRC matches the station in static. - _valid_crc, _ = helpers.check_callsign(static.DXCALLSIGN, bytes(data_in[4:7])) - if _valid_crc: + # Accept session data if the DXCALLSIGN_CRC matches the station in static or session id. + _valid_session = helpers.check_session_id(self.session_id, bytes(data_in[1:2])) + if _valid_crc or _valid_session: self.log.debug("[TNC] Received session heartbeat") helpers.add_to_heard_stations( static.DXCALLSIGN, @@ -1537,6 +1559,10 @@ class DATA: """ self.is_IRS = False + # init a new random session id + self.session_id = randbytes(1) + print(session_id) + # Update data_channel timestamp self.data_channel_last_received = int(time.time()) @@ -1553,7 +1579,8 @@ class DATA: connection_frame[1:4] = static.DXCALLSIGN_CRC connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[7:13] = helpers.callsign_to_bytes(mycallsign) - connection_frame[13:14] = bytes([n_frames_per_burst]) + #connection_frame[13:14] = bytes([n_frames_per_burst]) + connection_frame[13:14] = self.session_id while not static.ARQ_STATE: time.sleep(0.01) @@ -1710,6 +1737,9 @@ class DATA: static.HAMLIB_FREQUENCY, ) + self.session_id = data_in[13:14] + print(self.session_id) + # check if callsign ssid override _, mycallsign = helpers.check_callsign(self.mycallsign, data_in[1:4]) @@ -1740,8 +1770,9 @@ class DATA: connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = frametype - connection_frame[1:4] = static.DXCALLSIGN_CRC - connection_frame[4:7] = static.MYCALLSIGN_CRC + connection_frame[1:2] = self.session_id + #connection_frame[1:4] = static.DXCALLSIGN_CRC + #connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[8:9] = bytes([self.speed_level]) # For checking protocol version on the receiving side @@ -1978,8 +2009,9 @@ class DATA: self.log.warning("[TNC] Stopping transmission!") stop_frame = bytearray(self.length_sig_frame) stop_frame[:1] = bytes([FR_TYPE.ARQ_STOP.value]) - stop_frame[1:4] = static.DXCALLSIGN_CRC - stop_frame[4:7] = static.MYCALLSIGN_CRC + #stop_frame[1:4] = static.DXCALLSIGN_CRC + #stop_frame[4:7] = static.MYCALLSIGN_CRC + stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) self.enqueue_frame_for_tx(stop_frame, copies=2, repeat_delay=250) @@ -2353,6 +2385,7 @@ class DATA: self.log.debug("[TNC] arq_cleanup") + self.session_id = bytes(1) self.rx_frame_bof_received = False self.rx_frame_eof_received = False self.burst_ack = False diff --git a/tnc/helpers.py b/tnc/helpers.py index c1e36626..6b2dac0e 100644 --- a/tnc/helpers.py +++ b/tnc/helpers.py @@ -316,6 +316,23 @@ def check_callsign(callsign: bytes, crc_to_check: bytes): return [False, ""] +def check_session_id(id: bytes, id_to_check: bytes): + """ + Funktion to check if we received the correct session id + + Args: + id: our own session id + id_to_check: The session id byte we want to check + + Returns: + True + False + """ + if id == id_to_check: + return True + else: + return False + def encode_grid(grid): """ From 5a8a563787988b6b3a203f647ca6a9f9d444590b Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 19:43:23 +0200 Subject: [PATCH 08/47] force usage of python 3.9 for ctest --- .github/workflows/ctest.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index da07df8d..01d342a0 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -13,11 +13,17 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set up Python 3.9 + uses: actions/setup-python@v4 + with: + python-version: 3.9 + + - name: Install packages shell: bash run: | sudo apt-get update - sudo apt-get install octave octave-common octave-signal sox python3 python3-pip portaudio19-dev python3-pyaudio + sudo apt-get install octave octave-common octave-signal sox portaudio19-dev python3-pyaudio pip3 install psutil crcengine ujson pyserial numpy structlog sounddevice pip3 install pytest pytest-rerunfailures From 7a682219cc85cb84da2b950f8f8eac998f073ed1 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 20:27:38 +0200 Subject: [PATCH 09/47] several pep improvements --- tnc/data_handler.py | 139 +++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 67 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index c56ff058..d9fe8db0 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -56,6 +56,9 @@ class DATA: self.arq_session_timeout = 30 self.session_connect_max_retries = 15 + # actual n retries of burst + self.tx_n_retry_of_burst = 0 + self.transmission_uuid = "" self.data_channel_last_received = 0.0 # time of last "live sign" of a frame @@ -75,6 +78,7 @@ class DATA: # 3 bytes for the EOF End of File indicator in a data frame self.data_frame_eof = b"EOF" + self.tx_n_max_retries_per_burst = 50 self.rx_n_max_retries_per_burst = 50 self.n_retries_per_burst = 0 @@ -131,6 +135,10 @@ class DATA: self.rx_frame_bof_received = False self.rx_frame_eof_received = False + # TIMEOUTS + self.burst_ack_timeout_seconds = 3.0 # timeout for burst acknowledges + self.data_frame_ack_timeout_seconds = 3.0 # timeout for data frame acknowledges + self.rpt_ack_timeout_seconds = 3.0 # timeout for rpt frame acknowledges self.transmission_timeout = 360 # transmission timeout in seconds # Dictionary of functions and log messages used in process_data @@ -294,16 +302,16 @@ class DATA: or _valid3 or frametype in [ - FR_TYPE.CQ.value, - FR_TYPE.QRV.value, - FR_TYPE.PING.value, - FR_TYPE.BEACON.value, - ] + FR_TYPE.CQ.value, + FR_TYPE.QRV.value, + FR_TYPE.PING.value, + FR_TYPE.BEACON.value, + ] ): # CHECK IF FRAMETYPE IS BETWEEN 10 and 50 ------------------------ - frame = frametype - 10 - n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big") + # frame = frametype - 10 + # n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big") # Dispatch activity based on received frametype if frametype in self.rx_dispatcher: @@ -403,8 +411,8 @@ class DATA: """Build and send ACK frame for burst DATA frame""" ack_frame = bytearray(self.length_sig_frame) ack_frame[:1] = bytes([FR_TYPE.BURST_ACK.value]) - #ack_frame[1:4] = static.DXCALLSIGN_CRC - #ack_frame[4:7] = static.MYCALLSIGN_CRC + # ack_frame[1:4] = static.DXCALLSIGN_CRC + # ack_frame[4:7] = static.MYCALLSIGN_CRC ack_frame[1:2] = self.session_id ack_frame[7:8] = bytes([int(snr)]) ack_frame[8:9] = bytes([int(self.speed_level)]) @@ -417,8 +425,8 @@ class DATA: ack_frame = bytearray(self.length_sig_frame) ack_frame[:1] = bytes([FR_TYPE.FR_ACK.value]) ack_frame[1:2] = self.session_id - #ack_frame[1:4] = static.DXCALLSIGN_CRC - #ack_frame[4:7] = static.MYCALLSIGN_CRC + # ack_frame[1:4] = static.DXCALLSIGN_CRC + # ack_frame[4:7] = static.MYCALLSIGN_CRC ack_frame[7:8] = bytes([int(snr)]) ack_frame[8:9] = bytes([int(self.speed_level)]) @@ -445,8 +453,8 @@ class DATA: rpt_frame = bytearray(self.length_sig_frame) rpt_frame[:1] = bytes([FR_TYPE.FR_REPEAT.value]) rpt_frame[1:2] = self.session_id - #rpt_frame[1:4] = static.DXCALLSIGN_CRC - #rpt_frame[4:7] = static.MYCALLSIGN_CRC + # rpt_frame[1:4] = static.DXCALLSIGN_CRC + # rpt_frame[4:7] = static.MYCALLSIGN_CRC rpt_frame[7:13] = missing_frames self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) @@ -458,8 +466,8 @@ class DATA: nack_frame = bytearray(self.length_sig_frame) nack_frame[:1] = bytes([FR_TYPE.FR_NACK.value]) nack_frame[1:2] = self.session_id - #nack_frame[1:4] = static.DXCALLSIGN_CRC - #nack_frame[4:7] = static.MYCALLSIGN_CRC + # nack_frame[1:4] = static.DXCALLSIGN_CRC + # nack_frame[4:7] = static.MYCALLSIGN_CRC nack_frame[7:8] = bytes([int(snr)]) nack_frame[8:9] = bytes([int(self.speed_level)]) @@ -471,8 +479,8 @@ class DATA: nack_frame = bytearray(self.length_sig_frame) nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value]) nack_frame[1:2] = self.session_id - #nack_frame[1:4] = static.DXCALLSIGN_CRC - #nack_frame[4:7] = static.MYCALLSIGN_CRC + # nack_frame[1:4] = static.DXCALLSIGN_CRC + # nack_frame[4:7] = static.MYCALLSIGN_CRC nack_frame[7:8] = bytes([int(snr)]) nack_frame[8:9] = bytes([int(self.speed_level)]) @@ -484,8 +492,8 @@ class DATA: disconnection_frame = bytearray(self.length_sig_frame) disconnection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_CLOSE.value]) disconnection_frame[1:2] = self.session_id - #disconnection_frame[1:4] = static.DXCALLSIGN_CRC - #disconnection_frame[4:7] = static.MYCALLSIGN_CRC + # disconnection_frame[1:4] = static.DXCALLSIGN_CRC + # disconnection_frame[4:7] = static.MYCALLSIGN_CRC disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=250) @@ -526,19 +534,19 @@ class DATA: # Extract some important data from the frame # Get sequence number of burst frame - RX_N_FRAME_OF_BURST = int.from_bytes(bytes(data_in[:1]), "big") - 10 + rx_n_frame_of_burst = int.from_bytes(bytes(data_in[:1]), "big") - 10 # Get number of bursts from received frame - RX_N_FRAMES_PER_BURST = int.from_bytes(bytes(data_in[1:2]), "big") + rx_n_frames_per_burst = int.from_bytes(bytes(data_in[1:2]), "big") # The RX burst buffer needs to have a fixed length filled with "None". # We need this later for counting the "Nones" to detect missing data. # Check if burst buffer has expected length else create it - if len(static.RX_BURST_BUFFER) != RX_N_FRAMES_PER_BURST: - static.RX_BURST_BUFFER = [None] * RX_N_FRAMES_PER_BURST + 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 # [frame_type][n_frames_per_burst][CRC24][CRC24] - static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = data_in[8:] # type: ignore + static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[8:] # type: ignore self.log.debug("[TNC] static.RX_BURST_BUFFER", buffer=static.RX_BURST_BUFFER) @@ -618,7 +626,6 @@ class DATA: ) static.ARQ_SPEED_LEVEL = self.speed_level - # Update modes we are listening to self.set_listening_modes(self.mode_list[self.speed_level]) @@ -634,7 +641,7 @@ class DATA: self.rx_start_of_transmission, len(static.RX_FRAME_BUFFER) ) - elif RX_N_FRAME_OF_BURST == RX_N_FRAMES_PER_BURST - 1: + elif rx_n_frame_of_burst == rx_n_frames_per_burst - 1: # We have "Nones" in our rx buffer, # Check if we received last frame of burst - this is an indicator for missed frames. # With this way of doing this, we always MUST receive the last @@ -642,8 +649,8 @@ class DATA: # TODO: See if a timeout on the send side with re-transmit last burst would help. self.log.debug( "[TNC] all frames in burst received:", - frame=RX_N_FRAME_OF_BURST, - frames=RX_N_FRAMES_PER_BURST, + frame=rx_n_frame_of_burst, + frames=rx_n_frames_per_burst, ) self.send_retransmit_request_frame(freedv) self.calculate_transfer_rate_rx( @@ -654,8 +661,8 @@ class DATA: else: self.log.error( "[TNC] data_handler: Should not reach this point...", - frame=RX_N_FRAME_OF_BURST, - frames=RX_N_FRAMES_PER_BURST, + 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. @@ -824,13 +831,6 @@ class DATA: self.tx_n_retry_of_burst = 0 # retries we already sent data # Maximum number of retries to send before declaring a frame is lost - TX_N_MAX_RETRIES_PER_BURST = 50 - TX_N_FRAMES_PER_BURST = n_frames_per_burst # amount of n frames per burst - - # TIMEOUTS - BURST_ACK_TIMEOUT_SECONDS = 3.0 # timeout for burst acknowledges - DATA_FRAME_ACK_TIMEOUT_SECONDS = 3.0 # timeout for data frame acknowledges - RPT_ACK_TIMEOUT_SECONDS = 3.0 # timeout for rpt frame acknowledges # save len of data_out to TOTAL_BYTES for our statistics --> kBytes # static.TOTAL_BYTES = round(len(data_out) / 1024, 2) @@ -882,9 +882,9 @@ class DATA: # Iterate through data_out buffer while not self.data_frame_ack_received and static.ARQ_STATE: - # we have TX_N_MAX_RETRIES_PER_BURST attempts for sending a burst - for self.tx_n_retry_of_burst in range(TX_N_MAX_RETRIES_PER_BURST): - data_mode = mode + # we have self.tx_n_max_retries_per_burst attempts for sending a burst + for self.tx_n_retry_of_burst in range(self.tx_n_max_retries_per_burst): + # data_mode = mode # self.log.debug("[TNC] FIXED MODE:", mode=FREEDV_MODE(data_mode).name) # we are doing a modulo check of transmission retries of the actual burst @@ -921,17 +921,17 @@ class DATA: # Tempbuffer list for storing our data frames tempbuffer = [] - # Append data frames with TX_N_FRAMES_PER_BURST to tempbuffer + # Append data frames with n_frames_per_burst to tempbuffer # TODO: this part needs a complete rewrite! - # TX_N_FRAMES_PER_BURST = 1 is working + # n_frames_per_burst = 1 is working arqheader = bytearray() # arqheader[:1] = bytes([FR_TYPE.BURST_01.value + i]) arqheader[:1] = bytes([FR_TYPE.BURST_01.value]) - arqheader[1:2] = bytes([TX_N_FRAMES_PER_BURST]) + arqheader[1:2] = bytes([n_frames_per_burst]) arqheader[2:3] = self.session_id - #arqheader[2:5] = static.DXCALLSIGN_CRC - #arqheader[5:8] = static.MYCALLSIGN_CRC + # arqheader[2:5] = static.DXCALLSIGN_CRC + # arqheader[5:8] = static.MYCALLSIGN_CRC bufferposition_end = bufferposition + payload_per_frame - len(arqheader) @@ -955,7 +955,7 @@ class DATA: self.log.info( "[TNC] ARQ | TX | FRAMES", mode=FREEDV_MODE(data_mode).name, - fpb=TX_N_FRAMES_PER_BURST, + fpb=n_frames_per_burst, retry=self.tx_n_retry_of_burst, ) @@ -963,13 +963,13 @@ class DATA: self.enqueue_frame_for_tx(t_buf_item, c2_mode=data_mode) # After transmission finished, wait for an ACK or RPT frame - # burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS + 100 + # burstacktimeout = time.time() + self.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) - # burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS + 100 + # burstacktimeout = time.time() + self.burst_ack_timeout_seconds + 100 while static.ARQ_STATE and not ( self.burst_ack or self.burst_nack @@ -1016,7 +1016,7 @@ class DATA: self.log.debug( "[TNC] ATTEMPT:", retry=self.tx_n_retry_of_burst, - maxretries=TX_N_MAX_RETRIES_PER_BURST, + maxretries=self.tx_n_max_retries_per_burst, overflows=static.BUFFER_OVERFLOW_COUNTER, ) # End of FOR loop @@ -1294,8 +1294,8 @@ class DATA: connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_OPEN.value]) connection_frame[1:2] = self.session_id - #connection_frame[1:4] = static.DXCALLSIGN_CRC - #connection_frame[4:7] = static.MYCALLSIGN_CRC + # connection_frame[1:4] = static.DXCALLSIGN_CRC + # connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) while not static.ARQ_SESSION: @@ -1414,7 +1414,8 @@ class DATA: # is intended for this station. # Close the session if the CRC matches the remote station in static. _valid_crc, _ = helpers.check_callsign(static.DXCALLSIGN, bytes(data_in[4:7])) - if _valid_crc: + _valid_session = helpers.check_session_id(self.session_id, bytes(data_in[1:2])) + if _valid_crc or _valid_session: static.ARQ_SESSION_STATE = "disconnected" helpers.add_to_heard_stations( static.DXCALLSIGN, @@ -1452,9 +1453,8 @@ class DATA: connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_HB.value]) connection_frame[1:2] = self.session_id - #connection_frame[1:4] = static.DXCALLSIGN_CRC - #connection_frame[4:7] = static.MYCALLSIGN_CRC - + # connection_frame[1:4] = static.DXCALLSIGN_CRC + # connection_frame[4:7] = static.MYCALLSIGN_CRC self.enqueue_frame_for_tx(connection_frame) @@ -1466,6 +1466,7 @@ class DATA: """ # Accept session data if the DXCALLSIGN_CRC matches the station in static or session id. + _valid_crc, _ = helpers.check_callsign(static.DXCALLSIGN, bytes(data_in[4:7])) _valid_session = helpers.check_session_id(self.session_id, bytes(data_in[1:2])) if _valid_crc or _valid_session: self.log.debug("[TNC] Received session heartbeat") @@ -1507,6 +1508,8 @@ class DATA: data_out:bytes: mode:int: n_frames_per_burst:int: + transmission_uuid:str: + mycallsign:bytes: Returns: True if the data session was opened and the data was sent @@ -1552,6 +1555,7 @@ class DATA: Args: mode:int: n_frames_per_burst:int: + mycallsign:bytes: Returns: True if the data channel was opened successfully @@ -1559,9 +1563,10 @@ class DATA: """ self.is_IRS = False - # init a new random session id - self.session_id = randbytes(1) - print(session_id) + # init a new random session id if we are not in an arq session + if not static.ARQ_SESSION: + self.session_id = randbytes(1) + print(self.session_id) # Update data_channel timestamp self.data_channel_last_received = int(time.time()) @@ -1579,7 +1584,7 @@ class DATA: connection_frame[1:4] = static.DXCALLSIGN_CRC connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[7:13] = helpers.callsign_to_bytes(mycallsign) - #connection_frame[13:14] = bytes([n_frames_per_burst]) + # connection_frame[13:14] = bytes([n_frames_per_burst]) connection_frame[13:14] = self.session_id while not static.ARQ_STATE: @@ -1771,8 +1776,8 @@ class DATA: connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = frametype connection_frame[1:2] = self.session_id - #connection_frame[1:4] = static.DXCALLSIGN_CRC - #connection_frame[4:7] = static.MYCALLSIGN_CRC + # connection_frame[1:4] = static.DXCALLSIGN_CRC + # connection_frame[4:7] = static.MYCALLSIGN_CRC connection_frame[8:9] = bytes([self.speed_level]) # For checking protocol version on the receiving side @@ -2009,8 +2014,8 @@ class DATA: self.log.warning("[TNC] Stopping transmission!") stop_frame = bytearray(self.length_sig_frame) stop_frame[:1] = bytes([FR_TYPE.ARQ_STOP.value]) - #stop_frame[1:4] = static.DXCALLSIGN_CRC - #stop_frame[4:7] = static.MYCALLSIGN_CRC + # stop_frame[1:4] = static.DXCALLSIGN_CRC + # stop_frame[4:7] = static.MYCALLSIGN_CRC stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) @@ -2141,7 +2146,7 @@ class DATA: """ Transmit a CQ Args: - Nothing + self Returns: Nothing @@ -2290,7 +2295,7 @@ class DATA: ( receivedbytes * static.ARQ_COMPRESSION_FACTOR - / (static.TOTAL_BYTES) + / static.TOTAL_BYTES ) * 100 ), @@ -2302,7 +2307,7 @@ class DATA: if receivedbytes > 0: static.ARQ_BITS_PER_SECOND = int((receivedbytes * 8) / transmissiontime) static.ARQ_BYTES_PER_MINUTE = int( - (receivedbytes) / (transmissiontime / 60) + receivedbytes / (transmissiontime / 60) ) else: @@ -2356,7 +2361,7 @@ class DATA: if sentbytes > 0: static.ARQ_BITS_PER_SECOND = int((sentbytes * 8) / transmissiontime) - static.ARQ_BYTES_PER_MINUTE = int((sentbytes) / (transmissiontime / 60)) + static.ARQ_BYTES_PER_MINUTE = int(sentbytes / (transmissiontime / 60)) else: static.ARQ_BITS_PER_SECOND = 0 From 0ab0f444a2c5d74adebb04920cfea82b91c2019a Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 20:28:47 +0200 Subject: [PATCH 10/47] simplified session id check --- tnc/helpers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tnc/helpers.py b/tnc/helpers.py index 6b2dac0e..66e6eabb 100644 --- a/tnc/helpers.py +++ b/tnc/helpers.py @@ -328,10 +328,7 @@ def check_session_id(id: bytes, id_to_check: bytes): True False """ - if id == id_to_check: - return True - else: - return False + return id == id_to_check def encode_grid(grid): From 2ed79df2be9c1173f34fff9802556346ec9b1f76 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 22:42:48 +0200 Subject: [PATCH 11/47] improved codec2 mode init --- tnc/modem.py | 206 +++++++++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 97 deletions(-) diff --git a/tnc/modem.py b/tnc/modem.py index 1c394daa..865db473 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -81,110 +81,52 @@ class RF: self.fft_data = bytes() # Open codec2 instances - # Datac0 - control frames - self.datac0_freedv = ctypes.cast( - codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p - ) - self.c_lib.freedv_set_tuning_range( - self.datac0_freedv, - ctypes.c_float(static.TUNING_RANGE_FMIN), - ctypes.c_float(static.TUNING_RANGE_FMAX), - ) - self.datac0_bytes_per_frame = int( - codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv) / 8 - ) - self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame) - codec2.api.freedv_set_frames_per_burst(self.datac0_freedv, 1) - self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX) - # Additional Datac0-specific information - these are not referenced anywhere else. - # 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) - # ) + # DATAC0 + self.datac0_freedv, \ + self.datac0_bytes_per_frame, \ + self.datac0_bytes_out, \ + self.datac0_buffer, \ + self.datac0_nin = \ + self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC0, None) - # Datac1 - higher-bandwidth data frames - self.datac1_freedv = ctypes.cast( - codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p - ) - self.c_lib.freedv_set_tuning_range( - self.datac1_freedv, - ctypes.c_float(static.TUNING_RANGE_FMIN), - ctypes.c_float(static.TUNING_RANGE_FMAX), - ) - self.datac1_bytes_per_frame = int( - codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8 - ) - self.datac1_bytes_out = ctypes.create_string_buffer(self.datac1_bytes_per_frame) - codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, 1) - self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX) + # DATAC1 + self.datac1_freedv, \ + self.datac1_bytes_per_frame, \ + self.datac1_bytes_out, \ + self.datac1_buffer, \ + self.datac1_nin = \ + self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC1, None) - # Datac3 - lower-bandwidth data frames - self.datac3_freedv = ctypes.cast( - codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p - ) - self.c_lib.freedv_set_tuning_range( - self.datac3_freedv, - ctypes.c_float(static.TUNING_RANGE_FMIN), - ctypes.c_float(static.TUNING_RANGE_FMAX), - ) - self.datac3_bytes_per_frame = int( - codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8 - ) - self.datac3_bytes_out = ctypes.create_string_buffer(self.datac3_bytes_per_frame) - codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, 1) - self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX) + # DATAC3 + self.datac3_freedv, \ + self.datac3_bytes_per_frame, \ + self.datac3_bytes_out, \ + self.datac3_buffer, \ + self.datac3_nin = \ + self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC3, None) - # FSK Long-distance Parity Code 0 - data frames - self.fsk_ldpc_freedv_0 = ctypes.cast( - codec2.api.freedv_open_advanced( + # FSK LDPC - 0 + self.fsk_ldpc_freedv_0, \ + self.fsk_ldpc_bytes_per_frame_0, \ + self.fsk_ldpc_bytes_out_0, \ + self.fsk_ldpc_buffer_0, \ + self.fsk_ldpc_nin_0 = \ + self.init_codec2_mode( codec2.api.FREEDV_MODE_FSK_LDPC, - ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV), - ), - ctypes.c_void_p, - ) - self.fsk_ldpc_bytes_per_frame_0 = int( - codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_0) / 8 - ) - self.fsk_ldpc_bytes_out_0 = ctypes.create_string_buffer( - self.fsk_ldpc_bytes_per_frame_0 - ) - # codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1) - self.fsk_ldpc_buffer_0 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) + codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV + ) - # FSK Long-distance Parity Code 1 - data frames - self.fsk_ldpc_freedv_1 = ctypes.cast( - codec2.api.freedv_open_advanced( + # FSK LDPC - 1 + self.fsk_ldpc_freedv_1, \ + self.fsk_ldpc_bytes_per_frame_1, \ + self.fsk_ldpc_bytes_out_1, \ + self.fsk_ldpc_buffer_1, \ + self.fsk_ldpc_nin_1 = \ + self.init_codec2_mode( codec2.api.FREEDV_MODE_FSK_LDPC, - ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV), - ), - ctypes.c_void_p, - ) - self.fsk_ldpc_bytes_per_frame_1 = int( - codec2.api.freedv_get_bits_per_modem_frame(self.fsk_ldpc_freedv_1) / 8 - ) - self.fsk_ldpc_bytes_out_1 = ctypes.create_string_buffer( - self.fsk_ldpc_bytes_per_frame_1 - ) - # codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, 1) - self.fsk_ldpc_buffer_1 = codec2.audio_buffer(self.AUDIO_FRAMES_PER_BUFFER_RX) - - # initial nin values - 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.fsk_ldpc_nin_0 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_0) - self.fsk_ldpc_nin_1 = codec2.api.freedv_nin(self.fsk_ldpc_freedv_1) - # self.log.debug("[MDM] RF: ",datac0_nin=self.datac0_nin) + codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV + ) # --------------------------------------------CREATE PYAUDIO INSTANCE if not TESTMODE: @@ -622,6 +564,76 @@ class RF: self.calculate_snr(freedv) return nin + def init_codec2_mode(self, mode, adv): + """ + Init codec2 and return some important parameters + + Args: + self: + mode: + adv: + + Returns: + c2instance, bytes_per_frame, bytes_out, audio_buffer, nin + """ + if adv: + # FSK Long-distance Parity Code 1 - data frames + c2instance = ctypes.cast( + codec2.api.freedv_open_advanced( + codec2.api.FREEDV_MODE_FSK_LDPC, + ctypes.byref(adv), + ), + ctypes.c_void_p, + ) + else: + + # create codec2 instance + c2instance = ctypes.cast( + codec2.api.freedv_open(mode), ctypes.c_void_p + ) + + # set tuning range + self.c_lib.freedv_set_tuning_range( + c2instance, + ctypes.c_float(static.TUNING_RANGE_FMIN), + ctypes.c_float(static.TUNING_RANGE_FMAX), + ) + + # get bytes per frame + bytes_per_frame = int( + codec2.api.freedv_get_bits_per_modem_frame(c2instance) / 8 + ) + + # create byte out buffer + bytes_out = ctypes.create_string_buffer(bytes_per_frame) + + # set initial frames per burst + codec2.api.freedv_set_frames_per_burst(c2instance, 1) + + # init audio buffer + audio_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER_RX) + + # get initial nin + nin = codec2.api.freedv_nin(c2instance) + + # Additional Datac0-specific information - these are not referenced anywhere else. + # 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) + # ) + + # return values + return c2instance, bytes_per_frame, bytes_out, audio_buffer, nin + def audio_datac0(self) -> None: """Receive data encoded with datac0""" self.datac0_nin = self.demodulate_audio( From 56ee05186cb6297c3ca888bdd2c50f207cae9eb8 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 23:02:45 +0200 Subject: [PATCH 12/47] improved codec2 mode init --- tnc/modem.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tnc/modem.py b/tnc/modem.py index 865db473..53105ba7 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -184,6 +184,7 @@ class RF: # --------------------------------------------INIT AND OPEN HAMLIB # Check how we want to control the radio + # TODO: deprecated feature - we can remove this possibly if static.HAMLIB_RADIOCONTROL == "direct": import rig elif static.HAMLIB_RADIOCONTROL == "rigctl": From 54285c1c69b735d8147f1edb22066a50eb82fa14 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 16:01:58 +0200 Subject: [PATCH 13/47] another attempt fixing audio problems --- tnc/audio.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tnc/audio.py b/tnc/audio.py index 07269087..9c97e09e 100644 --- a/tnc/audio.py +++ b/tnc/audio.py @@ -12,6 +12,9 @@ atexit.register(sd._terminate) log = structlog.get_logger("audio") +# crc algorithm for unique audio device names +crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc16 library + def get_audio_devices(): """ @@ -28,7 +31,7 @@ def get_audio_devices(): sd._terminate() sd._initialize() - log.error("[AUD] get_audio_devices") + log.debug("[AUD] get_audio_devices") with multiprocessing.Manager() as manager: proxy_input_devices = manager.list() proxy_output_devices = manager.list() @@ -39,13 +42,13 @@ def get_audio_devices(): proc.start() proc.join() - log.error(f"[AUD] get_audio_devices: input_devices: {proxy_input_devices}") - log.error(f"[AUD] get_audio_devices: output_devices: {proxy_output_devices}") + log.debug("[AUD] get_audio_devices: input_devices:", list=f"{proxy_input_devices}") + log.debug("[AUD] get_audio_devices: output_devices:", list=f"{proxy_output_devices}") return list(proxy_input_devices), list(proxy_output_devices) def device_crc(device) -> str: - crc_algorithm = crcengine.new("crc16-ccitt-false") # load crc8 library + crc_hwid = crc_algorithm(bytes(f"{device}", encoding="utf-8")) crc_hwid = crc_hwid.to_bytes(2, byteorder="big") crc_hwid = crc_hwid.hex() @@ -65,11 +68,7 @@ def fetch_audio_devices(input_devices, output_devices): """ devices = sd.query_devices(device=None, kind=None) - # The use of set forces the list to contain only unique entries. - input_devs = set() - output_devs = set() - - for device in devices: + for index, device in enumerate(devices): # Use a try/except block because Windows doesn't have an audio device range try: name = device["name"] @@ -86,11 +85,13 @@ def fetch_audio_devices(input_devices, output_devices): name = "" if max_input_channels > 0: - input_devs.add(device_crc(device)) - if max_output_channels > 0: - output_devs.add(device_crc(device)) + new_input_device = {"id": index, "name": device_crc(device)} + # check if device not in device list + if new_input_device not in input_devices: + input_devices.append(new_input_device) - for index, item in enumerate(input_devs): - input_devices.append({"id": index, "name": item}) - for index, item in enumerate(output_devs): - output_devices.append({"id": index, "name": item}) + if max_output_channels > 0: + new_output_device = {"id": index, "name": device_crc(device)} + # check if device not in device list + if new_output_device not in output_devices: + output_devices.append(new_output_device) From 775bcc001553ec74b707881f12ff63307bbe00d4 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 5 Oct 2022 16:05:00 +0200 Subject: [PATCH 14/47] removed unused variable --- tnc/audio.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tnc/audio.py b/tnc/audio.py index 9c97e09e..41190bb6 100644 --- a/tnc/audio.py +++ b/tnc/audio.py @@ -82,7 +82,6 @@ def fetch_audio_devices(input_devices, output_devices): print(err) max_input_channels = 0 max_output_channels = 0 - name = "" if max_input_channels > 0: new_input_device = {"id": index, "name": device_crc(device)} From 1db840e1f424715d9edc271da962431c3c8b9944 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Thu, 6 Oct 2022 11:21:36 +0200 Subject: [PATCH 15/47] attempt to fix rx data --- tnc/data_handler.py | 10 +++++++++- tnc/helpers.py | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index d9fe8db0..1c889199 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -295,11 +295,15 @@ class DATA: _valid2, _ = helpers.check_callsign(self.mycallsign, bytes(bytes_out[2:5])) # check for session ID + # signalling frames _valid3 = helpers.check_session_id(self.session_id, bytes(bytes_out[1:2])) + # arq data frames + _valid4 = helpers.check_session_id(self.session_id, bytes(bytes_out[2:3])) if ( _valid1 or _valid2 or _valid3 + or _valid4 or frametype in [ FR_TYPE.CQ.value, @@ -546,7 +550,8 @@ class DATA: # Append data to rx burst buffer # [frame_type][n_frames_per_burst][CRC24][CRC24] - static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[8:] # type: ignore + #static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[8:] # type: ignore + static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[3:] # type: ignore self.log.debug("[TNC] static.RX_BURST_BUFFER", buffer=static.RX_BURST_BUFFER) @@ -777,6 +782,8 @@ class DATA: snr=snr, crc=data_frame_crc.hex(), ) + + print("kommen wir hier an?") self.send_data_ack_frame(snr) # Update statistics AFTER the frame ACK is sent self.calculate_transfer_rate_rx( @@ -1290,6 +1297,7 @@ class DATA: # create a random session id self.session_id = randbytes(1) + print(self.session_id) connection_frame = bytearray(self.length_sig_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_OPEN.value]) diff --git a/tnc/helpers.py b/tnc/helpers.py index 66e6eabb..0154cf43 100644 --- a/tnc/helpers.py +++ b/tnc/helpers.py @@ -328,6 +328,7 @@ def check_session_id(id: bytes, id_to_check: bytes): True False """ + log.debug("[HLP] check_sessionid: Checking:", ownid=id, check=id_to_check) return id == id_to_check From 47f6e54b6d91b9d8796d73d9f0363529e0ca8549 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Thu, 6 Oct 2022 11:35:12 +0200 Subject: [PATCH 16/47] first working arq transmission with session id --- tnc/data_handler.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 1c889199..c3f17534 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -435,7 +435,7 @@ class DATA: ack_frame[8:9] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx(ack_frame, copies=3, repeat_delay=100) + self.enqueue_frame_for_tx(ack_frame, copies=3, repeat_delay=0) def send_retransmit_request_frame(self, freedv) -> None: # check where a None is in our burst buffer and do frame+1, beacuse lists start at 0 @@ -500,7 +500,7 @@ class DATA: # disconnection_frame[4:7] = static.MYCALLSIGN_CRC disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=250) + self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=0) def arq_data_received( self, data_in: bytes, bytes_per_frame: int, snr: float, freedv @@ -518,11 +518,14 @@ class DATA: # is intended for this station. data_in = bytes(data_in) + # TODO: this seems not to work anymore # get received crc for different mycall ssids # check if callsign ssid override - _, mycallsign = helpers.check_callsign( - self.mycallsign, data_in[2:5] - ) + #_, mycallsign = helpers.check_callsign( + # self.mycallsign, data_in[2:5] + #) + # attempt fixing this + mycallsign = self.mycallsign # only process data if we are in ARQ and BUSY state else return to quit if not static.ARQ_STATE and static.TNC_STATE != "BUSY": @@ -783,7 +786,6 @@ class DATA: crc=data_frame_crc.hex(), ) - print("kommen wir hier an?") self.send_data_ack_frame(snr) # Update statistics AFTER the frame ACK is sent self.calculate_transfer_rate_rx( From d865edcfe7456558261721bb7482dcc2b5f36355 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Thu, 6 Oct 2022 11:36:14 +0200 Subject: [PATCH 17/47] removed delay between repeated frames --- tnc/data_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index c3f17534..28fd5aaa 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -2029,7 +2029,7 @@ class DATA: stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(stop_frame, copies=2, repeat_delay=250) + self.enqueue_frame_for_tx(stop_frame, copies=2, repeat_delay=0) static.TNC_STATE = "IDLE" static.ARQ_STATE = False From d365255a952db38e6596799ef953c1b0e7769425 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Thu, 6 Oct 2022 11:47:19 +0200 Subject: [PATCH 18/47] arq cleanup after sending close frames --- tnc/data_handler.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 28fd5aaa..e42b3ec6 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1407,9 +1407,13 @@ class DATA: self.IS_ARQ_SESSION_MASTER = False static.ARQ_SESSION = False + + # we need to send disconnect frame before doing arq cleanup + # we would loose our session id then + self.send_disconnect_frame() self.arq_cleanup() - self.send_disconnect_frame() + def received_session_close(self, data_in: bytes): """ @@ -1649,11 +1653,13 @@ class DATA: + "]" ) self.datachannel_timeout = True - self.arq_cleanup() + # Attempt to cleanup the far-side, if it received the # open_session frame and can still hear us. self.close_session() + + self.arq_cleanup() return False # Shouldn't get here.. From dad9230f3d43d7173d06a9642f9b8c1550c6d5fc Mon Sep 17 00:00:00 2001 From: dj2ls Date: Thu, 6 Oct 2022 11:57:54 +0200 Subject: [PATCH 19/47] dirty fix of stopping transmission --- tnc/data_handler.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index e42b3ec6..18b66378 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -2030,12 +2030,12 @@ class DATA: self.log.warning("[TNC] Stopping transmission!") stop_frame = bytearray(self.length_sig_frame) stop_frame[:1] = bytes([FR_TYPE.ARQ_STOP.value]) - # stop_frame[1:4] = static.DXCALLSIGN_CRC - # stop_frame[4:7] = static.MYCALLSIGN_CRC - stop_frame[1:2] = self.session_id + stop_frame[1:4] = static.DXCALLSIGN_CRC + stop_frame[4:7] = static.MYCALLSIGN_CRC + # TODO: Not sure if we really need the session id when disconnecting + # stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - - self.enqueue_frame_for_tx(stop_frame, copies=2, repeat_delay=0) + self.enqueue_frame_for_tx(stop_frame, copies=6, repeat_delay=0) static.TNC_STATE = "IDLE" static.ARQ_STATE = False From 101903b92460fd79d0894f3f584d88437bc0ffcd Mon Sep 17 00:00:00 2001 From: Paul Kronenwetter Date: Fri, 7 Oct 2022 15:44:10 +0000 Subject: [PATCH 20/47] Add pyaudio to pip install Use pip to install pyaudio, in addition to the debian package, as a test. --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 01d342a0..8be768ed 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -24,7 +24,7 @@ jobs: run: | sudo apt-get update sudo apt-get install octave octave-common octave-signal sox portaudio19-dev python3-pyaudio - pip3 install psutil crcengine ujson pyserial numpy structlog sounddevice + pip3 install psutil crcengine ujson pyserial numpy structlog sounddevice pyaudio pip3 install pytest pytest-rerunfailures - name: Build codec2 From b0e3d2286ee4527a174f32dcbcc2dc3528cf7732 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Mon, 10 Oct 2022 09:00:45 +0200 Subject: [PATCH 21/47] enable sig modes only when needed --- tnc/data_handler.py | 48 ++++++++----- tnc/modem.py | 161 ++++++++++++++++++++++++++------------------ 2 files changed, 126 insertions(+), 83 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 18b66378..6b52c6e7 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -418,8 +418,8 @@ class DATA: # ack_frame[1:4] = static.DXCALLSIGN_CRC # ack_frame[4:7] = static.MYCALLSIGN_CRC ack_frame[1:2] = self.session_id - ack_frame[7:8] = bytes([int(snr)]) - ack_frame[8:9] = bytes([int(self.speed_level)]) + ack_frame[2:3] = bytes([int(snr)]) + ack_frame[3:4] = bytes([int(self.speed_level)]) # Transmit frame self.enqueue_frame_for_tx(ack_frame) @@ -431,8 +431,8 @@ class DATA: ack_frame[1:2] = self.session_id # ack_frame[1:4] = static.DXCALLSIGN_CRC # ack_frame[4:7] = static.MYCALLSIGN_CRC - ack_frame[7:8] = bytes([int(snr)]) - ack_frame[8:9] = bytes([int(self.speed_level)]) + # ack_frame[7:8] = bytes([int(snr)]) + # ack_frame[8:9] = bytes([int(self.speed_level)]) # Transmit frame self.enqueue_frame_for_tx(ack_frame, copies=3, repeat_delay=0) @@ -452,14 +452,14 @@ class DATA: codec2.api.freedv_set_frames_per_burst(freedv, len(missing_frames)) # TODO: Trim `missing_frames` bytesarray to [7:13] (6) frames, if it's larger. - + # TODO: Instead of using int we could use a binary flag # then create a repeat frame rpt_frame = bytearray(self.length_sig_frame) rpt_frame[:1] = bytes([FR_TYPE.FR_REPEAT.value]) rpt_frame[1:2] = self.session_id # rpt_frame[1:4] = static.DXCALLSIGN_CRC # rpt_frame[4:7] = static.MYCALLSIGN_CRC - rpt_frame[7:13] = missing_frames + # rpt_frame[7:13] = missing_frames self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) # Transmit frame @@ -472,8 +472,8 @@ class DATA: nack_frame[1:2] = self.session_id # nack_frame[1:4] = static.DXCALLSIGN_CRC # nack_frame[4:7] = static.MYCALLSIGN_CRC - nack_frame[7:8] = bytes([int(snr)]) - nack_frame[8:9] = bytes([int(self.speed_level)]) + nack_frame[2:3] = bytes([int(snr)]) + nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST self.enqueue_frame_for_tx(nack_frame) @@ -485,8 +485,8 @@ class DATA: nack_frame[1:2] = self.session_id # nack_frame[1:4] = static.DXCALLSIGN_CRC # nack_frame[4:7] = static.MYCALLSIGN_CRC - nack_frame[7:8] = bytes([int(snr)]) - nack_frame[8:9] = bytes([int(self.speed_level)]) + nack_frame[2:3] = bytes([int(snr)]) + nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST self.enqueue_frame_for_tx(nack_frame) @@ -498,7 +498,7 @@ class DATA: disconnection_frame[1:2] = self.session_id # disconnection_frame[1:4] = static.DXCALLSIGN_CRC # disconnection_frame[4:7] = static.MYCALLSIGN_CRC - disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) + # TODO: Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=0) @@ -553,7 +553,7 @@ class DATA: # Append data to rx burst buffer # [frame_type][n_frames_per_burst][CRC24][CRC24] - #static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[8:] # type: ignore + # static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[8:] # type: ignore static.RX_BURST_BUFFER[rx_n_frame_of_burst] = data_in[3:] # type: ignore self.log.debug("[TNC] static.RX_BURST_BUFFER", buffer=static.RX_BURST_BUFFER) @@ -635,7 +635,7 @@ class DATA: static.ARQ_SPEED_LEVEL = self.speed_level # Update modes we are listening to - self.set_listening_modes(self.mode_list[self.speed_level]) + self.set_listening_modes(False, True, self.mode_list[self.speed_level]) # Create and send ACK frame self.log.info("[TNC] ARQ | RX | SENDING ACK") @@ -838,6 +838,11 @@ class DATA: """ self.arq_file_transfer = True + # set signalling modes we want to listen to + # we are in an ongoing arq transmission, so we don't need sig0 actually + modem.RECEIVE_SIG0 = False + modem.RECEIVE_SIG1 = True + self.tx_n_retry_of_burst = 0 # retries we already sent data # Maximum number of retries to send before declaring a frame is lost @@ -1143,8 +1148,8 @@ class DATA: # Update data_channel timestamp self.data_channel_last_received = int(time.time()) - self.burst_ack_snr = int.from_bytes(bytes(data_in[7:8]), "big") - self.speed_level = int.from_bytes(bytes(data_in[8:9]), "big") + self.burst_ack_snr = int.from_bytes(bytes(data_in[2:3]), "big") + self.speed_level = int.from_bytes(bytes(data_in[3:4]), "big") static.ARQ_SPEED_LEVEL = self.speed_level self.log.debug( @@ -1747,7 +1752,7 @@ class DATA: ) # Update modes we are listening to - self.set_listening_modes(self.mode_list[self.speed_level]) + self.set_listening_modes(True, True, self.mode_list[self.speed_level]) helpers.add_to_heard_stations( static.DXCALLSIGN, @@ -2417,6 +2422,8 @@ class DATA: self.burst_ack_snr = 255 # reset modem receiving state to reduce cpu load + modem.RECEIVE_SIG0 = True + modem.RECEIVE_SIG1 = False modem.RECEIVE_DATAC1 = False modem.RECEIVE_DATAC3 = False # modem.RECEIVE_FSK_LDPC_0 = False @@ -2457,15 +2464,20 @@ class DATA: self.rpt_request_received = state self.data_frame_ack_received = state - def set_listening_modes(self, mode: int) -> None: + def set_listening_modes(self, enable_sig0: bool, enable_sig1: bool, mode: int) -> None: """ Function for setting the data modes we are listening to for saving cpu power Args: + enable_sig0:int: Enable/Disable signalling mode 0 + enable_sig1:int: Enable/Disable signalling mode 1 mode:int: Codec2 mode to listen for """ # set modes we want to listen to + modem.RECEIVE_SIG0 = enable_sig0 + modem.RECEIVE_SIG1 = enable_sig1 + if mode == FREEDV_MODE.datac1.value: modem.RECEIVE_DATAC1 = True self.log.debug("[TNC] Changing listening data mode", mode="datac1") @@ -2530,7 +2542,7 @@ class DATA: static.ARQ_SPEED_LEVEL = self.speed_level # Update modes we are listening to - self.set_listening_modes(self.mode_list[self.speed_level]) + self.set_listening_modes(True, True, self.mode_list[self.speed_level]) # Why not pass `snr` or `static.SNR`? self.send_burst_nack_frame_watchdog(0) diff --git a/tnc/modem.py b/tnc/modem.py index 53105ba7..34656e92 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -32,6 +32,8 @@ TXCHANNEL = "" static.TRANSMITTING = False # Receive only specific modes to reduce CPU load +RECEIVE_SIG0 = False +RECEIVE_SIG1 = False RECEIVE_DATAC1 = False RECEIVE_DATAC3 = False RECEIVE_FSK_LDPC_1 = False @@ -83,27 +85,38 @@ class RF: # Open codec2 instances # DATAC0 - self.datac0_freedv, \ - self.datac0_bytes_per_frame, \ - self.datac0_bytes_out, \ - self.datac0_buffer, \ - self.datac0_nin = \ + # SIGNALLING MODE 0 - Used for Connecting - Payload 14 Bytes + self.sig0_datac0_freedv, \ + self.sig0_datac0_bytes_per_frame, \ + self.sig0_datac0_bytes_out, \ + self.sig0_datac0_buffer, \ + self.sig0_datac0_nin = \ self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC0, None) + # DATAC0 + # SIGNALLING MODE 1 - Used for ACK/NACK - Payload 5 Bytes + self.sig1_datac0_freedv, \ + self.sig1_datac0_bytes_per_frame, \ + self.sig1_datac0_bytes_out, \ + self.sig1_datac0_buffer, \ + self.sig1_datac0_nin = \ + self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC0, None) + + # DATAC1 - self.datac1_freedv, \ - self.datac1_bytes_per_frame, \ - self.datac1_bytes_out, \ - self.datac1_buffer, \ - self.datac1_nin = \ + self.dat0_datac1_freedv, \ + self.dat0_datac1_bytes_per_frame, \ + self.dat0_datac1_bytes_out, \ + self.dat0_datac1_buffer, \ + self.dat0_datac1_nin = \ self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC1, None) # DATAC3 - self.datac3_freedv, \ - self.datac3_bytes_per_frame, \ - self.datac3_bytes_out, \ - self.datac3_buffer, \ - self.datac3_nin = \ + self.dat0_datac3_freedv, \ + self.dat0_datac3_bytes_per_frame, \ + self.dat0_datac3_bytes_out, \ + self.dat0_datac3_buffer, \ + self.dat0_datac3_nin = \ self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC3, None) # FSK LDPC - 0 @@ -215,20 +228,25 @@ class RF: ) fft_thread.start() - audio_thread_datac0 = threading.Thread( - target=self.audio_datac0, name="AUDIO_THREAD DATAC0", daemon=True + audio_thread_sig0_datac0 = threading.Thread( + target=self.audio_sig0_datac0, name="AUDIO_THREAD DATAC0 - 0", daemon=True ) - audio_thread_datac0.start() + audio_thread_sig0_datac0.start() - audio_thread_datac1 = threading.Thread( - target=self.audio_datac1, name="AUDIO_THREAD DATAC1", daemon=True + audio_thread_sig1_datac0 = threading.Thread( + target=self.audio_sig1_datac0, name="AUDIO_THREAD DATAC0 - 1", daemon=True ) - audio_thread_datac1.start() + audio_thread_sig1_datac0.start() - audio_thread_datac3 = threading.Thread( - target=self.audio_datac3, name="AUDIO_THREAD DATAC3", daemon=True + audio_thread_dat0_datac1 = threading.Thread( + target=self.audio_dat0_datac1, name="AUDIO_THREAD DATAC1", daemon=True ) - audio_thread_datac3.start() + audio_thread_dat0_datac1.start() + + audio_thread_dat0_datac3 = threading.Thread( + target=self.audio_dat0_datac3, name="AUDIO_THREAD DATAC3", daemon=True + ) + audio_thread_dat0_datac3.start() if static.ENABLE_FSK: audio_thread_fsk_ldpc0 = threading.Thread( @@ -278,9 +296,10 @@ class RF: length_x = len(x) for data_buffer, receive in [ - (self.datac0_buffer, True), - (self.datac1_buffer, RECEIVE_DATAC1), - (self.datac3_buffer, RECEIVE_DATAC3), + (self.sig0_datac0_buffer, RECEIVE_SIG0), + (self.sig1_datac0_buffer, RECEIVE_SIG1), + (self.dat0_datac1_buffer, RECEIVE_DATAC1), + (self.dat0_datac3_buffer, RECEIVE_DATAC3), # Not enabled yet. # (self.fsk_ldpc_buffer_0, static.ENABLE_FSK), # (self.fsk_ldpc_buffer_1, static.ENABLE_FSK), @@ -334,11 +353,12 @@ class RF: # Avoid buffer overflow by filling only if buffer for # selected datachannel mode is not full for audiobuffer, receive, index in [ - (self.datac0_buffer, True, 0), - (self.datac1_buffer, RECEIVE_DATAC1, 1), - (self.datac3_buffer, RECEIVE_DATAC3, 2), - (self.fsk_ldpc_buffer_0, static.ENABLE_FSK, 3), - (self.fsk_ldpc_buffer_1, static.ENABLE_FSK, 4), + (self.sig0_datac0_buffer, True, 0), + (self.sig1_datac0_buffer, True, 1), + (self.dat0_datac1_buffer, RECEIVE_DATAC1, 2), + (self.dat0_datac3_buffer, RECEIVE_DATAC3, 3), + (self.fsk_ldpc_buffer_0, static.ENABLE_FSK, 4), + (self.fsk_ldpc_buffer_1, static.ENABLE_FSK, 5), ]: if audiobuffer.nbuffer + length_x > audiobuffer.size: static.BUFFER_OVERFLOW_COUNTER[index] += 1 @@ -618,51 +638,62 @@ class RF: nin = codec2.api.freedv_nin(c2instance) # Additional Datac0-specific information - these are not referenced anywhere else. - # 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.sig0_datac0_payload_per_frame = self.sig0_datac0_bytes_per_frame - 2 + # self.sig0_datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples( + # self.sig0_datac0_freedv # ) - # self.datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples( - # self.datac0_freedv + # self.sig0_datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples( + # self.sig0_datac0_freedv # ) - # self.datac0_n_tx_preamble_modem_samples = ( - # self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.datac0_freedv) + # self.sig0_datac0_n_tx_preamble_modem_samples = ( + # self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.sig0_datac0_freedv) # ) - # self.datac0_n_tx_postamble_modem_samples = ( - # self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.datac0_freedv) + # self.sig0_datac0_n_tx_postamble_modem_samples = ( + # self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.sig0_datac0_freedv) # ) # return values return c2instance, bytes_per_frame, bytes_out, audio_buffer, nin - def audio_datac0(self) -> None: - """Receive data encoded with datac0""" - self.datac0_nin = self.demodulate_audio( - self.datac0_buffer, - self.datac0_nin, - self.datac0_freedv, - self.datac0_bytes_out, - self.datac0_bytes_per_frame, + def audio_sig0_datac0(self) -> None: + """Receive data encoded with datac0 - 0""" + self.sig0_datac0_nin = self.demodulate_audio( + self.sig0_datac0_buffer, + self.sig0_datac0_nin, + self.sig0_datac0_freedv, + self.sig0_datac0_bytes_out, + self.sig0_datac0_bytes_per_frame, ) - def audio_datac1(self) -> None: + def audio_sig1_datac0(self) -> None: + """Receive data encoded with datac0 - 1""" + self.sig1_datac0_nin = self.demodulate_audio( + self.sig1_datac0_buffer, + self.sig1_datac0_nin, + self.sig1_datac0_freedv, + self.sig1_datac0_bytes_out, + self.sig1_datac0_bytes_per_frame, + ) + + + def audio_dat0_datac1(self) -> None: """Receive data encoded with datac1""" - self.datac1_nin = self.demodulate_audio( - self.datac1_buffer, - self.datac1_nin, - self.datac1_freedv, - self.datac1_bytes_out, - self.datac1_bytes_per_frame, + self.dat0_datac1_nin = self.demodulate_audio( + self.dat0_datac1_buffer, + self.dat0_datac1_nin, + self.dat0_datac1_freedv, + self.dat0_datac1_bytes_out, + self.dat0_datac1_bytes_per_frame, ) - def audio_datac3(self) -> None: + def audio_dat0_datac3(self) -> None: """Receive data encoded with datac3""" - self.datac3_nin = self.demodulate_audio( - self.datac3_buffer, - self.datac3_nin, - self.datac3_freedv, - self.datac3_bytes_out, - self.datac3_bytes_per_frame, + self.dat0_datac3_nin = self.demodulate_audio( + self.dat0_datac3_buffer, + self.dat0_datac3_nin, + self.dat0_datac3_freedv, + self.dat0_datac3_bytes_out, + self.dat0_datac3_bytes_per_frame, ) def audio_fsk_ldpc_0(self) -> None: @@ -883,8 +914,8 @@ class RF: frames_per_burst = min(frames_per_burst, 1) frames_per_burst = max(frames_per_burst, 5) - codec2.api.freedv_set_frames_per_burst(self.datac1_freedv, frames_per_burst) - codec2.api.freedv_set_frames_per_burst(self.datac3_freedv, frames_per_burst) + codec2.api.freedv_set_frames_per_burst(self.dat0_datac1_freedv, frames_per_burst) + codec2.api.freedv_set_frames_per_burst(self.dat0_datac3_freedv, frames_per_burst) codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, frames_per_burst) From 3600516a0b2865f0bdf55e46689c6bd111dee439 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Mon, 10 Oct 2022 09:39:26 +0200 Subject: [PATCH 22/47] additional tx mode options when sending sig --- tnc/data_handler.py | 70 +++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 6b52c6e7..77a7b036 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -44,7 +44,8 @@ class DATA: self.data_queue_received = DATA_QUEUE_RECEIVED # length of signalling frame - self.length_sig_frame = 14 + self.length_sig0_frame = 14 + self.length_sig1_frame = 14 # hold session id self.session_id = bytes(1) @@ -413,7 +414,7 @@ class DATA: def send_burst_ack_frame(self, snr) -> None: """Build and send ACK frame for burst DATA frame""" - ack_frame = bytearray(self.length_sig_frame) + ack_frame = bytearray(self.length_sig1_frame) ack_frame[:1] = bytes([FR_TYPE.BURST_ACK.value]) # ack_frame[1:4] = static.DXCALLSIGN_CRC # ack_frame[4:7] = static.MYCALLSIGN_CRC @@ -422,11 +423,11 @@ class DATA: ack_frame[3:4] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx(ack_frame) + self.enqueue_frame_for_tx(ack_frame, c2_mode=FREEDV_MODE.datac0.value) def send_data_ack_frame(self, snr) -> None: """Build and send ACK frame for received DATA frame""" - ack_frame = bytearray(self.length_sig_frame) + ack_frame = bytearray(self.length_sig1_frame) ack_frame[:1] = bytes([FR_TYPE.FR_ACK.value]) ack_frame[1:2] = self.session_id # ack_frame[1:4] = static.DXCALLSIGN_CRC @@ -435,7 +436,7 @@ class DATA: # ack_frame[8:9] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx(ack_frame, copies=3, repeat_delay=0) + self.enqueue_frame_for_tx(ack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) def send_retransmit_request_frame(self, freedv) -> None: # check where a None is in our burst buffer and do frame+1, beacuse lists start at 0 @@ -454,7 +455,7 @@ class DATA: # TODO: Trim `missing_frames` bytesarray to [7:13] (6) frames, if it's larger. # TODO: Instead of using int we could use a binary flag # then create a repeat frame - rpt_frame = bytearray(self.length_sig_frame) + rpt_frame = bytearray(self.length_sig1_frame) rpt_frame[:1] = bytes([FR_TYPE.FR_REPEAT.value]) rpt_frame[1:2] = self.session_id # rpt_frame[1:4] = static.DXCALLSIGN_CRC @@ -463,11 +464,12 @@ class DATA: self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) # Transmit frame - self.enqueue_frame_for_tx(rpt_frame) + self.enqueue_frame_for_tx(rpt_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + def send_burst_nack_frame(self, snr: float = 0) -> None: """Build and send NACK frame for received DATA frame""" - nack_frame = bytearray(self.length_sig_frame) + nack_frame = bytearray(self.length_sig1_frame) nack_frame[:1] = bytes([FR_TYPE.FR_NACK.value]) nack_frame[1:2] = self.session_id # nack_frame[1:4] = static.DXCALLSIGN_CRC @@ -476,11 +478,12 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST - self.enqueue_frame_for_tx(nack_frame) + self.enqueue_frame_for_tx(nack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: """Build and send NACK frame for watchdog timeout""" - nack_frame = bytearray(self.length_sig_frame) + nack_frame = bytearray(self.length_sig1_frame) nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value]) nack_frame[1:2] = self.session_id # nack_frame[1:4] = static.DXCALLSIGN_CRC @@ -489,18 +492,20 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST - self.enqueue_frame_for_tx(nack_frame) + self.enqueue_frame_for_tx(nack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + def send_disconnect_frame(self) -> None: """Build and send a disconnect frame""" - disconnection_frame = bytearray(self.length_sig_frame) + disconnection_frame = bytearray(self.length_sig1_frame) disconnection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_CLOSE.value]) disconnection_frame[1:2] = self.session_id # disconnection_frame[1:4] = static.DXCALLSIGN_CRC # disconnection_frame[4:7] = static.MYCALLSIGN_CRC # TODO: Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=0) + self.enqueue_frame_for_tx(disconnection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) + def arq_data_received( self, data_in: bytes, bytes_per_frame: int, snr: float, freedv @@ -1306,7 +1311,7 @@ class DATA: self.session_id = randbytes(1) print(self.session_id) - connection_frame = bytearray(self.length_sig_frame) + connection_frame = bytearray(self.length_sig0_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_OPEN.value]) connection_frame[1:2] = self.session_id # connection_frame[1:4] = static.DXCALLSIGN_CRC @@ -1326,7 +1331,7 @@ class DATA: state=static.ARQ_SESSION_STATE, ) - self.enqueue_frame_for_tx(connection_frame) + self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) # Wait for a time, looking to see if `static.ARQ_SESSION` # indicates we've received a positive response from the far station. @@ -1469,13 +1474,14 @@ class DATA: # static.TNC_STATE = "BUSY" # static.ARQ_SESSION_STATE = "connected" - connection_frame = bytearray(self.length_sig_frame) + connection_frame = bytearray(self.length_sig0_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_HB.value]) connection_frame[1:2] = self.session_id # connection_frame[1:4] = static.DXCALLSIGN_CRC # connection_frame[4:7] = static.MYCALLSIGN_CRC - self.enqueue_frame_for_tx(connection_frame) + self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + def received_session_heartbeat(self, data_in: bytes) -> None: """ @@ -1598,7 +1604,7 @@ class DATA: frametype = bytes([FR_TYPE.ARQ_DC_OPEN_W.value]) self.log.debug("[TNC] Requesting high bandwidth mode") - connection_frame = bytearray(self.length_sig_frame) + connection_frame = bytearray(self.length_sig0_frame) connection_frame[:1] = frametype connection_frame[1:4] = static.DXCALLSIGN_CRC connection_frame[4:7] = static.MYCALLSIGN_CRC @@ -1625,7 +1631,7 @@ class DATA: attempt=f"{str(attempt + 1)}/{str(self.data_channel_max_retries)}", ) - self.enqueue_frame_for_tx(connection_frame) + self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) timeout = time.time() + 4 while time.time() < timeout: @@ -1794,7 +1800,7 @@ class DATA: frametype = bytes([FR_TYPE.ARQ_DC_OPEN_ACK_W.value]) self.log.debug("[TNC] Responding with high bandwidth mode") - connection_frame = bytearray(self.length_sig_frame) + connection_frame = bytearray(self.length_sig0_frame) connection_frame[:1] = frametype connection_frame[1:2] = self.session_id # connection_frame[1:4] = static.DXCALLSIGN_CRC @@ -1804,7 +1810,8 @@ class DATA: # For checking protocol version on the receiving side connection_frame[13:14] = bytes([static.ARQ_PROTOCOL_VERSION]) - self.enqueue_frame_for_tx(connection_frame) + self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.log.info( "[TNC] ARQ | DATA | RX | [" @@ -1917,7 +1924,7 @@ class DATA: + "]" ) - ping_frame = bytearray(self.length_sig_frame) + ping_frame = bytearray(self.length_sig0_frame) ping_frame[:1] = bytes([FR_TYPE.PING.value]) ping_frame[1:4] = static.DXCALLSIGN_CRC ping_frame[4:7] = static.MYCALLSIGN_CRC @@ -1976,7 +1983,7 @@ class DATA: snr=static.SNR, ) - ping_frame = bytearray(self.length_sig_frame) + ping_frame = bytearray(self.length_sig0_frame) ping_frame[:1] = bytes([FR_TYPE.PING_ACK.value]) ping_frame[1:4] = static.DXCALLSIGN_CRC ping_frame[4:7] = static.MYCALLSIGN_CRC @@ -2033,14 +2040,14 @@ class DATA: Force a stop of the running transmission """ self.log.warning("[TNC] Stopping transmission!") - stop_frame = bytearray(self.length_sig_frame) + stop_frame = bytearray(self.length_sig0_frame) stop_frame[:1] = bytes([FR_TYPE.ARQ_STOP.value]) stop_frame[1:4] = static.DXCALLSIGN_CRC stop_frame[4:7] = static.MYCALLSIGN_CRC # TODO: Not sure if we really need the session id when disconnecting # stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(stop_frame, copies=6, repeat_delay=0) + self.enqueue_frame_for_tx(stop_frame, c2_mode=FREEDV_MODE.datac0.value, copies=6, repeat_delay=0) static.TNC_STATE = "IDLE" static.ARQ_STATE = False @@ -2099,7 +2106,7 @@ class DATA: "[TNC] Sending beacon!", interval=self.beacon_interval ) - beacon_frame = bytearray(self.length_sig_frame) + beacon_frame = bytearray(self.length_sig0_frame) beacon_frame[:1] = bytes([FR_TYPE.BEACON.value]) beacon_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign) beacon_frame[9:13] = static.MYGRID[:4] @@ -2111,7 +2118,8 @@ class DATA: c2_mode=FREEDV_MODE.fsk_ldpc_0.value, ) else: - self.enqueue_frame_for_tx(beacon_frame) + self.enqueue_frame_for_tx(beacon_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, + repeat_delay=0) interval_timer = time.time() + self.beacon_interval while ( @@ -2177,7 +2185,7 @@ class DATA: freedata="tnc-message", cq="transmitting", ) - cq_frame = bytearray(self.length_sig_frame) + cq_frame = bytearray(self.length_sig0_frame) cq_frame[:1] = bytes([FR_TYPE.CQ.value]) cq_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign) cq_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) @@ -2188,7 +2196,7 @@ class DATA: if static.ENABLE_FSK: self.enqueue_frame_for_tx(cq_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(cq_frame) + self.enqueue_frame_for_tx(cq_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def received_cq(self, data_in: bytes) -> None: """ @@ -2248,7 +2256,7 @@ class DATA: ) self.log.info("[TNC] Sending QRV!") - qrv_frame = bytearray(self.length_sig_frame) + qrv_frame = bytearray(self.length_sig0_frame) qrv_frame[:1] = bytes([FR_TYPE.QRV.value]) qrv_frame[1:7] = helpers.callsign_to_bytes(self.mycallsign) qrv_frame[7:11] = helpers.encode_grid(static.MYGRID.decode("UTF-8")) @@ -2258,7 +2266,7 @@ class DATA: if static.ENABLE_FSK: self.enqueue_frame_for_tx(qrv_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(qrv_frame) + self.enqueue_frame_for_tx(qrv_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def received_qrv(self, data_in: bytes) -> None: """ From cdb12861a504c613a341505e441ed369c059760c Mon Sep 17 00:00:00 2001 From: dj2ls Date: Mon, 10 Oct 2022 09:46:29 +0200 Subject: [PATCH 23/47] fix with enable/disable sig0/1 --- tnc/modem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tnc/modem.py b/tnc/modem.py index 34656e92..591bec07 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -32,7 +32,7 @@ TXCHANNEL = "" static.TRANSMITTING = False # Receive only specific modes to reduce CPU load -RECEIVE_SIG0 = False +RECEIVE_SIG0 = True RECEIVE_SIG1 = False RECEIVE_DATAC1 = False RECEIVE_DATAC3 = False @@ -353,8 +353,8 @@ class RF: # Avoid buffer overflow by filling only if buffer for # selected datachannel mode is not full for audiobuffer, receive, index in [ - (self.sig0_datac0_buffer, True, 0), - (self.sig1_datac0_buffer, True, 1), + (self.sig0_datac0_buffer, RECEIVE_SIG0, 0), + (self.sig1_datac0_buffer, RECEIVE_SIG1, 1), (self.dat0_datac1_buffer, RECEIVE_DATAC1, 2), (self.dat0_datac3_buffer, RECEIVE_DATAC3, 3), (self.fsk_ldpc_buffer_0, static.ENABLE_FSK, 4), From dee94b0acb6e68dcc29f0ae0e77860522930acfc Mon Sep 17 00:00:00 2001 From: dj2ls Date: Mon, 10 Oct 2022 10:20:56 +0200 Subject: [PATCH 24/47] additional timeout logging --- tnc/data_handler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 77a7b036..e28d8074 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -140,7 +140,7 @@ class DATA: self.burst_ack_timeout_seconds = 3.0 # timeout for burst acknowledges self.data_frame_ack_timeout_seconds = 3.0 # timeout for data frame acknowledges self.rpt_ack_timeout_seconds = 3.0 # timeout for rpt frame acknowledges - self.transmission_timeout = 360 # transmission timeout in seconds + self.transmission_timeout = 500 # transmission timeout in seconds # Dictionary of functions and log messages used in process_data # instead of a long series of if-elif-else statements. @@ -2578,7 +2578,10 @@ class DATA: self.data_channel_last_received + self.transmission_timeout > time.time() ): - time.sleep(0.01) + time.sleep(5) + timeleft = (self.data_channel_last_received + self.transmission_timeout) - time.time() + self.log.debug("Time left until timeout", seconds=timeleft) + # print(self.data_channel_last_received + self.transmission_timeout - time.time()) # pass else: From d98358b6ce58710154bd08d925c7bb3ef60da76c Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 07:40:39 +0200 Subject: [PATCH 25/47] first fixed connection session --- tnc/data_handler.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index e28d8074..7b589f2a 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1314,9 +1314,9 @@ class DATA: connection_frame = bytearray(self.length_sig0_frame) connection_frame[:1] = bytes([FR_TYPE.ARQ_SESSION_OPEN.value]) connection_frame[1:2] = self.session_id - # connection_frame[1:4] = static.DXCALLSIGN_CRC - # connection_frame[4:7] = static.MYCALLSIGN_CRC - connection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) + connection_frame[2:5] = static.DXCALLSIGN_CRC + connection_frame[5:8] = static.MYCALLSIGN_CRC + connection_frame[8:14] = helpers.callsign_to_bytes(self.mycallsign) while not static.ARQ_SESSION: time.sleep(0.01) @@ -1365,8 +1365,9 @@ class DATA: # Update arq_session timestamp self.arq_session_last_received = int(time.time()) - static.DXCALLSIGN_CRC = bytes(data_in[4:7]) - static.DXCALLSIGN = helpers.bytes_to_callsign(bytes(data_in[7:13])) + self.session_id = bytes(data_in[1:2]) + static.DXCALLSIGN_CRC = bytes(data_in[5:8]) + static.DXCALLSIGN = helpers.bytes_to_callsign(bytes(data_in[8:14])) helpers.add_to_heard_stations( static.DXCALLSIGN, From f096c7f3f9b47cf071ac9a2a07647e9c7f92625a Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 10:45:17 +0200 Subject: [PATCH 26/47] possible scatter fix --- tnc/codec2.py | 9 +++++++-- tnc/modem.py | 28 +++++++++++++--------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/tnc/codec2.py b/tnc/codec2.py index 18b5ee46..dc55fccc 100644 --- a/tnc/codec2.py +++ b/tnc/codec2.py @@ -103,6 +103,9 @@ api.freedv_open_advanced.restype = ctypes.c_void_p api.freedv_get_bits_per_modem_frame.argtype = [ctypes.c_void_p] # type: ignore api.freedv_get_bits_per_modem_frame.restype = ctypes.c_int +api.freedv_get_modem_extended_stats.argtype = [ctypes.c_void_p, ctypes.c_void_p] +api.freedv_get_modem_extended_stats.restype = ctypes.c_int + api.freedv_nin.argtype = [ctypes.c_void_p] # type: ignore api.freedv_nin.restype = ctypes.c_int @@ -208,8 +211,8 @@ api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200 api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_256_512_4".encode("utf-8") # code word # ------- MODEM STATS STRUCTURES -MODEM_STATS_NC_MAX = 50 + 1 -MODEM_STATS_NR_MAX = 160 +MODEM_STATS_NC_MAX = 50 + 1 * 2 +MODEM_STATS_NR_MAX = 160 * 2 MODEM_STATS_ET_MAX = 8 MODEM_STATS_EYE_IND_MAX = 160 MODEM_STATS_NSPEC = 512 @@ -233,10 +236,12 @@ class MODEMSTATS(ctypes.Structure): ("pre", ctypes.c_int), ("post", ctypes.c_int), ("uw_fails", ctypes.c_int), + ("rx_eye", (ctypes.c_float * MODEM_STATS_ET_MAX) * MODEM_STATS_EYE_IND_MAX), ("neyetr", ctypes.c_int), # How many eye traces are plotted ("neyesamp", ctypes.c_int), # How many samples in the eye diagram ("f_est", (ctypes.c_float * MODEM_STATS_MAX_F_EST)), ("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)), + ("fft_cfg", ctypes.c_void_p) ] diff --git a/tnc/modem.py b/tnc/modem.py index 591bec07..68a40545 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -581,7 +581,7 @@ class RF: "[MDM] [demod_audio] Pushing received data to received_queue" ) self.modem_received_queue.put([bytes_out, freedv, bytes_per_frame]) - # self.get_scatter(freedv) + self.get_scatter(freedv) self.calculate_snr(freedv) return nin @@ -749,7 +749,6 @@ class RF: :rtype: float """ modemStats = codec2.MODEMSTATS() - self.c_lib.freedv_get_modem_extended_stats.restype = None self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)) offset = round(modemStats.foff) * (-1) static.FREQ_OFFSET = offset @@ -767,28 +766,27 @@ class RF: return modemStats = codec2.MODEMSTATS() - self.c_lib.freedv_get_modem_extended_stats.restype = None - self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)) + ctypes.cast( + self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)), + ctypes.c_void_p, + ) scatterdata = [] - scatterdata_small = [] for i in range(codec2.MODEM_STATS_NC_MAX): - for j in range(codec2.MODEM_STATS_NR_MAX): - # check if odd or not to get every 2nd item for x - if (j % 2) == 0: - xsymbols = round(modemStats.rx_symbols[i][j] / 1000) - ysymbols = round(modemStats.rx_symbols[i][j + 1] / 1000) - # check if value 0.0 or has real data - if xsymbols != 0.0 and ysymbols != 0.0: - scatterdata.append({"x": xsymbols, "y": ysymbols}) + for j in range(1, codec2.MODEM_STATS_NR_MAX, 2): + # print(f"{modemStats.rx_symbols[i][j]} - {modemStats.rx_symbols[i][j]}") + xsymbols = round(modemStats.rx_symbols[i][j - 1] / 1000) + ysymbols = round(modemStats.rx_symbols[i][j] / 1000) + if xsymbols != 0.0 and ysymbols != 0.0: + scatterdata.append({"x": str(xsymbols), "y": str(ysymbols)}) # Send all the data if we have too-few samples, otherwise send a sampling if 150 > len(scatterdata) > 0: static.SCATTER = scatterdata else: # only take every tenth data point - scatterdata_small = scatterdata[::10] - static.SCATTER = scatterdata_small + static.SCATTER = scatterdata[::10] + def calculate_snr(self, freedv: ctypes.c_void_p) -> float: """ From b41430fc43166fee3c263af133f3fad474a18fe9 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 11:05:49 +0200 Subject: [PATCH 27/47] another attempt with rms --- gui/preload-main.js | 5 ++--- tnc/modem.py | 10 ++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/gui/preload-main.js b/gui/preload-main.js index b0f4ef1f..e0903593 100644 --- a/gui/preload-main.js +++ b/gui/preload-main.js @@ -1458,11 +1458,10 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { document.getElementById("beaconInterval").disabled = false; } // RMS - /* - var rms_level = Math.round((arg.rms_level/60) * 100) + var rms_level = (arg.rms_level / 32767) * 100 document.getElementById("rms_level").setAttribute("aria-valuenow", rms_level); document.getElementById("rms_level").setAttribute("style", "width:" + rms_level + "%;"); - */ + // SET FREQUENCY document.getElementById("frequency").innerHTML = arg.frequency; diff --git a/tnc/modem.py b/tnc/modem.py index 68a40545..6d1c513b 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -775,8 +775,8 @@ class RF: for i in range(codec2.MODEM_STATS_NC_MAX): for j in range(1, codec2.MODEM_STATS_NR_MAX, 2): # print(f"{modemStats.rx_symbols[i][j]} - {modemStats.rx_symbols[i][j]}") - xsymbols = round(modemStats.rx_symbols[i][j - 1] / 1000) - ysymbols = round(modemStats.rx_symbols[i][j] / 1000) + xsymbols = round(modemStats.rx_symbols[i][j - 1] // 1000) + ysymbols = round(modemStats.rx_symbols[i][j] // 1000) if xsymbols != 0.0 and ysymbols != 0.0: scatterdata.append({"x": str(xsymbols), "y": str(ysymbols)}) @@ -872,8 +872,10 @@ class RF: if not static.TRANSMITTING: dfft[dfft > avg + 10] = 100 - # Calculate audio max value - # static.AUDIO_RMS = np.amax(self.fft_data) + # Calculate audio RMS + # https://stackoverflow.com/a/9763652 + d = np.frombuffer(self.fft_data, np.int16).astype(np.float) + static.AUDIO_RMS = int(np.sqrt((d * d).sum() / len(d))) # Check for signals higher than average by checking for "100" # If we have a signal, increment our channel_busy delay counter From 7d2168a0e7398fba40f9b29f5c170e9c2b0e75cd Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 11:32:09 +0200 Subject: [PATCH 28/47] another attempt with rms --- gui/src/index.html | 6 +++--- tnc/modem.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/gui/src/index.html b/gui/src/index.html index be0588ee..ec8976eb 100644 --- a/gui/src/index.html +++ b/gui/src/index.html @@ -746,11 +746,11 @@
-

RX AUDIO LEVEL - not implemented yet

+

RX AUDIO LEVEL

-
-
+
+
diff --git a/tnc/modem.py b/tnc/modem.py index 6d1c513b..a2eef5bf 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -843,6 +843,9 @@ class RF: # Initialize channel_busy_delay counter channel_busy_delay = 0 + # Initialize rms counter + rms_counter = 0 + while True: # time.sleep(0.01) threading.Event().wait(0.01) @@ -874,8 +877,12 @@ class RF: # Calculate audio RMS # https://stackoverflow.com/a/9763652 - d = np.frombuffer(self.fft_data, np.int16).astype(np.float) - static.AUDIO_RMS = int(np.sqrt((d * d).sum() / len(d))) + # calculate RMS every 150 cycles for reducing CPU load + rms_counter += 1 + if rms_counter > 150: + d = np.frombuffer(self.fft_data, np.int16).astype(np.float) + static.AUDIO_RMS = int(np.sqrt((d * d).sum() / len(d))) + rms_counter = 0 # Check for signals higher than average by checking for "100" # If we have a signal, increment our channel_busy delay counter From 392e0bf93031e3daeaf5a6031576b2a89f846a62 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 12:33:35 +0200 Subject: [PATCH 29/47] moved from sum to mean --- tnc/modem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tnc/modem.py b/tnc/modem.py index a2eef5bf..488d5ca8 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -877,11 +877,11 @@ class RF: # Calculate audio RMS # https://stackoverflow.com/a/9763652 - # calculate RMS every 150 cycles for reducing CPU load + # calculate RMS every 50 cycles for reducing CPU load rms_counter += 1 - if rms_counter > 150: + if rms_counter > 50: d = np.frombuffer(self.fft_data, np.int16).astype(np.float) - static.AUDIO_RMS = int(np.sqrt((d * d).sum() / len(d))) + static.AUDIO_RMS = int(np.sqrt(np.mean(d ** 2))) rms_counter = 0 # Check for signals higher than average by checking for "100" From 5553009d748ee43c7cc52aa882208f00415e4d17 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 12:54:37 +0200 Subject: [PATCH 30/47] improved file transfer during arq session --- tnc/data_handler.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 7b589f2a..8a0df754 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1551,7 +1551,7 @@ class DATA: # wait a moment for the case, a heartbeat is already on the way back to us if static.ARQ_SESSION: - time.sleep(0.5) + time.sleep(1.5) self.datachannel_timeout = False @@ -2637,15 +2637,18 @@ class DATA: """ while True: time.sleep(0.01) - if ( - static.ARQ_SESSION - and self.IS_ARQ_SESSION_MASTER - and static.ARQ_SESSION_STATE == "connected" - and not self.arq_file_transfer - ): - time.sleep(1) - self.transmit_session_heartbeat() - time.sleep(2) + # additional check for smoother stopping if heartbeat transmission + while not self.arq_file_transfer: + time.sleep(0.01) + if ( + static.ARQ_SESSION + and self.IS_ARQ_SESSION_MASTER + and static.ARQ_SESSION_STATE == "connected" + #and not self.arq_file_transfer + ): + time.sleep(1) + self.transmit_session_heartbeat() + time.sleep(2) def send_test_frame(self) -> None: """Send an empty test frame""" From 616fb214d2abf3902ebd226d4f48f8e1044afe7e Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 12 Oct 2022 13:01:20 +0200 Subject: [PATCH 31/47] improved file transfer during arq session --- tnc/data_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 8a0df754..69bf2bcc 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1555,7 +1555,7 @@ class DATA: self.datachannel_timeout = False - # we need to compress data for gettin a compression factor. + # we need to compress data for getting a compression factor. # so we are compressing twice. This is not that nice and maybe there is another way # for calculating transmission statistics # static.ARQ_COMPRESSION_FACTOR = len(data_out) / len(zlib.compress(data_out)) From 4b37ea4d67b29ba93313dbe3239d13873179071d Mon Sep 17 00:00:00 2001 From: Paul Kronenwetter Date: Fri, 21 Oct 2022 14:56:25 -0400 Subject: [PATCH 32/47] Adapt TNC States test to use the session ID --- test/test_tnc_states.py | 63 +++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/test/test_tnc_states.py b/test/test_tnc_states.py index 7cc5575a..affbaef1 100644 --- a/test/test_tnc_states.py +++ b/test/test_tnc_states.py @@ -15,6 +15,7 @@ Uses util_datac0.py in separate process to perform the data transfer. """ import multiprocessing +from random import randbytes import sys import time @@ -62,16 +63,23 @@ def t_create_frame(frame_type: int, mycall: str, dxcall: str) -> bytearray: dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes) dxcallsign_crc = helpers.get_crc_24(dxcallsign) + # frame = bytearray(14) + # frame[:1] = bytes([frame_type]) + # frame[1:4] = dxcallsign_crc + # frame[4:7] = mycallsign_crc + # frame[7:13] = mycallsign_bytes + session_id = randbytes(1) frame = bytearray(14) frame[:1] = bytes([frame_type]) - frame[1:4] = dxcallsign_crc - frame[4:7] = mycallsign_crc - frame[7:13] = mycallsign_bytes + frame[1:2] = session_id + frame[2:5] = dxcallsign_crc + frame[5:8] = mycallsign_crc + frame[8:14] = mycallsign_bytes return frame -def t_create_session_close(mycall: str, dxcall: str) -> bytearray: +def t_create_session_close_old(mycall: str, dxcall: str) -> bytearray: """ Generate the session_close frame. @@ -85,6 +93,23 @@ def t_create_session_close(mycall: str, dxcall: str) -> bytearray: return t_create_frame(223, mycall, dxcall) +def t_create_session_close(session_id: bytes) -> bytearray: + """ + Generate the session_close frame. + + :param session_id: Session to close + :type mycall: int + :return: Bytearray of the requested frame + :rtype: bytearray + """ + # return t_create_frame(223, mycall, dxcall) + frame = bytearray(14) + frame[:1] = bytes([223]) + frame[1:2] = session_id + + return frame + + def t_create_start_session(mycall: str, dxcall: str) -> bytearray: """ Generate the create_session frame. @@ -150,18 +175,24 @@ def t_foreign_disconnect(mycall: str, dxcall: str): assert static.ARQ_SESSION_STATE == "connecting" # Set up a frame from a non-associated station. - foreigncall_bytes = helpers.callsign_to_bytes("ZZ0ZZ-0") - foreigncall = helpers.bytes_to_callsign(foreigncall_bytes) + # foreigncall_bytes = helpers.callsign_to_bytes("ZZ0ZZ-0") + # foreigncall = helpers.bytes_to_callsign(foreigncall_bytes) - close_frame = t_create_session_close("ZZ0ZZ-0", "ZZ0ZZ-0") + # close_frame = t_create_session_close_old("ZZ0ZZ-0", "ZZ0ZZ-0") + open_session = create_frame[1:2] + wrong_session = randbytes(1) + while wrong_session == open_session: + wrong_session = randbytes(1) + close_frame = t_create_session_close(wrong_session) print_frame(close_frame) - assert ( - helpers.check_callsign(static.DXCALLSIGN, bytes(close_frame[4:7]))[0] is False - ), f"{helpers.get_crc_24(static.DXCALLSIGN)} == {bytes(close_frame[4:7])} but should be not equal." - assert ( - helpers.check_callsign(foreigncall, bytes(close_frame[4:7]))[0] is True - ), f"{helpers.get_crc_24(foreigncall)} != {bytes(close_frame[4:7])} but should be equal." + # assert ( + # helpers.check_callsign(static.DXCALLSIGN, bytes(close_frame[4:7]))[0] is False + # ), f"{helpers.get_crc_24(static.DXCALLSIGN)} == {bytes(close_frame[4:7])} but should be not equal." + + # assert ( + # helpers.check_callsign(foreigncall, bytes(close_frame[4:7]))[0] is True + # ), f"{helpers.get_crc_24(foreigncall)} != {bytes(close_frame[4:7])} but should be equal." # Send the non-associated session close frame to the TNC tnc.received_session_close(close_frame) @@ -221,7 +252,9 @@ def t_valid_disconnect(mycall: str, dxcall: str): assert static.ARQ_SESSION_STATE == "connecting" # Create packet to be 'received' by this station. - close_frame = t_create_session_close(mycall=dxcall, dxcall=mycall) + # close_frame = t_create_session_close_old(mycall=dxcall, dxcall=mycall) + open_session = create_frame[1:2] + close_frame = t_create_session_close(open_session) print_frame(close_frame) tnc.received_session_close(close_frame) @@ -241,7 +274,7 @@ def t_valid_disconnect(mycall: str, dxcall: str): @pytest.mark.parametrize("mycall", ["AA1AA-2", "DE2DE-0", "E4AWQ-4"]) @pytest.mark.parametrize("dxcall", ["AA9AA-1", "DE2ED-0", "F6QWE-3"]) -@pytest.mark.flaky(reruns=2) +# @pytest.mark.flaky(reruns=2) def test_foreign_disconnect(mycall: str, dxcall: str): proc = multiprocessing.Process(target=t_foreign_disconnect, args=(mycall, dxcall)) # print("Starting threads.") From cf25cadc3c5d0f68541a7177f9b636c6ae88e22c Mon Sep 17 00:00:00 2001 From: Paul Kronenwetter Date: Fri, 21 Oct 2022 15:59:26 -0400 Subject: [PATCH 33/47] Suggested identification frame --- tnc/data_handler.py | 9 +++++++++ tnc/static.py | 1 + 2 files changed, 10 insertions(+) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 69bf2bcc..eada4b45 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -412,6 +412,15 @@ class DATA: json_data_out = json.dumps(jsondata) sock.SOCKET_QUEUE.put(json_data_out) + def send_ident_frame(self) -> None: + """Build and send IDENT frame """ + ident_frame = bytearray(self.length_sig1_frame) + ident_frame[:1] = bytes([FR_TYPE.IDENT.value]) + ident_frame[1:self.length_sig1_frame] = self.mycallsign + + # Transmit frame + self.enqueue_frame_for_tx(ident_frame, c2_mode=FREEDV_MODE.datac0.value) + def send_burst_ack_frame(self, snr) -> None: """Build and send ACK frame for burst DATA frame""" ack_frame = bytearray(self.length_sig1_frame) diff --git a/tnc/static.py b/tnc/static.py index 86f44ea7..70559f84 100644 --- a/tnc/static.py +++ b/tnc/static.py @@ -149,4 +149,5 @@ class FRAME_TYPE(Enum): ARQ_DC_OPEN_ACK_N = 228 ARQ_STOP = 249 BEACON = 250 + IDENT = 254 TEST_FRAME = 255 From 0a30f3fd2cd4c0796ad1f95bf9c5244427d7b1aa Mon Sep 17 00:00:00 2001 From: Paul Kronenwetter Date: Sat, 22 Oct 2022 09:59:37 -0400 Subject: [PATCH 34/47] Increase retries. For some reason 1-1-datac1 is succeeding locally but failing in the pipeline. --- test/test_chat_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_chat_text.py b/test/test_chat_text.py index ae798eb1..ddc1f010 100644 --- a/test/test_chat_text.py +++ b/test/test_chat_text.py @@ -133,7 +133,7 @@ def analyze_results(station1: list, station2: list, call_list: list): @pytest.mark.parametrize("freedv_mode", ["datac1", "datac3"]) @pytest.mark.parametrize("n_frames_per_burst", [1]) # Higher fpb is broken. @pytest.mark.parametrize("message_no", range(len(messages))) -@pytest.mark.flaky(reruns=2) +@pytest.mark.flaky(reruns=3) def test_chat_text( freedv_mode: str, n_frames_per_burst: int, message_no: int, tmp_path ): From 399177eca300eb62b8f97d3ec15b4e5d5e24231d Mon Sep 17 00:00:00 2001 From: Paul Kronenwetter Date: Sat, 22 Oct 2022 10:12:50 -0400 Subject: [PATCH 35/47] Revert Increase retries. --- test/test_chat_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_chat_text.py b/test/test_chat_text.py index ddc1f010..ae798eb1 100644 --- a/test/test_chat_text.py +++ b/test/test_chat_text.py @@ -133,7 +133,7 @@ def analyze_results(station1: list, station2: list, call_list: list): @pytest.mark.parametrize("freedv_mode", ["datac1", "datac3"]) @pytest.mark.parametrize("n_frames_per_burst", [1]) # Higher fpb is broken. @pytest.mark.parametrize("message_no", range(len(messages))) -@pytest.mark.flaky(reruns=3) +@pytest.mark.flaky(reruns=2) def test_chat_text( freedv_mode: str, n_frames_per_burst: int, message_no: int, tmp_path ): From 9e312b3b3ae9ed2d83c6aec404997e7a0557a795 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 08:25:47 +0200 Subject: [PATCH 36/47] increased waiting time for ARQ SESSION file transfer --- tnc/data_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index eada4b45..ae5892e7 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1559,8 +1559,9 @@ class DATA: self.transmission_uuid = transmission_uuid # wait a moment for the case, a heartbeat is already on the way back to us + # this makes channel establishment more clean if static.ARQ_SESSION: - time.sleep(1.5) + time.sleep(2) self.datachannel_timeout = False From 7b0535193da44229b5c1777d05bce498ecbffeb3 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 08:56:55 +0200 Subject: [PATCH 37/47] improved session disconnect to avoid heartbeat toggle --- tnc/data_handler.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index ae5892e7..5e276b39 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1429,7 +1429,7 @@ class DATA: static.ARQ_SESSION = False # we need to send disconnect frame before doing arq cleanup - # we would loose our session id then + # we would lose our session id then self.send_disconnect_frame() self.arq_cleanup() @@ -1521,8 +1521,18 @@ class DATA: # Update the timeout timestamps self.arq_session_last_received = int(time.time()) self.data_channel_last_received = int(time.time()) - - if not self.IS_ARQ_SESSION_MASTER and not self.arq_file_transfer: + # transmit session heartbeat only + # -> if not session master + # --> this will be triggered by heartbeat watchdog + # -> if not during a file transfer + # -> if ARQ_SESSION_STATE != disconnecting to avoid heartbeat toggle loops while disconnecting + if ( + not self.IS_ARQ_SESSION_MASTER + and not self.arq_file_transfer + and static.ARQ_SESSION_STATE != 'disconnecting' + and static.ARQ_SESSION_STATE != 'disconnected' + and static.ARQ_SESSION_STATE != 'failed' + ): self.transmit_session_heartbeat() ########################################################################################################## From 5acdc338ba314184b8bdb79a3530f3ca9645fec0 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 09:05:47 +0200 Subject: [PATCH 38/47] improved session disconnect inline documentation --- tnc/data_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 5e276b39..a4cd2d01 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -1525,7 +1525,8 @@ class DATA: # -> if not session master # --> this will be triggered by heartbeat watchdog # -> if not during a file transfer - # -> if ARQ_SESSION_STATE != disconnecting to avoid heartbeat toggle loops while disconnecting + # -> if ARQ_SESSION_STATE != disconnecting, disconnected, failed + # --> to avoid heartbeat toggle loops while disconnecting if ( not self.IS_ARQ_SESSION_MASTER and not self.arq_file_transfer From 0e28e2e3a2e68056398ea3b5671dbf0c783a0b08 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 09:38:42 +0200 Subject: [PATCH 39/47] resolve merge conflict --- tnc/audio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tnc/audio.py b/tnc/audio.py index 41190bb6..475cf780 100644 --- a/tnc/audio.py +++ b/tnc/audio.py @@ -42,8 +42,8 @@ def get_audio_devices(): proc.start() proc.join() - log.debug("[AUD] get_audio_devices: input_devices:", list=f"{proxy_input_devices}") - log.debug("[AUD] get_audio_devices: output_devices:", list=f"{proxy_output_devices}") + #log.debug("[AUD] get_audio_devices: input_devices:", list=f"{proxy_input_devices}") + #log.debug("[AUD] get_audio_devices: output_devices:", list=f"{proxy_output_devices}") return list(proxy_input_devices), list(proxy_output_devices) From b3726cfae5ba0c5a3c208bfe02a8278f99fa23af Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 09:42:18 +0200 Subject: [PATCH 40/47] increase protocol and app version --- gui/package.json | 2 +- tnc/audio.py | 4 ++-- tnc/static.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gui/package.json b/gui/package.json index 86f6e817..f7a9ad9b 100644 --- a/gui/package.json +++ b/gui/package.json @@ -1,6 +1,6 @@ { "name": "FreeDATA", - "version": "0.5.0-alpha.1", + "version": "0.6.0-alpha.1", "description": "FreeDATA ", "main": "main.js", "scripts": { diff --git a/tnc/audio.py b/tnc/audio.py index 475cf780..41190bb6 100644 --- a/tnc/audio.py +++ b/tnc/audio.py @@ -42,8 +42,8 @@ def get_audio_devices(): proc.start() proc.join() - #log.debug("[AUD] get_audio_devices: input_devices:", list=f"{proxy_input_devices}") - #log.debug("[AUD] get_audio_devices: output_devices:", list=f"{proxy_output_devices}") + log.debug("[AUD] get_audio_devices: input_devices:", list=f"{proxy_input_devices}") + log.debug("[AUD] get_audio_devices: output_devices:", list=f"{proxy_output_devices}") return list(proxy_input_devices), list(proxy_output_devices) diff --git a/tnc/static.py b/tnc/static.py index 70559f84..ed69a06d 100644 --- a/tnc/static.py +++ b/tnc/static.py @@ -11,7 +11,7 @@ Not nice, suggestions are appreciated :-) import subprocess from enum import Enum -VERSION = "0.5.0-alpha" +VERSION = "0.6.0-alpha" # DAEMON DAEMONPORT: int = 3001 @@ -85,7 +85,7 @@ ENABLE_FFT: bool = False CHANNEL_BUSY: bool = False # ARQ PROTOCOL VERSION -ARQ_PROTOCOL_VERSION: int = 2 +ARQ_PROTOCOL_VERSION: int = 3 # ARQ statistics ARQ_BYTES_PER_MINUTE_BURST: int = 0 From 5c041161e60800f27d0a8056ab96696a2e8c45f2 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 26 Oct 2022 12:11:39 +0200 Subject: [PATCH 41/47] revert increase protocol and app version --- gui/package.json | 2 +- tnc/static.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/package.json b/gui/package.json index f7a9ad9b..86f6e817 100644 --- a/gui/package.json +++ b/gui/package.json @@ -1,6 +1,6 @@ { "name": "FreeDATA", - "version": "0.6.0-alpha.1", + "version": "0.5.0-alpha.1", "description": "FreeDATA ", "main": "main.js", "scripts": { diff --git a/tnc/static.py b/tnc/static.py index ed69a06d..ef0e2b09 100644 --- a/tnc/static.py +++ b/tnc/static.py @@ -11,7 +11,7 @@ Not nice, suggestions are appreciated :-) import subprocess from enum import Enum -VERSION = "0.6.0-alpha" +VERSION = "0.5.0-alpha" # DAEMON DAEMONPORT: int = 3001 From eea9ff99195bd1b88eb02d5aa466bd2effca5564 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Fri, 28 Oct 2022 10:55:50 +0200 Subject: [PATCH 42/47] adjusted enqueue tx frame for N>1 frames and send ident frame after disconenct --- tnc/data_handler.py | 57 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index a4cd2d01..b9824c16 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -370,7 +370,7 @@ class DATA: Send (transmit) supplied frame to TNC :param frame_to_tx: Frame data to send - :type frame_to_tx: bytearray + :type frame_to_tx: list of bytearrays :param c2_mode: Codec2 mode to use, defaults to 14 (datac0) :type c2_mode: int, optional :param copies: Number of frame copies to send, defaults to 1 @@ -383,7 +383,7 @@ class DATA: # Set the TRANSMITTING flag before adding an object to the transmit queue # TODO: This is not that nice, we could improve this somehow static.TRANSMITTING = True - modem.MODEM_TRANSMIT_QUEUE.put([c2_mode, copies, repeat_delay, [frame_to_tx]]) + modem.MODEM_TRANSMIT_QUEUE.put([c2_mode, copies, repeat_delay, frame_to_tx]) # Wait while transmitting while static.TRANSMITTING: @@ -412,14 +412,17 @@ class DATA: json_data_out = json.dumps(jsondata) sock.SOCKET_QUEUE.put(json_data_out) - def send_ident_frame(self) -> None: + def send_ident_frame(self, transmit) -> None: """Build and send IDENT frame """ ident_frame = bytearray(self.length_sig1_frame) ident_frame[:1] = bytes([FR_TYPE.IDENT.value]) ident_frame[1:self.length_sig1_frame] = self.mycallsign # Transmit frame - self.enqueue_frame_for_tx(ident_frame, c2_mode=FREEDV_MODE.datac0.value) + if transmit: + self.enqueue_frame_for_tx([ident_frame], c2_mode=FREEDV_MODE.datac0.value) + else: + return ident_frame def send_burst_ack_frame(self, snr) -> None: """Build and send ACK frame for burst DATA frame""" @@ -432,7 +435,7 @@ class DATA: ack_frame[3:4] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx(ack_frame, c2_mode=FREEDV_MODE.datac0.value) + self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.datac0.value) def send_data_ack_frame(self, snr) -> None: """Build and send ACK frame for received DATA frame""" @@ -445,7 +448,7 @@ class DATA: # ack_frame[8:9] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx(ack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) + self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) def send_retransmit_request_frame(self, freedv) -> None: # check where a None is in our burst buffer and do frame+1, beacuse lists start at 0 @@ -473,7 +476,7 @@ class DATA: self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) # Transmit frame - self.enqueue_frame_for_tx(rpt_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([rpt_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def send_burst_nack_frame(self, snr: float = 0) -> None: @@ -487,7 +490,7 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST - self.enqueue_frame_for_tx(nack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: @@ -501,7 +504,7 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST - self.enqueue_frame_for_tx(nack_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def send_disconnect_frame(self) -> None: @@ -513,7 +516,7 @@ class DATA: # disconnection_frame[4:7] = static.MYCALLSIGN_CRC # TODO: Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(disconnection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) + self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) def arq_data_received( @@ -988,7 +991,7 @@ class DATA: ) for t_buf_item in tempbuffer: - self.enqueue_frame_for_tx(t_buf_item, c2_mode=data_mode) + self.enqueue_frame_for_tx([t_buf_item], c2_mode=data_mode) # After transmission finished, wait for an ACK or RPT frame # burstacktimeout = time.time() + self.burst_ack_timeout_seconds + 100 @@ -1340,7 +1343,7 @@ class DATA: state=static.ARQ_SESSION_STATE, ) - self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) # Wait for a time, looking to see if `static.ARQ_SESSION` # indicates we've received a positive response from the far station. @@ -1490,7 +1493,7 @@ class DATA: # connection_frame[1:4] = static.DXCALLSIGN_CRC # connection_frame[4:7] = static.MYCALLSIGN_CRC - self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def received_session_heartbeat(self, data_in: bytes) -> None: @@ -1653,7 +1656,7 @@ class DATA: attempt=f"{str(attempt + 1)}/{str(self.data_channel_max_retries)}", ) - self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) timeout = time.time() + 4 while time.time() < timeout: @@ -1832,7 +1835,7 @@ class DATA: # For checking protocol version on the receiving side connection_frame[13:14] = bytes([static.ARQ_PROTOCOL_VERSION]) - self.enqueue_frame_for_tx(connection_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) self.log.info( @@ -1954,9 +1957,9 @@ class DATA: self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) if static.ENABLE_FSK: - self.enqueue_frame_for_tx(ping_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(ping_frame, c2_mode=FREEDV_MODE.datac0.value) + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.datac0.value) def received_ping(self, data_in: bytes) -> None: """ @@ -2013,9 +2016,9 @@ class DATA: self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) if static.ENABLE_FSK: - self.enqueue_frame_for_tx(ping_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(ping_frame, c2_mode=FREEDV_MODE.datac0.value) + self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.datac0.value) def received_ping_ack(self, data_in: bytes) -> None: """ @@ -2069,7 +2072,7 @@ class DATA: # TODO: Not sure if we really need the session id when disconnecting # stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx(stop_frame, c2_mode=FREEDV_MODE.datac0.value, copies=6, repeat_delay=0) + self.enqueue_frame_for_tx([stop_frame], c2_mode=FREEDV_MODE.datac0.value, copies=6, repeat_delay=0) static.TNC_STATE = "IDLE" static.ARQ_STATE = False @@ -2136,11 +2139,11 @@ class DATA: if static.ENABLE_FSK: self.enqueue_frame_for_tx( - beacon_frame, + [beacon_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value, ) else: - self.enqueue_frame_for_tx(beacon_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, + self.enqueue_frame_for_tx([beacon_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) interval_timer = time.time() + self.beacon_interval @@ -2216,9 +2219,9 @@ class DATA: self.log.debug("[TNC] CQ Frame:", data=[cq_frame]) if static.ENABLE_FSK: - self.enqueue_frame_for_tx(cq_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) + self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(cq_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([cq_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def received_cq(self, data_in: bytes) -> None: """ @@ -2286,9 +2289,9 @@ class DATA: self.log.info("[TNC] ENABLE FSK", state=static.ENABLE_FSK) if static.ENABLE_FSK: - self.enqueue_frame_for_tx(qrv_frame, c2_mode=FREEDV_MODE.fsk_ldpc_0.value) + self.enqueue_frame_for_tx([qrv_frame], c2_mode=FREEDV_MODE.fsk_ldpc_0.value) else: - self.enqueue_frame_for_tx(qrv_frame, c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([qrv_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def received_qrv(self, data_in: bytes) -> None: """ @@ -2674,5 +2677,5 @@ class DATA: def send_test_frame(self) -> None: """Send an empty test frame""" self.enqueue_frame_for_tx( - frame_to_tx=bytearray(126), c2_mode=FREEDV_MODE.datac3.value + frame_to_tx=[bytearray(126)], c2_mode=FREEDV_MODE.datac3.value ) From 4ce36dba5e1dc17d8715df03782ee7edb660b06d Mon Sep 17 00:00:00 2001 From: dj2ls Date: Fri, 28 Oct 2022 11:02:23 +0200 Subject: [PATCH 43/47] inline comment --- tnc/data_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index b9824c16..ea68ac27 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -448,10 +448,12 @@ class DATA: # ack_frame[8:9] = bytes([int(self.speed_level)]) # Transmit frame + # TODO: Do we have to send , self.send_ident_frame(False) ? + # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) def send_retransmit_request_frame(self, freedv) -> None: - # check where a None is in our burst buffer and do frame+1, beacuse lists start at 0 + # check where a None is in our burst buffer and do frame+1, because lists start at 0 # FIXME: Check to see if there's a `frame - 1` in the receive portion. Remove both if there is. missing_frames = [ frame + 1 From 58e44a2dbba6c7775dbd2c8dad0413ddacc1c1f8 Mon Sep 17 00:00:00 2001 From: dj2ls Date: Fri, 28 Oct 2022 11:03:15 +0200 Subject: [PATCH 44/47] inline comment --- tnc/data_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index ea68ac27..4bd3e042 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -492,9 +492,10 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST + # TODO: Do we have to send ident frame? + # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: """Build and send NACK frame for watchdog timeout""" nack_frame = bytearray(self.length_sig1_frame) From 65dde27e6b59eb395eaa5073ff7f7a83ddf598af Mon Sep 17 00:00:00 2001 From: dj2ls Date: Fri, 28 Oct 2022 11:11:47 +0200 Subject: [PATCH 45/47] small pep8 improvement --- tnc/data_handler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 4bd3e042..0acc22be 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -495,7 +495,6 @@ class DATA: # TODO: Do we have to send ident frame? # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: """Build and send NACK frame for watchdog timeout""" nack_frame = bytearray(self.length_sig1_frame) @@ -1693,7 +1692,6 @@ class DATA: ) self.datachannel_timeout = True - # Attempt to cleanup the far-side, if it received the # open_session frame and can still hear us. self.close_session() @@ -1840,7 +1838,6 @@ class DATA: self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - self.log.info( "[TNC] ARQ | DATA | RX | [" + str(mycallsign, "UTF-8") From 6bb9932ce69c8d89a4260197faab06728dbb8c6d Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 2 Nov 2022 15:29:22 +0100 Subject: [PATCH 46/47] some pep8 changes --- tnc/data_handler.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 0acc22be..090efcfc 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -361,7 +361,7 @@ class DATA: def enqueue_frame_for_tx( self, - frame_to_tx: bytearray, + frame_to_tx: list[bytearray], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0, @@ -480,7 +480,6 @@ class DATA: # Transmit frame self.enqueue_frame_for_tx([rpt_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - def send_burst_nack_frame(self, snr: float = 0) -> None: """Build and send NACK frame for received DATA frame""" nack_frame = bytearray(self.length_sig1_frame) @@ -496,6 +495,7 @@ class DATA: # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: + """Build and send NACK frame for watchdog timeout""" nack_frame = bytearray(self.length_sig1_frame) nack_frame[:1] = bytes([FR_TYPE.BURST_NACK.value]) @@ -508,7 +508,6 @@ class DATA: # TRANSMIT NACK FRAME FOR BURST self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - def send_disconnect_frame(self) -> None: """Build and send a disconnect frame""" disconnection_frame = bytearray(self.length_sig1_frame) @@ -517,9 +516,11 @@ class DATA: # disconnection_frame[1:4] = static.DXCALLSIGN_CRC # disconnection_frame[4:7] = static.MYCALLSIGN_CRC # TODO: Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - - self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) - + # self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) + # TODO: We need to add the ident frame feature with a seperate PR after publishing latest protocol + # TODO: We need to wait some time between last arq related signalling frame and ident frame + # TODO: Maybe about 500ms - 1500ms to avoid confusion and too much PTT toggles + self.enqueue_frame_for_tx([disconnection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) def arq_data_received( self, data_in: bytes, bytes_per_frame: int, snr: float, freedv @@ -540,9 +541,9 @@ class DATA: # TODO: this seems not to work anymore # get received crc for different mycall ssids # check if callsign ssid override - #_, mycallsign = helpers.check_callsign( + # _, mycallsign = helpers.check_callsign( # self.mycallsign, data_in[2:5] - #) + # ) # attempt fixing this mycallsign = self.mycallsign @@ -590,7 +591,7 @@ class DATA: # This is the ideal case because we received all data if None not in static.RX_BURST_BUFFER: # then iterate through burst buffer and stick the burst together - # the temp burst buffer is needed for checking, if we already recevied data + # the temp burst buffer is needed for checking, if we already received data temp_burst_buffer = b"" for value in static.RX_BURST_BUFFER: # static.RX_FRAME_BUFFER += static.RX_BURST_BUFFER[i] @@ -698,7 +699,7 @@ class DATA: bof_position = static.RX_FRAME_BUFFER.find(self.data_frame_bof) eof_position = static.RX_FRAME_BUFFER.find(self.data_frame_eof) - # get total bytes per transmission information as soon we recevied a frame with a BOF + # get total bytes per transmission information as soon we received a frame with a BOF if bof_position >= 0: payload = static.RX_FRAME_BUFFER[ @@ -1071,7 +1072,7 @@ class DATA: bytesperminute=static.ARQ_BYTES_PER_MINUTE, ) - # Stay in the while loop until we receive a data_frame_ack. Otherwise + # Stay in the while loop until we receive a data_frame_ack. Otherwise, # the loop exits after sending the last frame only once and doesn't # wait for an acknowledgement. if self.data_frame_ack_received and bufferposition > len(data_out): @@ -1125,7 +1126,7 @@ class DATA: def burst_ack_nack_received(self, data_in: bytes) -> None: """ - Received a ACK/NACK for a transmitted frame, keep track and + Received an ACK/NACK for a transmitted frame, keep track and make adjustments to speed level if needed. Args: @@ -1438,8 +1439,6 @@ class DATA: self.send_disconnect_frame() self.arq_cleanup() - - def received_session_close(self, data_in: bytes): """ Closes the session when a close session frame is received and @@ -1497,7 +1496,6 @@ class DATA: self.enqueue_frame_for_tx([connection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) - def received_session_heartbeat(self, data_in: bytes) -> None: """ Received an ARQ session heartbeat, record and update state accordingly. @@ -1692,19 +1690,19 @@ class DATA: ) self.datachannel_timeout = True - # Attempt to cleanup the far-side, if it received the + # Attempt to clean up the far-side, if it received the # open_session frame and can still hear us. self.close_session() self.arq_cleanup() return False - # Shouldn't get here.. + # Shouldn't get here... return True def arq_received_data_channel_opener(self, data_in: bytes): """ - Received request to open data channel framt + Received request to open data channel frame Args: data_in:bytes: @@ -2326,7 +2324,7 @@ class DATA: static.HAMLIB_FREQUENCY, ) - # ------------ CALUCLATE TRANSFER RATES + # ------------ CALCULATE TRANSFER RATES def calculate_transfer_rate_rx( self, rx_start_of_transmission: float, receivedbytes: int ) -> list: @@ -2668,7 +2666,7 @@ class DATA: static.ARQ_SESSION and self.IS_ARQ_SESSION_MASTER and static.ARQ_SESSION_STATE == "connected" - #and not self.arq_file_transfer + # and not self.arq_file_transfer ): time.sleep(1) self.transmit_session_heartbeat() From 58dd4433259a8ad4681d8e1c984bdbb5329809bd Mon Sep 17 00:00:00 2001 From: dj2ls Date: Wed, 2 Nov 2022 22:48:50 +0100 Subject: [PATCH 47/47] added sig1 naming --- tnc/codec2.py | 3 ++- tnc/data_handler.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tnc/codec2.py b/tnc/codec2.py index dc55fccc..f9219c2f 100644 --- a/tnc/codec2.py +++ b/tnc/codec2.py @@ -23,7 +23,8 @@ class FREEDV_MODE(Enum): """ Enumeration for codec2 modes and names """ - + sig0 = 14 + sig1 = 14 datac0 = 14 datac1 = 10 datac3 = 12 diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 090efcfc..6a187719 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -435,7 +435,7 @@ class DATA: ack_frame[3:4] = bytes([int(self.speed_level)]) # Transmit frame - self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.datac0.value) + self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.sig1.value) def send_data_ack_frame(self, snr) -> None: """Build and send ACK frame for received DATA frame""" @@ -449,8 +449,8 @@ class DATA: # Transmit frame # TODO: Do we have to send , self.send_ident_frame(False) ? - # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) - self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) + # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0) + self.enqueue_frame_for_tx([ack_frame], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0) def send_retransmit_request_frame(self, freedv) -> None: # check where a None is in our burst buffer and do frame+1, because lists start at 0 @@ -478,7 +478,7 @@ class DATA: self.log.info("[TNC] ARQ | RX | Requesting", frames=missing_frames) # Transmit frame - self.enqueue_frame_for_tx([rpt_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([rpt_frame], c2_mode=FREEDV_MODE.sig1.value, copies=1, repeat_delay=0) def send_burst_nack_frame(self, snr: float = 0) -> None: """Build and send NACK frame for received DATA frame""" @@ -492,8 +492,8 @@ class DATA: # TRANSMIT NACK FRAME FOR BURST # TODO: Do we have to send ident frame? - # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=3, repeat_delay=0) - self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + # self.enqueue_frame_for_tx([ack_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.sig1.value, copies=3, repeat_delay=0) + self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.sig1.value, copies=1, repeat_delay=0) def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None: """Build and send NACK frame for watchdog timeout""" @@ -506,7 +506,7 @@ class DATA: nack_frame[3:4] = bytes([int(self.speed_level)]) # TRANSMIT NACK FRAME FOR BURST - self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.datac0.value, copies=1, repeat_delay=0) + self.enqueue_frame_for_tx([nack_frame], c2_mode=FREEDV_MODE.sig1.value, copies=1, repeat_delay=0) def send_disconnect_frame(self) -> None: """Build and send a disconnect frame""" @@ -516,11 +516,11 @@ class DATA: # disconnection_frame[1:4] = static.DXCALLSIGN_CRC # disconnection_frame[4:7] = static.MYCALLSIGN_CRC # TODO: Needed? disconnection_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - # self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) + # self.enqueue_frame_for_tx([disconnection_frame, self.send_ident_frame(False)], c2_mode=FREEDV_MODE.sig0.value, copies=5, repeat_delay=0) # TODO: We need to add the ident frame feature with a seperate PR after publishing latest protocol # TODO: We need to wait some time between last arq related signalling frame and ident frame # TODO: Maybe about 500ms - 1500ms to avoid confusion and too much PTT toggles - self.enqueue_frame_for_tx([disconnection_frame], c2_mode=FREEDV_MODE.datac0.value, copies=5, repeat_delay=0) + self.enqueue_frame_for_tx([disconnection_frame], c2_mode=FREEDV_MODE.sig0.value, copies=5, repeat_delay=0) def arq_data_received( self, data_in: bytes, bytes_per_frame: int, snr: float, freedv @@ -2070,7 +2070,7 @@ class DATA: # TODO: Not sure if we really need the session id when disconnecting # stop_frame[1:2] = self.session_id stop_frame[7:13] = helpers.callsign_to_bytes(self.mycallsign) - self.enqueue_frame_for_tx([stop_frame], c2_mode=FREEDV_MODE.datac0.value, copies=6, repeat_delay=0) + self.enqueue_frame_for_tx([stop_frame], c2_mode=FREEDV_MODE.sig1.value, copies=6, repeat_delay=0) static.TNC_STATE = "IDLE" static.ARQ_STATE = False