mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #95 from DJ2LS/ls-tnc-optimization
minor tnc changes
This commit is contained in:
commit
5365a411ff
16 changed files with 371 additions and 740 deletions
14
.github/workflows/build-project.yml
vendored
14
.github/workflows/build-project.yml
vendored
|
@ -79,9 +79,9 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-20.04]
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-20.04
|
||||||
zip_name: ubuntu_tnc
|
zip_name: ubuntu_tnc
|
||||||
generator: Unix Makefiles
|
generator: Unix Makefiles
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ jobs:
|
||||||
|
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
- name: Install Linux dependencies
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
run: |
|
run: |
|
||||||
sudo apt install portaudio19-dev libhamlib-dev libhamlib-utils build-essential cmake python3-libhamlib2
|
sudo apt install portaudio19-dev libhamlib-dev libhamlib-utils build-essential cmake python3-libhamlib2
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
|
@ -128,7 +128,7 @@ jobs:
|
||||||
|
|
||||||
|
|
||||||
- name: Build codec2 Linux
|
- name: Build codec2 Linux
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
#working-directory: tnc
|
#working-directory: tnc
|
||||||
run: |
|
run: |
|
||||||
cd ~
|
cd ~
|
||||||
|
@ -139,7 +139,7 @@ jobs:
|
||||||
|
|
||||||
|
|
||||||
- name: Build Linux
|
- name: Build Linux
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
working-directory: tnc
|
working-directory: tnc
|
||||||
run: |
|
run: |
|
||||||
#pyinstaller -F daemon.py -n daemon
|
#pyinstaller -F daemon.py -n daemon
|
||||||
|
@ -171,7 +171,7 @@ jobs:
|
||||||
node-version: 14
|
node-version: 14
|
||||||
|
|
||||||
- name: Copy TNC to GUI Linux
|
- name: Copy TNC to GUI Linux
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
run: |
|
run: |
|
||||||
cp -R ./tnc/dist ./gui/tnc
|
cp -R ./tnc/dist ./gui/tnc
|
||||||
ls -R
|
ls -R
|
||||||
|
@ -218,7 +218,7 @@ jobs:
|
||||||
release:
|
release:
|
||||||
name: Upload Release
|
name: Upload Release
|
||||||
needs: [build_linux_release, build_windows_release]
|
needs: [build_linux_release, build_windows_release]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
# FreeDATA
|
# FreeDATA
|
||||||
My attempt to create a free and opensource TNC with a GUI for [codec2](https://github.com/drowe67/codec2) to send data over HF channels.
|
My attempt to create a free and opensource TNC with a GUI for [codec2](https://github.com/drowe67/codec2) for sending data over HF channels.
|
||||||
|
|
||||||
## Under development
|
## Under development
|
||||||
This project is still a prototype and not usable at this time.
|
This project is still a prototype and not usable at this time.
|
||||||
Build steps for other OS than Ubuntu are provided, but not working, yet.
|
Build steps for other OS than Ubuntu are provided, but not working, yet.
|
||||||
|
|
||||||
|
## Preview
|
||||||
|
![preview](https://github.com/DJ2LS/FreeDATA/blob/main/documentation/FreeDATA_preview.gif?raw=true "Preview")
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
* David Rowe and the FreeDV team for developing the modem and libraries -
|
* David Rowe and the FreeDV team for developing the modem and libraries -
|
||||||
FreeDV Codec 2 : https://github.com/drowe67/codec2
|
FreeDV Codec 2 : https://github.com/drowe67/codec2
|
||||||
|
@ -13,9 +16,9 @@ xssfox : https://github.com/xssfox/freedv-tnc
|
||||||
* Wolfgang, for lending me his radio so I'm able to do real hf tests
|
* Wolfgang, for lending me his radio so I'm able to do real hf tests
|
||||||
|
|
||||||
## Running the Ubuntu app bundle
|
## Running the Ubuntu app bundle
|
||||||
Just download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies
|
Download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies
|
||||||
|
|
||||||
## Manual installation
|
## Manual installation
|
||||||
Please check the wiki for installation instructions
|
Please check the [wiki](https://github.com/DJ2LS/FreeDATA/wiki) for installation instructions
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
documentation/FreeDATA_preview.gif
Normal file
BIN
documentation/FreeDATA_preview.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
|
@ -140,14 +140,14 @@ exports.getDaemonState = function() {
|
||||||
// START TNC
|
// START TNC
|
||||||
// ` `== multi line string
|
// ` `== multi line string
|
||||||
|
|
||||||
exports.startTNC = function(rx_audio, tx_audio, deviceid, deviceport, pttprotocol, pttport, serialspeed, pttspeed, data_bits, stop_bits, handshake) {
|
exports.startTNC = function(rx_audio, tx_audio, devicename, deviceport, pttprotocol, pttport, serialspeed, pttspeed, data_bits, stop_bits, handshake) {
|
||||||
var json_command = JSON.stringify({
|
var json_command = JSON.stringify({
|
||||||
type: 'SET',
|
type: 'SET',
|
||||||
command: 'STARTTNC',
|
command: 'STARTTNC',
|
||||||
parameter: [{
|
parameter: [{
|
||||||
rx_audio: rx_audio,
|
rx_audio: rx_audio,
|
||||||
tx_audio: tx_audio,
|
tx_audio: tx_audio,
|
||||||
deviceid: deviceid,
|
devicename: devicename,
|
||||||
deviceport: deviceport,
|
deviceport: deviceport,
|
||||||
pttprotocol: pttprotocol,
|
pttprotocol: pttprotocol,
|
||||||
pttport: pttport,
|
pttport: pttport,
|
||||||
|
@ -172,13 +172,13 @@ exports.stopTNC = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST HAMLIB
|
// TEST HAMLIB
|
||||||
exports.testHamlib = function(deviceid, deviceport, serialspeed, pttprotocol, pttport, pttspeed, data_bits, stop_bits, handshake) {
|
exports.testHamlib = function(devicename, deviceport, serialspeed, pttprotocol, pttport, pttspeed, data_bits, stop_bits, handshake) {
|
||||||
|
|
||||||
var json_command = JSON.stringify({
|
var json_command = JSON.stringify({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
command: 'TEST_HAMLIB',
|
command: 'TEST_HAMLIB',
|
||||||
parameter: [{
|
parameter: [{
|
||||||
deviceid: deviceid,
|
devicename: devicename,
|
||||||
deviceport: deviceport,
|
deviceport: deviceport,
|
||||||
pttprotocol: pttprotocol,
|
pttprotocol: pttprotocol,
|
||||||
pttport: pttport,
|
pttport: pttport,
|
||||||
|
|
|
@ -332,15 +332,12 @@ advancedHamlibSettingsModal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
sock.saveMyCall(config.mycall);
|
sock.saveMyCall(config.mycall);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
sock.saveMyGrid(config.mygrid);
|
sock.saveMyGrid(config.mygrid);
|
||||||
}, 4000);
|
}, 3500);
|
||||||
})
|
})
|
||||||
|
|
||||||
// stopTNC button clicked
|
// stopTNC button clicked
|
||||||
|
@ -649,7 +646,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BEACON STATE
|
// BEACON STATE
|
||||||
console.log(arg.beacon_state)
|
|
||||||
if (arg.beacon_state == 'True') {
|
if (arg.beacon_state == 'True') {
|
||||||
document.getElementById("startBeacon").className = "btn btn-success spinner-grow"
|
document.getElementById("startBeacon").className = "btn btn-success spinner-grow"
|
||||||
document.getElementById("startBeacon").disabled = true
|
document.getElementById("startBeacon").disabled = true
|
||||||
|
@ -670,27 +666,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
|
||||||
document.getElementById("rms_level").setAttribute("aria-valuenow", arg.rms_level)
|
document.getElementById("rms_level").setAttribute("aria-valuenow", arg.rms_level)
|
||||||
document.getElementById("rms_level").setAttribute("style", "width:" + arg.rms_level + "%;")
|
document.getElementById("rms_level").setAttribute("style", "width:" + arg.rms_level + "%;")
|
||||||
|
|
||||||
// CHANNEL STATE
|
|
||||||
if (arg.channel_state == 'RECEIVING_SIGNALLING') {
|
|
||||||
document.getElementById("signalling_state").className = "btn btn-success";
|
|
||||||
document.getElementById("data_state").className = "btn btn-secondary";
|
|
||||||
|
|
||||||
} else if (arg.channel_state == 'SENDING_SIGNALLING') {
|
|
||||||
document.getElementById("signalling_state").className = "btn btn-danger";
|
|
||||||
document.getElementById("data_state").className = "btn btn-secondary";
|
|
||||||
|
|
||||||
} else if (arg.channel_state == 'RECEIVING_DATA') {
|
|
||||||
document.getElementById("signalling_state").className = "btn btn-secondary";
|
|
||||||
document.getElementById("data_state").className = "btn btn-success";
|
|
||||||
|
|
||||||
} else if (arg.channel_state == 'SENDING_DATA') {
|
|
||||||
document.getElementById("signalling_state").className = "btn btn-secondary";
|
|
||||||
document.getElementById("data_state").className = "btn btn-danger";
|
|
||||||
} else {
|
|
||||||
document.getElementById("signalling_state").className = "btn btn-secondary"
|
|
||||||
document.getElementById("busy_state").className = "btn btn-secondary"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// SET FREQUENCY
|
// SET FREQUENCY
|
||||||
document.getElementById("frequency").innerHTML = arg.frequency
|
document.getElementById("frequency").innerHTML = arg.frequency
|
||||||
|
@ -1219,7 +1194,7 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
|
||||||
|
|
||||||
var fileName = document.createElement("td");
|
var fileName = document.createElement("td");
|
||||||
var fileNameText = document.createElement('span');
|
var fileNameText = document.createElement('span');
|
||||||
var fileNameString = arg.data[i]['RXDATA'][0]['filename']
|
var fileNameString = arg.data[i]['RXDATA'][0]['fn']
|
||||||
fileNameText.innerText = fileNameString
|
fileNameText.innerText = fileNameString
|
||||||
fileName.appendChild(fileNameText);
|
fileName.appendChild(fileNameText);
|
||||||
|
|
||||||
|
@ -1247,7 +1222,7 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
|
||||||
|
|
||||||
|
|
||||||
// write file to rxdata folder
|
// write file to rxdata folder
|
||||||
var base64String = arg.data[i]['RXDATA'][0]['data']
|
var base64String = arg.data[i]['RXDATA'][0]['d']
|
||||||
// remove header from base64 String
|
// remove header from base64 String
|
||||||
// https://www.codeblocq.com/2016/04/Convert-a-base64-string-to-a-file-in-Node/
|
// https://www.codeblocq.com/2016/04/Convert-a-base64-string-to-a-file-in-Node/
|
||||||
var base64Data = base64String.split(';base64,').pop()
|
var base64Data = base64String.split(';base64,').pop()
|
||||||
|
|
|
@ -46,7 +46,7 @@ client.on('error', function(data) {
|
||||||
let Data = {
|
let Data = {
|
||||||
busy_state: "-",
|
busy_state: "-",
|
||||||
arq_state: "-",
|
arq_state: "-",
|
||||||
channel_state: "-",
|
//channel_state: "-",
|
||||||
frequency: "-",
|
frequency: "-",
|
||||||
mode: "-",
|
mode: "-",
|
||||||
bandwith: "-",
|
bandwith: "-",
|
||||||
|
@ -133,7 +133,7 @@ client.on('data', function(data) {
|
||||||
ptt_state: data['PTT_STATE'],
|
ptt_state: data['PTT_STATE'],
|
||||||
busy_state: data['TNC_STATE'],
|
busy_state: data['TNC_STATE'],
|
||||||
arq_state: data['ARQ_STATE'],
|
arq_state: data['ARQ_STATE'],
|
||||||
channel_state: data['CHANNEL_STATE'],
|
//channel_state: data['CHANNEL_STATE'],
|
||||||
frequency: data['FREQUENCY'],
|
frequency: data['FREQUENCY'],
|
||||||
mode: data['MODE'],
|
mode: data['MODE'],
|
||||||
bandwith: data['BANDWITH'],
|
bandwith: data['BANDWITH'],
|
||||||
|
|
|
@ -905,7 +905,6 @@
|
||||||
<div class="input-group input-group-sm"> <span class="input-group-text" id="basic-addon1">Frames</span>
|
<div class="input-group input-group-sm"> <span class="input-group-text" id="basic-addon1">Frames</span>
|
||||||
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="framesperburst">
|
<select class="form-select form-select-sm" aria-label=".form-select-sm" id="framesperburst">
|
||||||
<option selected value="1">1</option>
|
<option selected value="1">1</option>
|
||||||
<option value="2">2</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -973,22 +972,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group btn-group-sm" role="group" style="visibility:hidden">
|
|
||||||
<button class="btn btn-secondary" id="signalling_state" type="button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-code" viewBox="0 0 16 16">
|
|
||||||
<path fill-rule="evenodd" d="M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z" />
|
|
||||||
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z" />
|
|
||||||
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary" id="data_state" type="button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-richtext" viewBox="0 0 16 16">
|
|
||||||
<path d="M7.5 3.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm-.861 1.542 1.33.886 1.854-1.855a.25.25 0 0 1 .289-.047L11 4.75V7a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 7v-.5s1.54-1.274 1.639-1.208zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z" />
|
|
||||||
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z" />
|
|
||||||
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid" style="width:30%">
|
<div class="container-fluid" style="width:30%">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
|
|
|
@ -20,7 +20,7 @@ import serial.tools.list_ports
|
||||||
import static
|
import static
|
||||||
import crcengine
|
import crcengine
|
||||||
import re
|
import re
|
||||||
|
import rig
|
||||||
import logging, structlog, log_handler
|
import logging, structlog, log_handler
|
||||||
|
|
||||||
log_handler.setup_logging("daemon")
|
log_handler.setup_logging("daemon")
|
||||||
|
@ -153,13 +153,13 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
if received_json["type"] == 'SET' and received_json["command"] == 'STARTTNC' and not static.TNCSTARTED:
|
if received_json["type"] == 'SET' and received_json["command"] == 'STARTTNC' and not static.TNCSTARTED:
|
||||||
rx_audio = str(received_json["parameter"][0]["rx_audio"])
|
rx_audio = str(received_json["parameter"][0]["rx_audio"])
|
||||||
tx_audio = str(received_json["parameter"][0]["tx_audio"])
|
tx_audio = str(received_json["parameter"][0]["tx_audio"])
|
||||||
deviceid = str(received_json["parameter"][0]["deviceid"])
|
devicename = str(received_json["parameter"][0]["devicename"])
|
||||||
deviceport = str(received_json["parameter"][0]["deviceport"])
|
deviceport = str(received_json["parameter"][0]["deviceport"])
|
||||||
serialspeed = str(received_json["parameter"][0]["serialspeed"])
|
serialspeed = str(received_json["parameter"][0]["serialspeed"])
|
||||||
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
|
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
|
||||||
pttport = str(received_json["parameter"][0]["pttport"])
|
pttport = str(received_json["parameter"][0]["pttport"])
|
||||||
|
|
||||||
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=deviceid, port=deviceport)
|
structlog.get_logger("structlog").warning("[DMN] Starting TNC", rig=devicename, port=deviceport)
|
||||||
#print(received_json["parameter"][0])
|
#print(received_json["parameter"][0])
|
||||||
|
|
||||||
# command = "--rx "+ rx_audio +" \
|
# command = "--rx "+ rx_audio +" \
|
||||||
|
@ -178,8 +178,8 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
options.append(tx_audio)
|
options.append(tx_audio)
|
||||||
options.append('--deviceport')
|
options.append('--deviceport')
|
||||||
options.append(deviceport)
|
options.append(deviceport)
|
||||||
options.append('--deviceid')
|
options.append('--devicename')
|
||||||
options.append(deviceid)
|
options.append(devicename)
|
||||||
options.append('--serialspeed')
|
options.append('--serialspeed')
|
||||||
options.append(serialspeed)
|
options.append(serialspeed)
|
||||||
options.append('--pttprotocol')
|
options.append('--pttprotocol')
|
||||||
|
@ -276,9 +276,10 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
|
|
||||||
if received_json["type"] == 'GET' and received_json["command"] == 'TEST_HAMLIB':
|
if received_json["type"] == 'GET' and received_json["command"] == 'TEST_HAMLIB':
|
||||||
|
|
||||||
|
try:
|
||||||
print(received_json["parameter"])
|
print(received_json["parameter"])
|
||||||
|
|
||||||
deviceid = str(received_json["parameter"][0]["deviceid"])
|
devicename = str(received_json["parameter"][0]["devicename"])
|
||||||
deviceport = str(received_json["parameter"][0]["deviceport"])
|
deviceport = str(received_json["parameter"][0]["deviceport"])
|
||||||
serialspeed = str(received_json["parameter"][0]["serialspeed"])
|
serialspeed = str(received_json["parameter"][0]["serialspeed"])
|
||||||
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
|
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
|
||||||
|
@ -289,87 +290,23 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
stop_bits = str(received_json["parameter"][0]["stop_bits"])
|
stop_bits = str(received_json["parameter"][0]["stop_bits"])
|
||||||
handshake = str(received_json["parameter"][0]["handshake"])
|
handshake = str(received_json["parameter"][0]["handshake"])
|
||||||
|
|
||||||
# try to init hamlib
|
hamlib = rig.radio()
|
||||||
try:
|
hamlib.open_rig(devicename=devicename, deviceport=deviceport, hamlib_ptt_type=pttprotocol, serialspeed=serialspeed)
|
||||||
|
|
||||||
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
|
hamlib.set_ptt(True)
|
||||||
|
pttstate = hamlib.get_ptt()
|
||||||
# get devicenumber by looking for deviceobject in Hamlib module
|
if pttstate:
|
||||||
try:
|
|
||||||
devicenumber = getattr(Hamlib, deviceid)
|
|
||||||
except:
|
|
||||||
structlog.get_logger("structlog").error("[DMN] Hamlib: rig not supported...")
|
|
||||||
devicenumber = 0
|
|
||||||
|
|
||||||
|
|
||||||
my_rig = Hamlib.Rig(int(devicenumber))
|
|
||||||
my_rig.set_conf("rig_pathname", deviceport)
|
|
||||||
my_rig.set_conf("retry", "1")
|
|
||||||
my_rig.set_conf("serial_speed", serialspeed)
|
|
||||||
my_rig.set_conf("serial_handshake", handshake)
|
|
||||||
my_rig.set_conf("stop_bits", stop_bits)
|
|
||||||
my_rig.set_conf("data_bits", data_bits)
|
|
||||||
|
|
||||||
if pttprotocol == 'RIG':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
|
||||||
|
|
||||||
elif pttprotocol == 'DTR-H':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
|
||||||
my_rig.set_conf("dtr_state", "HIGH")
|
|
||||||
my_rig.set_conf("ptt_type", "DTR")
|
|
||||||
|
|
||||||
elif pttprotocol == 'DTR-L':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
|
||||||
my_rig.set_conf("dtr_state", "LOW")
|
|
||||||
my_rig.set_conf("ptt_type", "DTR")
|
|
||||||
|
|
||||||
elif pttprotocol == 'RTS':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
|
||||||
my_rig.set_conf("dtr_state", "OFF")
|
|
||||||
my_rig.set_conf("ptt_type", "RTS")
|
|
||||||
|
|
||||||
elif pttprotocol == 'PARALLEL':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
|
||||||
|
|
||||||
elif pttprotocol == 'MICDATA':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
|
||||||
|
|
||||||
elif pttprotocol == 'CM108':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
|
||||||
|
|
||||||
else: # static.HAMLIB_PTT_TYPE == 'RIG_PTT_NONE':
|
|
||||||
hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
|
||||||
|
|
||||||
|
|
||||||
my_rig.open()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# lets determine the error message when opening rig
|
|
||||||
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
|
|
||||||
error = error[1].split('err=')
|
|
||||||
error = error[1]
|
|
||||||
|
|
||||||
if error == 'Permission denied':
|
|
||||||
structlog.get_logger("structlog").error("[DMN] Hamlib has no permissions", e = error)
|
|
||||||
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions'
|
|
||||||
structlog.get_logger("structlog").error("[DMN] HELP:", check = help_url)
|
|
||||||
except:
|
|
||||||
structlog.get_logger("structlog").info("[DMN] Hamlib device openend", status='SUCCESS')
|
|
||||||
|
|
||||||
my_rig.set_ptt(hamlib_ptt_type, 1)
|
|
||||||
pttstate = my_rig.get_ptt()
|
|
||||||
if pttstate == 1:
|
|
||||||
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS')
|
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS')
|
||||||
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'SUCCESS'}
|
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'SUCCESS'}
|
||||||
elif pttstate == 0:
|
elif not pttstate:
|
||||||
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS')
|
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS')
|
||||||
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'NOSUCCESS'}
|
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'NOSUCCESS'}
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED')
|
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED')
|
||||||
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'FAILED'}
|
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'FAILED'}
|
||||||
|
|
||||||
my_rig.set_ptt(hamlib_ptt_type, 0)
|
hamlib.set_ptt(False)
|
||||||
my_rig.close
|
hamlib.close_rig()
|
||||||
|
|
||||||
jsondata = json.dumps(data)
|
jsondata = json.dumps(data)
|
||||||
self.request.sendall(bytes(jsondata, encoding))
|
self.request.sendall(bytes(jsondata, encoding))
|
||||||
|
|
|
@ -13,7 +13,6 @@ from random import randrange
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
import static
|
import static
|
||||||
import modem
|
import modem
|
||||||
import helpers
|
import helpers
|
||||||
|
@ -54,6 +53,7 @@ RX_START_OF_TRANSMISSION = 0 # time of transmission start
|
||||||
# ################################################
|
# ################################################
|
||||||
|
|
||||||
def arq_data_received(data_in, bytes_per_frame):
|
def arq_data_received(data_in, bytes_per_frame):
|
||||||
|
|
||||||
# we neeed to declare our global variables, so the thread has access to them
|
# we neeed to declare our global variables, so the thread has access to them
|
||||||
global RX_START_OF_TRANSMISSION
|
global RX_START_OF_TRANSMISSION
|
||||||
global DATA_CHANNEL_LAST_RECEIVED
|
global DATA_CHANNEL_LAST_RECEIVED
|
||||||
|
@ -92,7 +92,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
frame_progress = str(RX_N_FRAME_OF_BURST) + "/" + str(RX_N_FRAMES_PER_BURST)
|
frame_progress = str(RX_N_FRAME_OF_BURST) + "/" + str(RX_N_FRAMES_PER_BURST)
|
||||||
total_frame_progress = str(RX_N_FRAME_OF_DATA_FRAME) + "/" + str(RX_N_FRAMES_PER_DATA_FRAME)
|
total_frame_progress = str(RX_N_FRAME_OF_DATA_FRAME) + "/" + str(RX_N_FRAMES_PER_DATA_FRAME)
|
||||||
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
|
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
|
||||||
structlog.get_logger("structlog").info("[TNC] ARQ RX DATA", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress)
|
structlog.get_logger("structlog").info("[TNC] ARQ | RX | DATA FRAME", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress)
|
||||||
|
|
||||||
# allocate ARQ_static.RX_FRAME_BUFFER as a list with "None" if not already done. This should be done only once per burst!
|
# allocate ARQ_static.RX_FRAME_BUFFER as a list with "None" if not already done. This should be done only once per burst!
|
||||||
# here we will save the N frame of a data frame to N list position so we can explicit search for it
|
# here we will save the N frame of a data frame to N list position so we can explicit search for it
|
||||||
|
@ -102,10 +102,6 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
# but better doing this, to avoid problems caused by old chunks in data
|
# but better doing this, to avoid problems caused by old chunks in data
|
||||||
if RX_N_FRAME_OF_DATA_FRAME == 1:
|
if RX_N_FRAME_OF_DATA_FRAME == 1:
|
||||||
static.RX_FRAME_BUFFER = []
|
static.RX_FRAME_BUFFER = []
|
||||||
#
|
|
||||||
# # we set the start of transmission - 7 seconds, which is more or less the transfer time for the first frame
|
|
||||||
# RX_START_OF_TRANSMISSION = time.time() - 7
|
|
||||||
# calculate_transfer_rate()
|
|
||||||
|
|
||||||
#try appending data to frame buffer
|
#try appending data to frame buffer
|
||||||
try:
|
try:
|
||||||
|
@ -124,10 +120,6 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
|
|
||||||
static.RX_FRAME_BUFFER[RX_N_FRAME_OF_DATA_FRAME] = bytes(data_in)
|
static.RX_FRAME_BUFFER[RX_N_FRAME_OF_DATA_FRAME] = bytes(data_in)
|
||||||
|
|
||||||
#if RX_N_FRAME_OF_BURST == 1:
|
|
||||||
# static.ARQ_START_OF_BURST = time.time() - 6
|
|
||||||
|
|
||||||
|
|
||||||
# try appending data to burst buffer
|
# try appending data to burst buffer
|
||||||
try:
|
try:
|
||||||
static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = bytes(data_in)
|
static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = bytes(data_in)
|
||||||
|
@ -147,8 +139,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
# if we received the last burst of a data frame, we can directly send a frame ack to
|
# if we received the last burst of a data frame, we can directly send a frame ack to
|
||||||
# improve transfer rate
|
# improve transfer rate
|
||||||
if static.RX_BURST_BUFFER.count(None) == 1 and RX_N_FRAMES_PER_DATA_FRAME != RX_N_FRAME_OF_DATA_FRAME : # count nones
|
if static.RX_BURST_BUFFER.count(None) == 1 and RX_N_FRAMES_PER_DATA_FRAME != RX_N_FRAME_OF_DATA_FRAME : # count nones
|
||||||
logging.info("ARQ | TX | BURST ACK")
|
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING BURST ACK")
|
||||||
structlog.get_logger("structlog").info("[TNC] ARQ TX BURST ACK")
|
|
||||||
|
|
||||||
# BUILDING ACK FRAME FOR BURST -----------------------------------------------
|
# BUILDING ACK FRAME FOR BURST -----------------------------------------------
|
||||||
ack_frame = bytearray(14)
|
ack_frame = bytearray(14)
|
||||||
|
@ -156,14 +147,9 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
ack_frame[1:2] = static.DXCALLSIGN_CRC8
|
ack_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||||
ack_frame[2:3] = static.MYCALLSIGN_CRC8
|
ack_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||||
|
|
||||||
|
|
||||||
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
|
|
||||||
helpers.wait(0.3)
|
|
||||||
|
|
||||||
txbuffer = [ack_frame]
|
txbuffer = [ack_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
|
||||||
# clear burst buffer
|
# clear burst buffer
|
||||||
static.RX_BURST_BUFFER = []
|
static.RX_BURST_BUFFER = []
|
||||||
|
|
||||||
|
@ -182,7 +168,8 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
frame_number = frame_number.to_bytes(2, byteorder='big')
|
frame_number = frame_number.to_bytes(2, byteorder='big')
|
||||||
missing_frames += frame_number
|
missing_frames += frame_number
|
||||||
|
|
||||||
structlog.get_logger("structlog").warning("[TNC] ARQ RPT FRAMES", snr=static.SNR, frames=missing_frames)
|
structlog.get_logger("structlog").warning("[TNC] ARQ | RX | RPT FRAMES", snr=static.SNR, frames=missing_frames)
|
||||||
|
|
||||||
# BUILDING RPT FRAME FOR BURST -----------------------------------------------
|
# BUILDING RPT FRAME FOR BURST -----------------------------------------------
|
||||||
rpt_frame = bytearray(14)
|
rpt_frame = bytearray(14)
|
||||||
rpt_frame[:1] = bytes([62])
|
rpt_frame[:1] = bytes([62])
|
||||||
|
@ -192,17 +179,13 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
|
|
||||||
# TRANSMIT RPT FRAME FOR BURST-----------------------------------------------
|
# TRANSMIT RPT FRAME FOR BURST-----------------------------------------------
|
||||||
txbuffer = [rpt_frame]
|
txbuffer = [rpt_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
#while not modem.transmit_signalling(rpt_frame, 1):
|
|
||||||
# time.sleep(0.01)
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
|
||||||
|
|
||||||
# ---------------------------- FRAME MACHINE
|
# ---------------------------- FRAME MACHINE
|
||||||
# --------------- IF LIST NOT CONTAINS "None" stick everything together
|
# --------------- IF LIST NOT CONTAINS "None" stick everything together
|
||||||
complete_data_frame = bytearray()
|
complete_data_frame = bytearray()
|
||||||
if static.RX_FRAME_BUFFER.count(None) == 1: # 1 because position 0 of list will alaways be None in our case
|
if static.RX_FRAME_BUFFER.count(None) == 1: # 1 because position 0 of list will alaways be None in our case
|
||||||
logging.debug("DECODING FRAME!")
|
#logging.debug("DECODING FRAME!")
|
||||||
for frame in range(1, len(static.RX_FRAME_BUFFER)):
|
for frame in range(1, len(static.RX_FRAME_BUFFER)):
|
||||||
raw_arq_frame = static.RX_FRAME_BUFFER[frame]
|
raw_arq_frame = static.RX_FRAME_BUFFER[frame]
|
||||||
arq_frame_payload = raw_arq_frame[8:]
|
arq_frame_payload = raw_arq_frame[8:]
|
||||||
|
@ -214,7 +197,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
|
|
||||||
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_BOF)
|
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_BOF)
|
||||||
arq_frame_payload = arq_frame_payload[1]
|
arq_frame_payload = arq_frame_payload[1]
|
||||||
logging.debug("BOF")
|
#logging.debug("BOF")
|
||||||
|
|
||||||
|
|
||||||
# -------- DETECT IF WE RECEIVED A FRAME FOOTER THEN SAVE DATA TO GLOBALS
|
# -------- DETECT IF WE RECEIVED A FRAME FOOTER THEN SAVE DATA TO GLOBALS
|
||||||
|
@ -227,7 +210,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
else:
|
else:
|
||||||
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_EOF)
|
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_EOF)
|
||||||
arq_frame_payload = arq_frame_payload[0]
|
arq_frame_payload = arq_frame_payload[0]
|
||||||
logging.debug("EOF")
|
#logging.debug("EOF")
|
||||||
|
|
||||||
# --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER
|
# --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER
|
||||||
complete_data_frame = complete_data_frame + arq_frame_payload
|
complete_data_frame = complete_data_frame + arq_frame_payload
|
||||||
|
@ -241,7 +224,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
# IF THE FRAME PAYLOAD CRC IS EQUAL TO THE FRAME CRC WHICH IS KNOWN FROM THE HEADER --> SUCCESS
|
# IF THE FRAME PAYLOAD CRC IS EQUAL TO THE FRAME CRC WHICH IS KNOWN FROM THE HEADER --> SUCCESS
|
||||||
if frame_payload_crc == data_frame_crc:
|
if frame_payload_crc == data_frame_crc:
|
||||||
static.INFO.append("ARQ;RECEIVING;SUCCESS")
|
static.INFO.append("ARQ;RECEIVING;SUCCESS")
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA FRAME SUCESSFULLY RECEIVED")
|
structlog.get_logger("structlog").info("[TNC] ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED")
|
||||||
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
||||||
|
|
||||||
# decode to utf-8 string
|
# decode to utf-8 string
|
||||||
|
@ -251,14 +234,21 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
rawdata = json.loads(complete_data_frame)
|
rawdata = json.loads(complete_data_frame)
|
||||||
|
|
||||||
# if datatype is a file, we append to RX_BUFFER, which contains files only
|
# if datatype is a file, we append to RX_BUFFER, which contains files only
|
||||||
if rawdata["datatype"] == "file":
|
# dt = datatype
|
||||||
logging.info("RECEIVED FILE --> MOVING DATA TO RX BUFFER")
|
# --> f = file
|
||||||
|
# --> m = message
|
||||||
|
# fn = filename
|
||||||
|
# ft = filetype
|
||||||
|
# d = data
|
||||||
|
# crc = checksum
|
||||||
|
if rawdata["dt"] == "f":
|
||||||
|
#logging.debug("RECEIVED FILE --> MOVING DATA TO RX BUFFER")
|
||||||
static.RX_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
|
static.RX_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
|
||||||
|
|
||||||
# if datatype is a file, we append to RX_MSG_BUFFER, which contains messages only
|
# if datatype is a file, we append to RX_MSG_BUFFER, which contains messages only
|
||||||
if rawdata["datatype"] == "message":
|
if rawdata["dt"] == "m":
|
||||||
static.RX_MSG_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
|
static.RX_MSG_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
|
||||||
logging.info("RECEIVED MESSAGE --> MOVING DATA TO MESSAGE BUFFER")
|
#logging.debug("RECEIVED MESSAGE --> MOVING DATA TO MESSAGE BUFFER")
|
||||||
|
|
||||||
# BUILDING ACK FRAME FOR DATA FRAME -----------------------------------------------
|
# BUILDING ACK FRAME FOR DATA FRAME -----------------------------------------------
|
||||||
ack_frame = bytearray(14)
|
ack_frame = bytearray(14)
|
||||||
|
@ -267,17 +257,11 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
ack_frame[2:3] = static.MYCALLSIGN_CRC8
|
ack_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||||
|
|
||||||
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
|
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
|
||||||
structlog.get_logger("structlog").info("[TNC] ARQ DATA FRAME ACK", snr=static.SNR, crc=data_frame_crc.hex())
|
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING DATA FRAME ACK", snr=static.SNR, crc=data_frame_crc.hex())
|
||||||
# since simultaneous decoding it seems, we don't have to wait anymore
|
|
||||||
# however, we will wait a little bit for easier ptt debugging
|
|
||||||
# possibly we can remove this later
|
|
||||||
helpers.wait(0.5)
|
|
||||||
|
|
||||||
txbuffer = [ack_frame]
|
txbuffer = [ack_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=2, repeat_delay=250, frames=txbuffer)
|
||||||
|
|
||||||
#while not modem.transmit_signalling(ack_frame, 3):
|
|
||||||
# time.sleep(0.01)
|
|
||||||
|
|
||||||
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
||||||
|
|
||||||
|
@ -288,14 +272,14 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
static.RX_BURST_BUFFER = []
|
static.RX_BURST_BUFFER = []
|
||||||
static.RX_FRAME_BUFFER = []
|
static.RX_FRAME_BUFFER = []
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<< >>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
structlog.get_logger("structlog").info("[TNC] DATACHANNEL [" + str(static.MYCALLSIGN, 'utf-8') + "]<< >>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug("[TNC] ARQ: ", ARQ_FRAME_BOF_RECEIVED=RX_FRAME_BOF_RECEIVED, ARQ_FRAME_EOF_RECEIVED=RX_FRAME_EOF_RECEIVED )
|
structlog.get_logger("structlog").debug("[TNC] ARQ: ", ARQ_FRAME_BOF_RECEIVED=RX_FRAME_BOF_RECEIVED, ARQ_FRAME_EOF_RECEIVED=RX_FRAME_EOF_RECEIVED )
|
||||||
|
|
||||||
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
|
||||||
static.INFO.append("ARQ;RECEIVING;FAILED")
|
static.INFO.append("ARQ;RECEIVING;FAILED")
|
||||||
structlog.get_logger("structlog").warning("[TNC] ARQ: DATA FRAME NOT SUCESSFULLY RECEIVED!")
|
structlog.get_logger("structlog").warning("[TNC] ARQ | RX | DATA FRAME NOT SUCESSFULLY RECEIVED!")
|
||||||
|
|
||||||
# STATE CLEANUP
|
# STATE CLEANUP
|
||||||
#arq_reset_frame_machine()
|
#arq_reset_frame_machine()
|
||||||
|
@ -305,7 +289,7 @@ def arq_data_received(data_in, bytes_per_frame):
|
||||||
static.RX_BURST_BUFFER = []
|
static.RX_BURST_BUFFER = []
|
||||||
static.RX_FRAME_BUFFER = []
|
static.RX_FRAME_BUFFER = []
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<<X>>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
structlog.get_logger("structlog").info("[TNC] DATACHANNEL [" + str(static.MYCALLSIGN, 'utf-8') + "]<<X>>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||||
|
|
||||||
|
|
||||||
def arq_transmit(data_out, mode, n_frames_per_burst):
|
def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
|
@ -329,7 +313,7 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
TX_BUFFER = [] # our buffer for appending new data
|
TX_BUFFER = [] # our buffer for appending new data
|
||||||
|
|
||||||
# TIMEOUTS
|
# TIMEOUTS
|
||||||
BURST_ACK_TIMEOUT_SECONDS = 3.0 # timeout for burst acknowledges
|
BURST_ACK_TIMEOUT_SECONDS = 10.0 # timeout for burst acknowledges
|
||||||
DATA_FRAME_ACK_TIMEOUT_SECONDS = 10.0 # timeout for data frame acknowledges
|
DATA_FRAME_ACK_TIMEOUT_SECONDS = 10.0 # timeout for data frame acknowledges
|
||||||
RPT_ACK_TIMEOUT_SECONDS = 10.0 # timeout for rpt frame acknowledges
|
RPT_ACK_TIMEOUT_SECONDS = 10.0 # timeout for rpt frame acknowledges
|
||||||
|
|
||||||
|
@ -352,8 +336,6 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
TX_PAYLOAD_PER_ARQ_FRAME = payload_per_frame - 8
|
TX_PAYLOAD_PER_ARQ_FRAME = payload_per_frame - 8
|
||||||
frame_header_length = 6
|
frame_header_length = 6
|
||||||
|
|
||||||
#n_arq_frames_per_data_frame = (len(data_out) + frame_header_length) // TX_PAYLOAD_PER_ARQ_FRAME + ((len(data_out) + frame_header_length) % TX_PAYLOAD_PER_ARQ_FRAME > 0)
|
|
||||||
|
|
||||||
frame_payload_crc = helpers.get_crc_16(data_out)
|
frame_payload_crc = helpers.get_crc_16(data_out)
|
||||||
|
|
||||||
# This is the total frame with frame header, which will be send
|
# This is the total frame with frame header, which will be send
|
||||||
|
@ -367,7 +349,7 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
TX_BUFFER_SIZE = len(TX_BUFFER)
|
TX_BUFFER_SIZE = len(TX_BUFFER)
|
||||||
static.INFO.append("ARQ;TRANSMITTING")
|
static.INFO.append("ARQ;TRANSMITTING")
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[TNC] ARQ TX DATA", mode=DATA_CHANNEL_MODE, bytes=len(data_out), frames=TX_BUFFER_SIZE)
|
structlog.get_logger("structlog").info("[TNC] DATACHANNEL", mode=DATA_CHANNEL_MODE, bytes=len(data_out), frames=TX_BUFFER_SIZE)
|
||||||
|
|
||||||
|
|
||||||
# ----------------------- THIS IS THE MAIN LOOP-----------------------------------------------------------------
|
# ----------------------- THIS IS THE MAIN LOOP-----------------------------------------------------------------
|
||||||
|
@ -401,7 +383,7 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
total_frame_progress = str(TX_N_SENT_FRAMES) + "/" + str(TX_BUFFER_SIZE)
|
total_frame_progress = str(TX_N_SENT_FRAMES) + "/" + str(TX_BUFFER_SIZE)
|
||||||
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
|
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
|
||||||
transmission_attempts = str(TX_N_RETRIES_PER_BURST + 1) + "/" + str(TX_N_MAX_RETRIES_PER_BURST)
|
transmission_attempts = str(TX_N_RETRIES_PER_BURST + 1) + "/" + str(TX_N_MAX_RETRIES_PER_BURST)
|
||||||
structlog.get_logger("structlog").info("[TNC] ARQ TX DATA", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress, attempt=transmission_attempts)
|
structlog.get_logger("structlog").info("[TNC] ARQ | TX | DATA", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress, attempt=transmission_attempts)
|
||||||
|
|
||||||
# lets refresh all timers and ack states before sending a new frame
|
# lets refresh all timers and ack states before sending a new frame
|
||||||
arq_reset_ack(False)
|
arq_reset_ack(False)
|
||||||
|
@ -419,7 +401,6 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
n_current_arq_frame = TX_N_SENT_FRAMES + n + 1
|
n_current_arq_frame = TX_N_SENT_FRAMES + n + 1
|
||||||
n_current_arq_frame = n_current_arq_frame.to_bytes(2, byteorder='big')
|
n_current_arq_frame = n_current_arq_frame.to_bytes(2, byteorder='big')
|
||||||
n_total_arq_frame = len(TX_BUFFER)
|
n_total_arq_frame = len(TX_BUFFER)
|
||||||
#static.ARQ_TX_N_TOTAL_ARQ_FRAMES = n_total_arq_frame
|
|
||||||
|
|
||||||
arqframe = frame_type + \
|
arqframe = frame_type + \
|
||||||
bytes([TX_N_FRAMES_PER_BURST]) + \
|
bytes([TX_N_FRAMES_PER_BURST]) + \
|
||||||
|
@ -431,29 +412,25 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
|
|
||||||
tempbuffer.append(arqframe)
|
tempbuffer.append(arqframe)
|
||||||
|
|
||||||
while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, tempbuffer):
|
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
|
||||||
time.sleep(0.01)
|
|
||||||
|
|
||||||
## lets wait during sending. After sending is finished we will continue
|
|
||||||
#while static.CHANNEL_STATE == 'SENDING_DATA':
|
|
||||||
# time.sleep(0.01)
|
|
||||||
|
|
||||||
# --------------------------- START TIMER FOR WAITING FOR ACK ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1
|
# --------------------------- START TIMER FOR WAITING FOR ACK ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug("[TNC] ARQ | RX | WAITING FOR BURST ACK")
|
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | WAITING FOR BURST ACK")
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||||
|
|
||||||
burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS
|
burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS
|
||||||
# --------------------------- WHILE TIMEOUT NOT REACHED AND NO ACK RECEIVED AND IN ARQ STATE--> LISTEN
|
# --------------------------- WHILE TIMEOUT NOT REACHED AND NO ACK RECEIVED AND IN ARQ STATE--> LISTEN
|
||||||
while not BURST_ACK_RECEIVED and not RPT_REQUEST_RECEIVED and not DATA_FRAME_ACK_RECEIVED and time.time() < burstacktimeout and static.ARQ_STATE == 'DATA':
|
while not BURST_ACK_RECEIVED and not RPT_REQUEST_RECEIVED and not DATA_FRAME_ACK_RECEIVED and time.time() < burstacktimeout and static.ARQ_STATE == 'DATA':
|
||||||
time.sleep(0.01) # lets reduce CPU load a little bit
|
time.sleep(0.01) # lets reduce CPU load a little bit
|
||||||
logging.debug(static.CHANNEL_STATE)
|
logging.debug("WAITING FOR BURST ACK..")
|
||||||
|
|
||||||
# HERE WE PROCESS DATA IF WE RECEIVED ACK/RPT FRAMES OR NOT WHILE WE ARE IN ARQ STATE
|
# HERE WE PROCESS DATA IF WE RECEIVED ACK/RPT FRAMES OR NOT WHILE WE ARE IN ARQ STATE
|
||||||
# IF WE ARE NOT IN ARQ STATE, WE STOPPED THE TRANSMISSION
|
# IF WE ARE NOT IN ARQ STATE, WE STOPPED THE TRANSMISSION
|
||||||
if RPT_REQUEST_RECEIVED and static.ARQ_STATE == 'DATA':
|
if RPT_REQUEST_RECEIVED and static.ARQ_STATE == 'DATA':
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug("[TNC] ARQ | RX | REQUEST FOR REPEATING FRAMES: ",buffer=RPT_REQUEST_BUFFER)
|
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | REQUEST FOR REPEATING FRAMES: ",buffer=RPT_REQUEST_BUFFER)
|
||||||
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | SENDING REQUESTED FRAMES: ",buffer=RPT_REQUEST_BUFFER)
|
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | SENDING REQUESTED FRAMES: ",buffer=RPT_REQUEST_BUFFER)
|
||||||
# --------- BUILD RPT FRAME --------------
|
# --------- BUILD RPT FRAME --------------
|
||||||
tempbuffer = []
|
tempbuffer = []
|
||||||
|
@ -485,13 +462,7 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
|
|
||||||
tempbuffer.append(arqframe)
|
tempbuffer.append(arqframe)
|
||||||
|
|
||||||
while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, tempbuffer):
|
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
|
||||||
time.sleep(0.01)
|
|
||||||
|
|
||||||
# lets wait during sending. After sending is finished we will continue
|
|
||||||
#while static.ARQ_STATE == 'SENDING_DATA':
|
|
||||||
# time.sleep(0.01)
|
|
||||||
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
|
||||||
|
|
||||||
arq_reset_ack(False)
|
arq_reset_ack(False)
|
||||||
|
|
||||||
|
@ -537,24 +508,21 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
|
|
||||||
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
|
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
|
||||||
logging.info("ARQ | RX | ACK [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
|
logging.info("ARQ | RX | ACK [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
|
||||||
|
|
||||||
# lets wait a little bit before we are processing the next frame
|
|
||||||
helpers.wait(0.3)
|
|
||||||
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.info("--->NO RULE MATCHED OR TRANSMISSION STOPPED!")
|
logging.debug("--->NO RULE MATCHED OR TRANSMISSION STOPPED!")
|
||||||
print("ARQ_ACK_RECEIVED " + str(BURST_ACK_RECEIVED))
|
logging.debug("ARQ_ACK_RECEIVED " + str(BURST_ACK_RECEIVED))
|
||||||
|
logging.debug(f"TX_N_SENT_FRAMES: {TX_N_SENT_FRAMES}") # SENT FRAMES WILL INCREMENT AFTER ACK RECEIVED!
|
||||||
|
logging.debug(f"TX_BUFFER_SIZE: {TX_BUFFER_SIZE}")
|
||||||
|
logging.debug(f"DATA_FRAME_ACK_RECEIVED: {DATA_FRAME_ACK_RECEIVED}")
|
||||||
break
|
break
|
||||||
|
|
||||||
# --------------------------------WAITING AREA FOR FRAME ACKs
|
# --------------------------------WAITING AREA FOR FRAME ACKs
|
||||||
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
|
||||||
|
|
||||||
frameacktimeout = time.time() + DATA_FRAME_ACK_TIMEOUT_SECONDS
|
frameacktimeout = time.time() + DATA_FRAME_ACK_TIMEOUT_SECONDS
|
||||||
# wait for frame ACK if we processed the last frame/burst
|
# wait for frame ACK if we processed the last frame/burst
|
||||||
|
|
||||||
while not DATA_FRAME_ACK_RECEIVED and time.time() < frameacktimeout and TX_N_SENT_FRAMES == TX_BUFFER_SIZE:
|
while not DATA_FRAME_ACK_RECEIVED and time.time() < frameacktimeout and TX_N_SENT_FRAMES == TX_BUFFER_SIZE:
|
||||||
time.sleep(0.01) # lets reduce CPU load a little bit
|
time.sleep(0.01) # lets reduce CPU load a little bit
|
||||||
logging.debug("WAITING FOR FRAME ACK")
|
logging.debug("WAITING FOR FRAME ACK")
|
||||||
|
@ -567,10 +535,9 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
|
||||||
|
|
||||||
# -------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT AND WE GOT A FRAME ACK
|
# -------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT AND WE GOT A FRAME ACK
|
||||||
elif TX_N_SENT_FRAMES == TX_BUFFER_SIZE and DATA_FRAME_ACK_RECEIVED:
|
elif TX_N_SENT_FRAMES == TX_BUFFER_SIZE and DATA_FRAME_ACK_RECEIVED:
|
||||||
print(TX_N_SENT_FRAMES)
|
|
||||||
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
|
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
|
||||||
static.INFO.append("ARQ;TRANSMITTING;SUCCESS")
|
static.INFO.append("ARQ;TRANSMITTING;SUCCESS")
|
||||||
logging.log(25, "ARQ | RX | FRAME ACK! - DATA TRANSMITTED! [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
|
logging.info("ARQ | RX | FRAME ACK! - DATA TRANSMITTED! [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
|
||||||
break
|
break
|
||||||
|
|
||||||
elif not DATA_FRAME_ACK_RECEIVED and time.time() > frameacktimeout:
|
elif not DATA_FRAME_ACK_RECEIVED and time.time() > frameacktimeout:
|
||||||
|
@ -651,19 +618,13 @@ def burst_rpt_received(data_in):
|
||||||
def open_dc_and_transmit(data_out, mode, n_frames_per_burst):
|
def open_dc_and_transmit(data_out, mode, n_frames_per_burst):
|
||||||
global DATA_CHANNEL_READY_FOR_DATA
|
global DATA_CHANNEL_READY_FOR_DATA
|
||||||
|
|
||||||
|
static.TNC_STATE = 'BUSY'
|
||||||
|
|
||||||
asyncio.run(arq_open_data_channel(mode))
|
asyncio.run(arq_open_data_channel(mode))
|
||||||
# wait until data channel is open
|
# wait until data channel is open
|
||||||
while not DATA_CHANNEL_READY_FOR_DATA:
|
while not DATA_CHANNEL_READY_FOR_DATA:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
# lets wait a little bit so RX station is ready for receiving
|
|
||||||
#wait_before_data_timer = time.time() + 0.8
|
|
||||||
#while time.time() < wait_before_data_timer:
|
|
||||||
# pass
|
|
||||||
helpers.wait(0.8)
|
|
||||||
|
|
||||||
|
|
||||||
# transmit data
|
|
||||||
arq_transmit(data_out, mode, n_frames_per_burst)
|
arq_transmit(data_out, mode, n_frames_per_burst)
|
||||||
|
|
||||||
|
|
||||||
|
@ -694,8 +655,7 @@ async def arq_open_data_channel(mode):
|
||||||
|
|
||||||
|
|
||||||
txbuffer = [connection_frame]
|
txbuffer = [connection_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
|
|
||||||
timeout = time.time() + 3
|
timeout = time.time() + 3
|
||||||
while time.time() < timeout:
|
while time.time() < timeout:
|
||||||
|
@ -742,14 +702,10 @@ def arq_received_data_channel_opener(data_in):
|
||||||
connection_frame[12:13] = bytes([mode])
|
connection_frame[12:13] = bytes([mode])
|
||||||
|
|
||||||
txbuffer = [connection_frame]
|
txbuffer = [connection_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, mode=mode)
|
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, mode=mode)
|
||||||
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
|
||||||
# and now we are going to "RECEIVING_DATA" mode....
|
|
||||||
|
|
||||||
|
|
||||||
def arq_received_channel_is_open(data_in):
|
def arq_received_channel_is_open(data_in):
|
||||||
|
|
||||||
global DATA_CHANNEL_LAST_RECEIVED
|
global DATA_CHANNEL_LAST_RECEIVED
|
||||||
|
@ -768,18 +724,12 @@ def arq_received_channel_is_open(data_in):
|
||||||
if DATA_CHANNEL_MODE == int.from_bytes(bytes(data_in[12:13]), "big"):
|
if DATA_CHANNEL_MODE == int.from_bytes(bytes(data_in[12:13]), "big"):
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
|
||||||
|
|
||||||
# wait a little bit so other station is ready ( PTT toggle )
|
|
||||||
print("wait.....")
|
|
||||||
print(time.time())
|
|
||||||
helpers.wait(0.5)
|
|
||||||
print(time.time())
|
|
||||||
# as soon as we set ARQ_STATE to DATA, transmission starts
|
# as soon as we set ARQ_STATE to DATA, transmission starts
|
||||||
static.ARQ_STATE = 'DATA'
|
static.ARQ_STATE = 'DATA'
|
||||||
DATA_CHANNEL_READY_FOR_DATA = True
|
DATA_CHANNEL_READY_FOR_DATA = True
|
||||||
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
|
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, info="wrong mode rcvd")
|
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, info="wrong mode rcvd")
|
||||||
helpers.wait(0.5)
|
|
||||||
# as soon as we set ARQ_STATE to DATA, transmission starts
|
# as soon as we set ARQ_STATE to DATA, transmission starts
|
||||||
static.ARQ_STATE = 'DATA'
|
static.ARQ_STATE = 'DATA'
|
||||||
DATA_CHANNEL_READY_FOR_DATA = True
|
DATA_CHANNEL_READY_FOR_DATA = True
|
||||||
|
@ -803,8 +753,7 @@ def transmit_ping(callsign):
|
||||||
ping_frame[3:9] = static.MYCALLSIGN
|
ping_frame[3:9] = static.MYCALLSIGN
|
||||||
|
|
||||||
txbuffer = [ping_frame]
|
txbuffer = [ping_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
|
|
||||||
def received_ping(data_in, frequency_offset):
|
def received_ping(data_in, frequency_offset):
|
||||||
|
|
||||||
|
@ -824,7 +773,7 @@ def received_ping(data_in, frequency_offset):
|
||||||
ping_frame[9:11] = frequency_offset.to_bytes(2, byteorder='big', signed=True)
|
ping_frame[9:11] = frequency_offset.to_bytes(2, byteorder='big', signed=True)
|
||||||
|
|
||||||
txbuffer = [ping_frame]
|
txbuffer = [ping_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
def received_ping_ack(data_in):
|
def received_ping_ack(data_in):
|
||||||
|
|
||||||
|
@ -858,8 +807,7 @@ def run_beacon(interval):
|
||||||
structlog.get_logger("structlog").info("[TNC] Sending beacon!", interval=interval)
|
structlog.get_logger("structlog").info("[TNC] Sending beacon!", interval=interval)
|
||||||
|
|
||||||
txbuffer = [beacon_frame]
|
txbuffer = [beacon_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
|
||||||
|
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
|
@ -890,8 +838,8 @@ def transmit_cq():
|
||||||
cq_frame[8:14] = static.MYGRID
|
cq_frame[8:14] = static.MYGRID
|
||||||
|
|
||||||
txbuffer = [cq_frame]
|
txbuffer = [cq_frame]
|
||||||
modem.transmit('datac0', 1, txbuffer)
|
modem.transmit(mode=14, repeats=1, repeat_delay=1000, frames=txbuffer)
|
||||||
#while not modem.transmit('datac0', 1, txbuffer):
|
#while not modem.transmit(14, 1, txbuffer):
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -1008,7 +956,7 @@ def watchdog():
|
||||||
watchdog master function. Frome here we call the watchdogs
|
watchdog master function. Frome here we call the watchdogs
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
time.sleep(0.01)
|
time.sleep(0.5)
|
||||||
data_channel_keep_alive_watchdog()
|
data_channel_keep_alive_watchdog()
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
40
tnc/main.py
40
tnc/main.py
|
@ -28,8 +28,8 @@ if __name__ == '__main__':
|
||||||
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int)
|
PARSER.add_argument('--rx', dest="audio_input_device", default=0, help="listening sound card", type=int)
|
||||||
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
PARSER.add_argument('--tx', dest="audio_output_device", default=0, help="transmitting sound card", type=int)
|
||||||
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port", type=int)
|
PARSER.add_argument('--port', dest="socket_port", default=3000, help="Socket port", type=int)
|
||||||
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Socket port", type=str)
|
PARSER.add_argument('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Hamlib device port", type=str)
|
||||||
PARSER.add_argument('--deviceid', dest="hamlib_device_id", default=2028, help="Socket port", type=str)
|
PARSER.add_argument('--devicename', dest="hamlib_device_name", default=2028, help="Hamlib device name", type=str)
|
||||||
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", default=9600, help="Serialspeed", type=str)
|
PARSER.add_argument('--serialspeed', dest="hamlib_serialspeed", default=9600, help="Serialspeed", type=str)
|
||||||
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", default='RTS', help="PTT Type", type=str)
|
PARSER.add_argument('--pttprotocol', dest="hamlib_ptt_type", default='RTS', help="PTT Type", type=str)
|
||||||
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
PARSER.add_argument('--pttport', dest="hamlib_ptt_port", default="/dev/ttyUSB0", help="PTT Port", type=str)
|
||||||
|
@ -39,10 +39,10 @@ if __name__ == '__main__':
|
||||||
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
||||||
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
||||||
static.PORT = ARGS.socket_port
|
static.PORT = ARGS.socket_port
|
||||||
static.HAMLIB_DEVICE_ID = ARGS.hamlib_device_id
|
static.HAMLIB_DEVICE_NAME = ARGS.hamlib_device_name
|
||||||
static.HAMLIB_DEVICE_PORT = ARGS.hamlib_device_port
|
static.HAMLIB_DEVICE_PORT = ARGS.hamlib_device_port
|
||||||
static.HAMLIB_PTT_TYPE = ARGS.hamlib_ptt_type
|
static.HAMLIB_PTT_TYPE = ARGS.hamlib_ptt_type
|
||||||
HAMLIB_PTT_PORT = ARGS.hamlib_ptt_port
|
static.HAMLIB_PTT_PORT = ARGS.hamlib_ptt_port
|
||||||
static.HAMLIB_SERIAL_SPEED = ARGS.hamlib_serialspeed
|
static.HAMLIB_SERIAL_SPEED = ARGS.hamlib_serialspeed
|
||||||
|
|
||||||
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
||||||
|
@ -60,35 +60,3 @@ if __name__ == '__main__':
|
||||||
CMD_SERVER_THREAD = threading.Thread(target=sock.start_cmd_socket, name="cmd server")
|
CMD_SERVER_THREAD = threading.Thread(target=sock.start_cmd_socket, name="cmd server")
|
||||||
CMD_SERVER_THREAD.start()
|
CMD_SERVER_THREAD.start()
|
||||||
|
|
||||||
'''
|
|
||||||
# Start RIGCTLD
|
|
||||||
|
|
||||||
if static.HAMLIB_PTT_TYPE == "RTS":
|
|
||||||
dtr_state = "OFF"
|
|
||||||
else:
|
|
||||||
dtr_state = "NONE"
|
|
||||||
|
|
||||||
if sys.platform == "linux":
|
|
||||||
command = "exec ./hamlib/linux/rigctld -r " + str(static.HAMLIB_DEVICE_PORT) + \
|
|
||||||
" -s "+ str(static.HAMLIB_SERIAL_SPEED) + \
|
|
||||||
" -P "+ str(static.HAMLIB_PTT_TYPE) + \
|
|
||||||
" -m "+ str(static.HAMLIB_DEVICE_ID) + \
|
|
||||||
" --set-conf=dtr_state=" + dtr_state
|
|
||||||
try:
|
|
||||||
p = subprocess.Popen(command, shell=True)
|
|
||||||
except:
|
|
||||||
print("hamlib not started")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
print("platform not yet supported")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
elif sys.platform == "win32":
|
|
||||||
print("platform not yet supported")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("platform not supported!")
|
|
||||||
sys.exit()
|
|
||||||
'''
|
|
||||||
|
|
367
tnc/modem.py
367
tnc/modem.py
|
@ -21,6 +21,7 @@ import data_handler
|
||||||
import re
|
import re
|
||||||
import queue
|
import queue
|
||||||
import codec2
|
import codec2
|
||||||
|
import rig
|
||||||
|
|
||||||
# option for testing miniaudio instead of audioop for sample rate conversion
|
# option for testing miniaudio instead of audioop for sample rate conversion
|
||||||
#import miniaudio
|
#import miniaudio
|
||||||
|
@ -54,29 +55,6 @@ def noalsaerr():
|
||||||
# p = pyaudio.PyAudio()
|
# p = pyaudio.PyAudio()
|
||||||
######################################################
|
######################################################
|
||||||
|
|
||||||
# try importing hamlib
|
|
||||||
try:
|
|
||||||
# get python version
|
|
||||||
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
|
||||||
|
|
||||||
# installation path for Ubuntu 20.04 LTS python modules
|
|
||||||
sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
|
||||||
# installation path for Ubuntu 20.10 +
|
|
||||||
sys.path.append('/usr/local/lib/')
|
|
||||||
import Hamlib
|
|
||||||
|
|
||||||
# https://stackoverflow.com/a/4703409
|
|
||||||
hamlib_version = re.findall(r"[-+]?\d*\.?\d+|\d+", Hamlib.cvar.hamlib_version)
|
|
||||||
hamlib_version = float(hamlib_version[0])
|
|
||||||
|
|
||||||
min_hamlib_version = 4.1
|
|
||||||
if hamlib_version > min_hamlib_version:
|
|
||||||
structlog.get_logger("structlog").info("[TNC] Hamlib found", version=hamlib_version)
|
|
||||||
else:
|
|
||||||
structlog.get_logger("structlog").warning("[TNC] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
|
||||||
except Exception as e:
|
|
||||||
structlog.get_logger("structlog").critical("[TNC] Hamlib not found", error=e)
|
|
||||||
|
|
||||||
|
|
||||||
MODEM_STATS_NR_MAX = 320
|
MODEM_STATS_NR_MAX = 320
|
||||||
MODEM_STATS_NC_MAX = 51
|
MODEM_STATS_NC_MAX = 51
|
||||||
|
@ -124,6 +102,8 @@ class RF():
|
||||||
# init FIFO queue to store modulation out in
|
# init FIFO queue to store modulation out in
|
||||||
self.modoutqueue = queue.Queue()
|
self.modoutqueue = queue.Queue()
|
||||||
|
|
||||||
|
# define fft_data buffer
|
||||||
|
self.fft_data = bytes()
|
||||||
|
|
||||||
# open codec2 instance
|
# open codec2 instance
|
||||||
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
|
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
|
||||||
|
@ -185,90 +165,31 @@ class RF():
|
||||||
output=True,
|
output=True,
|
||||||
input_device_index=static.AUDIO_INPUT_DEVICE,
|
input_device_index=static.AUDIO_INPUT_DEVICE,
|
||||||
output_device_index=static.AUDIO_OUTPUT_DEVICE,
|
output_device_index=static.AUDIO_OUTPUT_DEVICE,
|
||||||
stream_callback=self.callback
|
stream_callback=self.audio_callback
|
||||||
)
|
)
|
||||||
|
|
||||||
# not needed anymore.
|
|
||||||
#self.streambuffer = bytes(0)
|
# --------------------------------------------INIT AND OPEN HAMLIB
|
||||||
|
self.hamlib = rig.radio()
|
||||||
|
self.hamlib.open_rig(devicename=static.HAMLIB_DEVICE_NAME, deviceport=static.HAMLIB_DEVICE_PORT, hamlib_ptt_type=static.HAMLIB_PTT_TYPE, serialspeed=static.HAMLIB_SERIAL_SPEED)
|
||||||
|
|
||||||
# --------------------------------------------START DECODER THREAD
|
# --------------------------------------------START DECODER THREAD
|
||||||
|
|
||||||
|
FFT_THREAD = threading.Thread(target=self.calculate_fft, name="FFT_THREAD")
|
||||||
|
FFT_THREAD.start()
|
||||||
|
|
||||||
AUDIO_THREAD = threading.Thread(target=self.audio, name="AUDIO_THREAD")
|
AUDIO_THREAD = threading.Thread(target=self.audio, name="AUDIO_THREAD")
|
||||||
AUDIO_THREAD.start()
|
AUDIO_THREAD.start()
|
||||||
|
|
||||||
|
HAMLIB_THREAD = threading.Thread(target=self.update_rig_data, name="HAMLIB_THREAD")
|
||||||
|
HAMLIB_THREAD.start()
|
||||||
|
|
||||||
WORKER_THREAD = threading.Thread(target=self.worker, name="WORKER_THREAD")
|
WORKER_THREAD = threading.Thread(target=self.worker, name="WORKER_THREAD")
|
||||||
WORKER_THREAD.start()
|
WORKER_THREAD.start()
|
||||||
|
|
||||||
self.fft_data = bytes()
|
|
||||||
FFT_THREAD = threading.Thread(target=self.calculate_fft, name="FFT_THREAD")
|
|
||||||
FFT_THREAD.start()
|
|
||||||
|
|
||||||
# --------------------------------------------CONFIGURE HAMLIB
|
|
||||||
# try to init hamlib
|
|
||||||
try:
|
|
||||||
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
|
|
||||||
|
|
||||||
# get devicenumber by looking for deviceobject in Hamlib module
|
|
||||||
try:
|
|
||||||
devicenumber = getattr(Hamlib, static.HAMLIB_DEVICE_ID)
|
|
||||||
except:
|
|
||||||
structlog.get_logger("structlog").error("[DMN] Hamlib: rig not supported...")
|
|
||||||
devicenumber = 0
|
|
||||||
|
|
||||||
self.my_rig = Hamlib.Rig(int(devicenumber))
|
|
||||||
self.my_rig.set_conf("rig_pathname", static.HAMLIB_DEVICE_PORT)
|
|
||||||
self.my_rig.set_conf("retry", "5")
|
|
||||||
self.my_rig.set_conf("serial_speed", static.HAMLIB_SERIAL_SPEED)
|
|
||||||
self.my_rig.set_conf("serial_handshake", "None")
|
|
||||||
self.my_rig.set_conf("stop_bits", "1")
|
|
||||||
self.my_rig.set_conf("data_bits", "8")
|
|
||||||
|
|
||||||
if static.HAMLIB_PTT_TYPE == 'RIG':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'DTR-H':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
|
||||||
self.my_rig.set_conf("dtr_state", "HIGH")
|
|
||||||
self.my_rig.set_conf("ptt_type", "DTR")
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'DTR-L':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
|
||||||
self.my_rig.set_conf("dtr_state", "LOW")
|
|
||||||
self.my_rig.set_conf("ptt_type", "DTR")
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'RTS':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
|
||||||
self.my_rig.set_conf("dtr_state", "OFF")
|
|
||||||
self.my_rig.set_conf("ptt_type", "RTS")
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'PARALLEL':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'MICDATA':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
|
||||||
|
|
||||||
elif static.HAMLIB_PTT_TYPE == 'CM108':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
|
||||||
|
|
||||||
else: # static.HAMLIB_PTT_TYPE == 'RIG_PTT_NONE':
|
|
||||||
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
|
||||||
|
|
||||||
self.my_rig.open()
|
|
||||||
atexit.register(self.my_rig.close)
|
|
||||||
|
|
||||||
# set rig mode to USB
|
|
||||||
self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
|
||||||
|
|
||||||
# start thread for getting hamlib data
|
|
||||||
HAMLIB_THREAD = threading.Thread(target=self.get_radio_stats, name="HAMLIB_THREAD")
|
|
||||||
HAMLIB_THREAD.start()
|
|
||||||
|
|
||||||
except:
|
|
||||||
structlog.get_logger("structlog").error("[TNC] Hamlib - can't open rig", e=sys.exc_info()[0])
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
def callback(self, data_in48k, frame_count, time_info, status):
|
def audio_callback(self, data_in48k, frame_count, time_info, status):
|
||||||
|
|
||||||
x = np.frombuffer(data_in48k, dtype=np.int16)
|
x = np.frombuffer(data_in48k, dtype=np.int16)
|
||||||
x = self.resampler.resample48_to_8(x)
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
@ -276,12 +197,8 @@ class RF():
|
||||||
self.datac0_buffer.push(x)
|
self.datac0_buffer.push(x)
|
||||||
self.datac1_buffer.push(x)
|
self.datac1_buffer.push(x)
|
||||||
self.datac3_buffer.push(x)
|
self.datac3_buffer.push(x)
|
||||||
|
|
||||||
# refill fft_data buffer so we can plot a fft
|
|
||||||
if len(self.fft_data) < 1024:
|
|
||||||
self.fft_data += bytes(x)
|
self.fft_data += bytes(x)
|
||||||
|
|
||||||
|
|
||||||
if self.modoutqueue.empty():
|
if self.modoutqueue.empty():
|
||||||
data_out48k = bytes(self.AUDIO_FRAMES_PER_BUFFER_TX*2*2)
|
data_out48k = bytes(self.AUDIO_FRAMES_PER_BUFFER_TX*2*2)
|
||||||
else:
|
else:
|
||||||
|
@ -289,41 +206,14 @@ class RF():
|
||||||
|
|
||||||
return (data_out48k, pyaudio.paContinue)
|
return (data_out48k, pyaudio.paContinue)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ptt_and_wait(self, state):
|
|
||||||
static.PTT_STATE = state
|
|
||||||
|
|
||||||
if state:
|
|
||||||
|
|
||||||
self.my_rig.set_ptt(self.hamlib_ptt_type, 1)
|
|
||||||
# rigctld.ptt_enable()
|
|
||||||
ptt_toggle_timeout = time.time() + 0.5
|
|
||||||
|
|
||||||
while time.time() < ptt_toggle_timeout and not self.modoutqueue.empty():
|
|
||||||
pass
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
ptt_toggle_timeout = time.time() + 0.5
|
|
||||||
while time.time() < ptt_toggle_timeout:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.my_rig.set_ptt(self.hamlib_ptt_type, 0)
|
|
||||||
# rigctld.ptt_disable()
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def transmit(self, mode, count, frames):
|
def transmit(self, mode, repeats, repeat_delay, frames):
|
||||||
|
|
||||||
state_before_transmit = static.CHANNEL_STATE
|
|
||||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
|
||||||
|
|
||||||
# open codec2 instance
|
# open codec2 instance
|
||||||
self.MODE = codec2.FREEDV_MODE[mode].value
|
#self.MODE = codec2.freedv_get_mode_value_by_name(mode)
|
||||||
|
self.MODE = mode
|
||||||
freedv = cast(codec2.api.freedv_open(self.MODE), c_void_p)
|
freedv = cast(codec2.api.freedv_open(self.MODE), c_void_p)
|
||||||
|
|
||||||
# get number of bytes per frame for mode
|
# get number of bytes per frame for mode
|
||||||
|
@ -342,18 +232,22 @@ class RF():
|
||||||
n_tx_postamble_modem_samples = codec2.api.freedv_get_n_tx_postamble_modem_samples(freedv)
|
n_tx_postamble_modem_samples = codec2.api.freedv_get_n_tx_postamble_modem_samples(freedv)
|
||||||
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
|
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
|
||||||
|
|
||||||
|
# add empty data to handle ptt toggle time
|
||||||
|
data_delay_seconds = 250
|
||||||
|
data_delay = int(self.MODEM_SAMPLE_RATE*(data_delay_seconds/1000))
|
||||||
|
mod_out_silence = create_string_buffer(data_delay*2)
|
||||||
|
txbuffer = bytes(mod_out_silence)
|
||||||
|
|
||||||
|
for i in range(1,repeats+1):
|
||||||
for i in range(1,count+1):
|
|
||||||
|
|
||||||
# write preamble to txbuffer
|
# write preamble to txbuffer
|
||||||
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||||
txbuffer = bytes(mod_out_preamble)
|
time.sleep(0.01)
|
||||||
|
txbuffer += bytes(mod_out_preamble)
|
||||||
|
|
||||||
# create modulaton for n frames in list
|
# create modulaton for n frames in list
|
||||||
for n in range(0,len(frames)):
|
for n in range(0,len(frames)):
|
||||||
|
|
||||||
|
|
||||||
# create buffer for data
|
# create buffer for data
|
||||||
buffer = bytearray(payload_bytes_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
|
buffer = bytearray(payload_bytes_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
|
||||||
buffer[:len(frames[n])] = frames[n] # set buffersize to length of data which will be send
|
buffer[:len(frames[n])] = frames[n] # set buffersize to length of data which will be send
|
||||||
|
@ -366,13 +260,19 @@ class RF():
|
||||||
|
|
||||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||||
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer
|
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer
|
||||||
|
time.sleep(0.01)
|
||||||
txbuffer += bytes(mod_out)
|
txbuffer += bytes(mod_out)
|
||||||
|
|
||||||
|
|
||||||
# append postamble to txbuffer
|
# append postamble to txbuffer
|
||||||
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||||
txbuffer += bytes(mod_out_postamble)
|
txbuffer += bytes(mod_out_postamble)
|
||||||
|
time.sleep(0.01)
|
||||||
|
# add delay to end of frames
|
||||||
|
samples_delay = int(self.MODEM_SAMPLE_RATE*(repeat_delay/1000))
|
||||||
|
mod_out_silence = create_string_buffer(samples_delay*2)
|
||||||
|
txbuffer += bytes(mod_out_silence)
|
||||||
|
time.sleep(0.01)
|
||||||
|
|
||||||
# resample up to 48k (resampler works on np.int16)
|
# resample up to 48k (resampler works on np.int16)
|
||||||
x = np.frombuffer(txbuffer, dtype=np.int16)
|
x = np.frombuffer(txbuffer, dtype=np.int16)
|
||||||
|
@ -389,167 +289,17 @@ class RF():
|
||||||
if len(c) < self.AUDIO_FRAMES_PER_BUFFER_RX*2:
|
if len(c) < self.AUDIO_FRAMES_PER_BUFFER_RX*2:
|
||||||
c += bytes(self.AUDIO_FRAMES_PER_BUFFER_RX*2 - len(c))
|
c += bytes(self.AUDIO_FRAMES_PER_BUFFER_RX*2 - len(c))
|
||||||
self.modoutqueue.put(c)
|
self.modoutqueue.put(c)
|
||||||
print(len(c))
|
|
||||||
|
|
||||||
while self.ptt_and_wait(True):
|
# maybe we need to toggle PTT before craeting modulation because of queue processing
|
||||||
|
static.PTT_STATE = self.hamlib.set_ptt(True)
|
||||||
|
while not self.modoutqueue.empty():
|
||||||
pass
|
pass
|
||||||
|
static.PTT_STATE = self.hamlib.set_ptt(False)
|
||||||
|
|
||||||
# set channel state
|
|
||||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
|
||||||
|
|
||||||
# set ptt back to false
|
|
||||||
self.ptt_and_wait(False)
|
|
||||||
|
|
||||||
|
|
||||||
# we have a problem with the receiving state
|
|
||||||
if state_before_transmit != 'RECEIVING_DATA':
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
|
||||||
else:
|
|
||||||
static.CHANNEL_STATE = state_before_transmit
|
|
||||||
|
|
||||||
self.c_lib.freedv_close(freedv)
|
self.c_lib.freedv_close(freedv)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
def transmit_signalling(self, data_out, count):
|
|
||||||
state_before_transmit = static.CHANNEL_STATE
|
|
||||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
|
||||||
|
|
||||||
mod_out = create_string_buffer(self.datac0_n_tx_modem_samples * 2)
|
|
||||||
mod_out_preamble = create_string_buffer(self.datac0_n_tx_preamble_modem_samples * 2)
|
|
||||||
mod_out_postamble = create_string_buffer(self.datac0_n_tx_postamble_modem_samples * 2)
|
|
||||||
|
|
||||||
buffer = bytearray(self.datac0_payload_per_frame)
|
|
||||||
# set buffersize to length of data which will be send
|
|
||||||
buffer[:len(data_out)] = data_out
|
|
||||||
|
|
||||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), self.datac0_payload_per_frame)) # generate CRC16
|
|
||||||
# convert crc to 2 byte hex string
|
|
||||||
crc = crc.value.to_bytes(2, byteorder='big')
|
|
||||||
buffer += crc # append crc16 to buffer
|
|
||||||
data = (ctypes.c_ubyte * self.datac0_bytes_per_frame).from_buffer_copy(buffer)
|
|
||||||
|
|
||||||
# modulate DATA and safe it into mod_out pointer
|
|
||||||
self.c_lib.freedv_rawdatapreambletx(self.datac0_freedv, mod_out_preamble)
|
|
||||||
self.c_lib.freedv_rawdatatx(self.datac0_freedv, mod_out, data)
|
|
||||||
self.c_lib.freedv_rawdatapostambletx(self.datac0_freedv, mod_out_postamble)
|
|
||||||
|
|
||||||
self.streambuffer = bytearray()
|
|
||||||
self.streambuffer += bytes(mod_out_preamble)
|
|
||||||
self.streambuffer += bytes(mod_out)
|
|
||||||
self.streambuffer += bytes(mod_out_postamble)
|
|
||||||
|
|
||||||
# resample up to 48k (resampler works on np.int16)
|
|
||||||
x = np.frombuffer(self.streambuffer, dtype=np.int16)
|
|
||||||
txbuffer_48k = self.resampler.resample8_to_48(x)
|
|
||||||
|
|
||||||
|
|
||||||
# append frame again with as much as in count defined
|
|
||||||
#for i in range(1, count):
|
|
||||||
# self.streambuffer += bytes(txbuffer_48k.tobytes())
|
|
||||||
|
|
||||||
while self.ptt_and_wait(True):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# set channel state
|
|
||||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
|
||||||
|
|
||||||
# start writing audio data to audio stream
|
|
||||||
#self.stream_tx.write(self.streambuffer)
|
|
||||||
self.stream_tx.write(txbuffer_48k.tobytes())
|
|
||||||
|
|
||||||
|
|
||||||
# set ptt back to false
|
|
||||||
self.ptt_and_wait(False)
|
|
||||||
|
|
||||||
|
|
||||||
# we have a problem with the receiving state
|
|
||||||
if state_before_transmit != 'RECEIVING_DATA':
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
|
||||||
else:
|
|
||||||
static.CHANNEL_STATE = state_before_transmit
|
|
||||||
|
|
||||||
return True
|
|
||||||
# --------------------------------------------------------------------------------------------------------
|
|
||||||
# GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT
|
|
||||||
|
|
||||||
def transmit_arq_burst(self, mode, frames):
|
|
||||||
|
|
||||||
# we could place this timing part inside the modem...
|
|
||||||
# lets see if this is a good idea..
|
|
||||||
# we need to update our timeout timestamp
|
|
||||||
|
|
||||||
state_before_transmit = static.CHANNEL_STATE
|
|
||||||
static.CHANNEL_STATE = 'SENDING_DATA'
|
|
||||||
|
|
||||||
freedv = cast(self.c_lib.freedv_open(mode), c_void_p)
|
|
||||||
self.c_lib.freedv_set_clip(freedv, 1)
|
|
||||||
self.c_lib.freedv_set_tx_bpf(freedv, 1)
|
|
||||||
|
|
||||||
bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv) / 8)
|
|
||||||
payload_per_frame = bytes_per_frame - 2
|
|
||||||
n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(freedv)
|
|
||||||
n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(freedv)
|
|
||||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
|
||||||
n_tx_postamble_modem_samples = self.c_lib.freedv_get_n_tx_postamble_modem_samples(freedv)
|
|
||||||
|
|
||||||
mod_out = create_string_buffer(n_tx_modem_samples * 2)
|
|
||||||
mod_out_preamble = create_string_buffer(n_tx_preamble_modem_samples * 2)
|
|
||||||
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
|
|
||||||
|
|
||||||
self.streambuffer = bytearray()
|
|
||||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
|
||||||
self.streambuffer += bytes(mod_out_preamble)
|
|
||||||
|
|
||||||
|
|
||||||
# loop through list of frames per burst
|
|
||||||
for n in range(0, len(frames)):
|
|
||||||
|
|
||||||
# create TX buffer
|
|
||||||
buffer = bytearray(payload_per_frame)
|
|
||||||
# set buffersize to length of data which will be send
|
|
||||||
buffer[:len(frames[n])] = frames[n]
|
|
||||||
|
|
||||||
crc = ctypes.c_ushort(self.c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16
|
|
||||||
# convert crc to 2 byte hex string
|
|
||||||
crc = crc.value.to_bytes(2, byteorder='big')
|
|
||||||
buffer += crc # append crc16 to buffer
|
|
||||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
|
||||||
|
|
||||||
# modulate DATA and safe it into mod_out pointer
|
|
||||||
self.c_lib.freedv_rawdatatx(freedv, mod_out, data)
|
|
||||||
self.streambuffer += bytes(mod_out)
|
|
||||||
|
|
||||||
self.c_lib.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
|
||||||
self.streambuffer += bytes(mod_out_postamble)
|
|
||||||
|
|
||||||
# resample up to 48k (resampler works on np.int16)
|
|
||||||
x = np.frombuffer(self.streambuffer, dtype=np.int16)
|
|
||||||
txbuffer_48k = self.resampler.resample8_to_48(x)
|
|
||||||
|
|
||||||
# -------------- transmit audio
|
|
||||||
|
|
||||||
while self.ptt_and_wait(True):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# set channel state
|
|
||||||
static.CHANNEL_STATE = 'SENDING_DATA'
|
|
||||||
|
|
||||||
# write audio to stream
|
|
||||||
self.stream_tx.write(txbuffer_48k.tobytes())
|
|
||||||
|
|
||||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
|
||||||
|
|
||||||
self.ptt_and_wait(False)
|
|
||||||
|
|
||||||
# close codec2 instance
|
|
||||||
self.c_lib.freedv_close(freedv)
|
|
||||||
|
|
||||||
return True
|
|
||||||
# --------------------------------------------------------------------------------------------------------
|
|
||||||
'''
|
|
||||||
def audio(self):
|
def audio(self):
|
||||||
try:
|
try:
|
||||||
print(f"starting pyaudio callback", file=sys.stderr)
|
print(f"starting pyaudio callback", file=sys.stderr)
|
||||||
|
@ -565,7 +315,6 @@ class RF():
|
||||||
self.datac0_buffer.pop(self.datac0_nin)
|
self.datac0_buffer.pop(self.datac0_nin)
|
||||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
||||||
if nbytes == self.datac0_bytes_per_frame:
|
if nbytes == self.datac0_bytes_per_frame:
|
||||||
print(len(self.datac0_bytes_out))
|
|
||||||
self.dataqueue.put([self.datac0_bytes_out, self.datac0_freedv ,self.datac0_bytes_per_frame])
|
self.dataqueue.put([self.datac0_bytes_out, self.datac0_freedv ,self.datac0_bytes_per_frame])
|
||||||
self.get_scatter(self.datac0_freedv)
|
self.get_scatter(self.datac0_freedv)
|
||||||
self.calculate_snr(self.datac0_freedv)
|
self.calculate_snr(self.datac0_freedv)
|
||||||
|
@ -597,7 +346,7 @@ class RF():
|
||||||
# worker for FIFO queue for processing received frames
|
# worker for FIFO queue for processing received frames
|
||||||
def worker(self):
|
def worker(self):
|
||||||
while True:
|
while True:
|
||||||
time.sleep(0.01)
|
time.sleep(0.1)
|
||||||
data = self.dataqueue.get()
|
data = self.dataqueue.get()
|
||||||
self.process_data(data[0], data[1], data[2])
|
self.process_data(data[0], data[1], data[2])
|
||||||
self.dataqueue.task_done()
|
self.dataqueue.task_done()
|
||||||
|
@ -616,15 +365,12 @@ class RF():
|
||||||
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
||||||
frame = frametype - 10
|
frame = frametype - 10
|
||||||
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
||||||
self.c_lib.freedv_set_frames_per_burst(freedv, n_frames_per_burst);
|
#self.c_lib.freedv_set_frames_per_burst(freedv, n_frames_per_burst);
|
||||||
|
|
||||||
#frequency_offset = self.get_frequency_offset(freedv)
|
#frequency_offset = self.get_frequency_offset(freedv)
|
||||||
#print("Freq-Offset: " + str(frequency_offset))
|
#print("Freq-Offset: " + str(frequency_offset))
|
||||||
|
|
||||||
if 50 >= frametype >= 10:
|
if 50 >= frametype >= 10:
|
||||||
# force = True, if we don't simulate a loss of the third frame, else force = False
|
|
||||||
force = True
|
|
||||||
if frame != 3 or force:
|
|
||||||
|
|
||||||
# send payload data to arq checker without CRC16
|
# send payload data to arq checker without CRC16
|
||||||
data_handler.arq_data_received(bytes(bytes_out[:-2]), bytes_per_frame)
|
data_handler.arq_data_received(bytes(bytes_out[:-2]), bytes_per_frame)
|
||||||
|
@ -634,9 +380,6 @@ class RF():
|
||||||
logging.debug("FULL BURST BUFFER ---> UNSYNC")
|
logging.debug("FULL BURST BUFFER ---> UNSYNC")
|
||||||
self.c_lib.freedv_set_sync(freedv, 0)
|
self.c_lib.freedv_set_sync(freedv, 0)
|
||||||
|
|
||||||
else:
|
|
||||||
logging.critical("-------------SIMULATED MISSING FRAME")
|
|
||||||
force = True
|
|
||||||
|
|
||||||
# BURST ACK
|
# BURST ACK
|
||||||
elif frametype == 60:
|
elif frametype == 60:
|
||||||
|
@ -683,12 +426,12 @@ class RF():
|
||||||
|
|
||||||
# ARQ FILE TRANSFER RECEIVED!
|
# ARQ FILE TRANSFER RECEIVED!
|
||||||
elif frametype == 225:
|
elif frametype == 225:
|
||||||
logging.debug("ARQ arq_received_data_channel_opener RECEIVED")
|
logging.debug("ARQ arq_received_data_channel_opener")
|
||||||
data_handler.arq_received_data_channel_opener(bytes_out[:-2])
|
data_handler.arq_received_data_channel_opener(bytes_out[:-2])
|
||||||
|
|
||||||
# ARQ CHANNEL IS OPENED
|
# ARQ CHANNEL IS OPENED
|
||||||
elif frametype == 226:
|
elif frametype == 226:
|
||||||
logging.debug("ARQ arq_received_channel_is_open RECEIVED")
|
logging.debug("ARQ arq_received_channel_is_open")
|
||||||
data_handler.arq_received_channel_is_open(bytes_out[:-2])
|
data_handler.arq_received_channel_is_open(bytes_out[:-2])
|
||||||
|
|
||||||
# ARQ CONNECT ACK / KEEP ALIVE
|
# ARQ CONNECT ACK / KEEP ALIVE
|
||||||
|
@ -703,6 +446,7 @@ class RF():
|
||||||
else:
|
else:
|
||||||
structlog.get_logger("structlog").warning("[TNC] ARQ - other frame type", frametype=frametype)
|
structlog.get_logger("structlog").warning("[TNC] ARQ - other frame type", frametype=frametype)
|
||||||
|
|
||||||
|
|
||||||
# DO UNSYNC AFTER LAST BURST by checking the frame nums against the total frames per burst
|
# DO UNSYNC AFTER LAST BURST by checking the frame nums against the total frames per burst
|
||||||
if frame == n_frames_per_burst:
|
if frame == n_frames_per_burst:
|
||||||
logging.info("LAST FRAME ---> UNSYNC")
|
logging.info("LAST FRAME ---> UNSYNC")
|
||||||
|
@ -749,17 +493,6 @@ class RF():
|
||||||
static.SCATTER = scatterdata_small
|
static.SCATTER = scatterdata_small
|
||||||
|
|
||||||
|
|
||||||
def calculate_ber(self, freedv):
|
|
||||||
Tbits = self.c_lib.freedv_get_total_bits(freedv)
|
|
||||||
Terrs = self.c_lib.freedv_get_total_bit_errors(freedv)
|
|
||||||
|
|
||||||
if Tbits != 0:
|
|
||||||
ber = (Terrs / Tbits) * 100
|
|
||||||
static.BER = int(ber)
|
|
||||||
|
|
||||||
self.c_lib.freedv_set_total_bit_errors(freedv, 0)
|
|
||||||
self.c_lib.freedv_set_total_bits(freedv, 0)
|
|
||||||
|
|
||||||
def calculate_snr(self, freedv):
|
def calculate_snr(self, freedv):
|
||||||
|
|
||||||
modem_stats_snr = c_float()
|
modem_stats_snr = c_float()
|
||||||
|
@ -773,12 +506,14 @@ class RF():
|
||||||
except:
|
except:
|
||||||
static.SNR = 0
|
static.SNR = 0
|
||||||
|
|
||||||
def get_radio_stats(self):
|
|
||||||
|
def update_rig_data(self):
|
||||||
while True:
|
while True:
|
||||||
time.sleep(0.1)
|
time.sleep(0.5)
|
||||||
static.HAMLIB_FREQUENCY = int(self.my_rig.get_freq())
|
#(static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data()
|
||||||
(hamlib_mode, static.HAMLIB_BANDWITH) = self.my_rig.get_mode()
|
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
|
||||||
static.HAMLIB_MODE = Hamlib.rig_strrmode(hamlib_mode)
|
static.HAMLIB_MODE = self.hamlib.get_mode()
|
||||||
|
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith()
|
||||||
|
|
||||||
def calculate_fft(self):
|
def calculate_fft(self):
|
||||||
while True:
|
while True:
|
||||||
|
@ -803,11 +538,11 @@ class RF():
|
||||||
dfft = np.around(dfft, 1)
|
dfft = np.around(dfft, 1)
|
||||||
dfftlist = dfft.tolist()
|
dfftlist = dfft.tolist()
|
||||||
|
|
||||||
static.FFT = dfftlist[10:180] #200 --> bandwith 3000
|
static.FFT = dfftlist[0:320] #200 --> bandwith 3000
|
||||||
except:
|
except:
|
||||||
|
|
||||||
structlog.get_logger("structlog").debug("[TNC] Setting fft=0")
|
structlog.get_logger("structlog").debug("[TNC] Setting fft=0")
|
||||||
# else 0
|
# else 0
|
||||||
static.FFT = [0] * 400
|
static.FFT = [0] * 320
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
157
tnc/rig.py
Normal file
157
tnc/rig.py
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import logging, structlog, log_handler
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
|
||||||
|
# try importing hamlib
|
||||||
|
try:
|
||||||
|
# get python version
|
||||||
|
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
||||||
|
|
||||||
|
# installation path for Ubuntu 20.04 LTS python modules
|
||||||
|
sys.path.append('/usr/local/lib/python'+ python_version +'/site-packages')
|
||||||
|
# installation path for Ubuntu 20.10 +
|
||||||
|
sys.path.append('/usr/local/lib/')
|
||||||
|
import Hamlib
|
||||||
|
|
||||||
|
# https://stackoverflow.com/a/4703409
|
||||||
|
hamlib_version = re.findall(r"[-+]?\d*\.?\d+|\d+", Hamlib.cvar.hamlib_version)
|
||||||
|
hamlib_version = float(hamlib_version[0])
|
||||||
|
|
||||||
|
min_hamlib_version = 4.1
|
||||||
|
if hamlib_version > min_hamlib_version:
|
||||||
|
structlog.get_logger("structlog").info("[TNC] Hamlib found", version=hamlib_version)
|
||||||
|
else:
|
||||||
|
structlog.get_logger("structlog").warning("[TNC] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
|
||||||
|
except Exception as e:
|
||||||
|
structlog.get_logger("structlog").critical("[TNC] Hamlib not found", error=e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class radio:
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.devicename = ''
|
||||||
|
self.devicenumber = ''
|
||||||
|
self.deviceport = ''
|
||||||
|
self.serialspeed = 0
|
||||||
|
self.hamlib_ptt_type = ''
|
||||||
|
self.my_rig = ''
|
||||||
|
|
||||||
|
|
||||||
|
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed):
|
||||||
|
|
||||||
|
self.devicename = devicename
|
||||||
|
self.deviceport = deviceport
|
||||||
|
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
|
||||||
|
self.hamlib_ptt_type = hamlib_ptt_type
|
||||||
|
|
||||||
|
# try to init hamlib
|
||||||
|
try:
|
||||||
|
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
|
||||||
|
|
||||||
|
# get devicenumber by looking for deviceobject in Hamlib module
|
||||||
|
try:
|
||||||
|
self.devicenumber = int(getattr(Hamlib, self.devicename))
|
||||||
|
except:
|
||||||
|
structlog.get_logger("structlog").error("[DMN] Hamlib: rig not supported...")
|
||||||
|
self.devicenumber = 0
|
||||||
|
|
||||||
|
|
||||||
|
self.my_rig = Hamlib.Rig(self.devicenumber)
|
||||||
|
self.my_rig.set_conf("rig_pathname", self.deviceport)
|
||||||
|
self.my_rig.set_conf("retry", "5")
|
||||||
|
self.my_rig.set_conf("serial_speed", self.serialspeed)
|
||||||
|
self.my_rig.set_conf("serial_handshake", "None")
|
||||||
|
self.my_rig.set_conf("stop_bits", "1")
|
||||||
|
self.my_rig.set_conf("data_bits", "8")
|
||||||
|
|
||||||
|
if self.hamlib_ptt_type == 'RIG':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
|
||||||
|
self.my_rig.set_conf("ptt_type", 'RIG')
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'DTR-H':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||||
|
self.my_rig.set_conf("dtr_state", "HIGH")
|
||||||
|
self.my_rig.set_conf("ptt_type", "DTR")
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'DTR-L':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_DTR
|
||||||
|
self.my_rig.set_conf("dtr_state", "LOW")
|
||||||
|
self.my_rig.set_conf("ptt_type", "DTR")
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'RTS':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_SERIAL_RTS
|
||||||
|
self.my_rig.set_conf("dtr_state", "OFF")
|
||||||
|
self.my_rig.set_conf("ptt_type", "RTS")
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'PARALLEL':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_PARALLEL
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'MICDATA':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG_MICDATA
|
||||||
|
|
||||||
|
elif self.hamlib_ptt_type == 'CM108':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_CM108
|
||||||
|
|
||||||
|
else: #self.hamlib_ptt_type == 'RIG_PTT_NONE':
|
||||||
|
self.hamlib_ptt_type = Hamlib.RIG_PTT_NONE
|
||||||
|
|
||||||
|
|
||||||
|
self.my_rig.open()
|
||||||
|
atexit.register(self.my_rig.close)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# lets determine the error message when opening rig
|
||||||
|
error = str(Hamlib.rigerror(my_rig.error_status)).splitlines()
|
||||||
|
error = error[1].split('err=')
|
||||||
|
error = error[1]
|
||||||
|
|
||||||
|
if error == 'Permission denied':
|
||||||
|
structlog.get_logger("structlog").error("[DMN] Hamlib has no permissions", e = error)
|
||||||
|
help_url = 'https://github.com/DJ2LS/FreeDATA/wiki/UBUNTU-Manual-installation#1-permissions'
|
||||||
|
structlog.get_logger("structlog").error("[DMN] HELP:", check = help_url)
|
||||||
|
except:
|
||||||
|
structlog.get_logger("structlog").info("[DMN] Hamlib device openend", status='SUCCESS')
|
||||||
|
|
||||||
|
|
||||||
|
# set ptt to false if ptt is stuck for some reason
|
||||||
|
self.set_ptt(False)
|
||||||
|
|
||||||
|
# set rig mode to USB
|
||||||
|
self.my_rig.set_mode(Hamlib.RIG_MODE_USB)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
structlog.get_logger("structlog").error("[TNC] Hamlib - can't open rig", error=e, e=sys.exc_info()[0])
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_frequency(self):
|
||||||
|
return int(self.my_rig.get_freq())
|
||||||
|
|
||||||
|
def get_mode(self):
|
||||||
|
(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||||
|
return Hamlib.rig_strrmode(hamlib_mode)
|
||||||
|
|
||||||
|
def get_bandwith(self):
|
||||||
|
(hamlib_mode, bandwith) = self.my_rig.get_mode()
|
||||||
|
return bandwith
|
||||||
|
|
||||||
|
def set_mode(self, mode):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_ptt(self):
|
||||||
|
return self.my_rig.get_ptt()
|
||||||
|
|
||||||
|
def set_ptt(self, state):
|
||||||
|
if state:
|
||||||
|
self.my_rig.set_ptt(self.hamlib_ptt_type, 1)
|
||||||
|
else:
|
||||||
|
self.my_rig.set_ptt(self.hamlib_ptt_type, 0)
|
||||||
|
return state
|
||||||
|
|
||||||
|
def close_rig(self):
|
||||||
|
self.my_rig.close()
|
|
@ -1,89 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import socket
|
|
||||||
import logging
|
|
||||||
import static
|
|
||||||
|
|
||||||
# rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35
|
|
||||||
# https://github.com/xssfox/freedv-tnc/blob/master/freedvtnc/rigctl.py
|
|
||||||
|
|
||||||
|
|
||||||
class Rigctld():
|
|
||||||
""" rotctld (hamlib) communication class """
|
|
||||||
# Note: This is a massive hack.
|
|
||||||
|
|
||||||
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
|
|
||||||
""" Open a connection to rotctld, and test it for validity """
|
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.sock.settimeout(timeout)
|
|
||||||
|
|
||||||
self.hostname = hostname
|
|
||||||
self.port = port
|
|
||||||
self.connect()
|
|
||||||
logging.debug(f"Rigctl intialized")
|
|
||||||
|
|
||||||
def get_model(self):
|
|
||||||
""" Get the rotator model from rotctld """
|
|
||||||
model = self.send_command(b'_')
|
|
||||||
return model
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
""" Connect to rotctld instance """
|
|
||||||
self.sock.connect((self.hostname,self.port))
|
|
||||||
model = self.get_model()
|
|
||||||
if model == None:
|
|
||||||
# Timeout!
|
|
||||||
self.close()
|
|
||||||
raise Exception("Timeout!")
|
|
||||||
else:
|
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.sock.close()
|
|
||||||
|
|
||||||
|
|
||||||
def send_command(self, command):
|
|
||||||
""" Send a command to the connected rotctld instance,
|
|
||||||
and return the return value.
|
|
||||||
"""
|
|
||||||
self.sock.sendall(command+b'\n')
|
|
||||||
try:
|
|
||||||
return self.sock.recv(1024)
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def ptt_enable(self):
|
|
||||||
logging.debug(f"PTT enabled")
|
|
||||||
self.send_command(b"T 1")
|
|
||||||
|
|
||||||
def ptt_disable(self):
|
|
||||||
logging.debug(f"PTT disabled")
|
|
||||||
self.send_command(b"T 0")
|
|
||||||
|
|
||||||
def get_frequency(self):
|
|
||||||
data = self.send_command(b"f")
|
|
||||||
if data is not None:
|
|
||||||
data = data.split(b'\n')
|
|
||||||
try:
|
|
||||||
freq = int(data[0])/1000
|
|
||||||
except:
|
|
||||||
freq = static.HAMLIB_FREQUENCY
|
|
||||||
#print("freq-err: " + str(data))
|
|
||||||
#for i in range(len(data)):
|
|
||||||
# print(data[i])
|
|
||||||
|
|
||||||
return freq
|
|
||||||
|
|
||||||
def get_mode(self):
|
|
||||||
data = self.send_command(b"m")
|
|
||||||
if data is not None:
|
|
||||||
data = data.split(b'\n')
|
|
||||||
try:
|
|
||||||
mode = str(data[0], "utf-8")
|
|
||||||
bandwith = int(data[1])
|
|
||||||
except:
|
|
||||||
#print("mode-err: " + str(data))
|
|
||||||
mode = static.HAMLIB_MODE
|
|
||||||
bandwith = static.HAMLIB_BANDWITH
|
|
||||||
return [mode, bandwith]
|
|
||||||
|
|
31
tnc/sock.py
31
tnc/sock.py
|
@ -100,14 +100,14 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
CQ_THREAD = threading.Thread(target=data_handler.transmit_cq, args=[], name="CQ")
|
CQ_THREAD = threading.Thread(target=data_handler.transmit_cq, args=[], name="CQ")
|
||||||
CQ_THREAD.start()
|
CQ_THREAD.start()
|
||||||
|
|
||||||
# CQ CQ CQ -----------------------------------------------------
|
# START_BEACON -----------------------------------------------------
|
||||||
if received_json["command"] == "START_BEACON":
|
if received_json["command"] == "START_BEACON":
|
||||||
static.BEACON_STATE = True
|
static.BEACON_STATE = True
|
||||||
interval = int(received_json["parameter"])
|
interval = int(received_json["parameter"])
|
||||||
BEACON_THREAD = threading.Thread(target=data_handler.run_beacon, args=[interval], name="START BEACON")
|
BEACON_THREAD = threading.Thread(target=data_handler.run_beacon, args=[interval], name="START BEACON")
|
||||||
BEACON_THREAD.start()
|
BEACON_THREAD.start()
|
||||||
|
|
||||||
# CQ CQ CQ -----------------------------------------------------
|
# STOP_BEACON -----------------------------------------------------
|
||||||
if received_json["command"] == "STOP_BEACON":
|
if received_json["command"] == "STOP_BEACON":
|
||||||
static.BEACON_STATE = False
|
static.BEACON_STATE = False
|
||||||
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
|
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
|
||||||
|
@ -141,7 +141,14 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
|
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
|
||||||
static.DXCALLSIGN)
|
static.DXCALLSIGN)
|
||||||
|
|
||||||
rawdata = {"datatype": "file", "filename": filename, "filetype": filetype,"data": data, "checksum": checksum}
|
# dt = datatype
|
||||||
|
# --> f = file
|
||||||
|
# --> m = message
|
||||||
|
# fn = filename
|
||||||
|
# ft = filetype
|
||||||
|
# d = data
|
||||||
|
# crc = checksum
|
||||||
|
rawdata = {"dt": "f", "fn": filename, "ft": filetype,"d": data, "crc": checksum}
|
||||||
dataframe = json.dumps(rawdata)
|
dataframe = json.dumps(rawdata)
|
||||||
data_out = bytes(dataframe, 'utf-8')
|
data_out = bytes(dataframe, 'utf-8')
|
||||||
|
|
||||||
|
@ -158,15 +165,21 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
dxcallsign = received_json["dxcallsign"]
|
dxcallsign = received_json["dxcallsign"]
|
||||||
mode = int(received_json["mode"])
|
mode = int(received_json["mode"])
|
||||||
n_frames = int(received_json["n_frames"])
|
n_frames = int(received_json["n_frames"])
|
||||||
data = received_json["data"]
|
data = received_json["d"] # d = data
|
||||||
checksum = received_json["checksum"]
|
checksum = received_json["crc"] # crc = checksum
|
||||||
|
|
||||||
|
|
||||||
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
||||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
|
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
|
||||||
static.DXCALLSIGN)
|
|
||||||
|
|
||||||
rawdata = {"datatype": "message","data": data, "checksum": checksum}
|
# dt = datatype
|
||||||
|
# --> f = file
|
||||||
|
# --> m = message
|
||||||
|
# fn = filename
|
||||||
|
# ft = filetype
|
||||||
|
# d = data
|
||||||
|
# crc = checksum
|
||||||
|
rawdata = {"dt": "m","d": data, "crc": checksum}
|
||||||
dataframe = json.dumps(rawdata)
|
dataframe = json.dumps(rawdata)
|
||||||
data_out = bytes(dataframe, 'utf-8')
|
data_out = bytes(dataframe, 'utf-8')
|
||||||
|
|
||||||
|
@ -221,7 +234,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||||
"COMMAND": "TNC_STATE",
|
"COMMAND": "TNC_STATE",
|
||||||
"TIMESTAMP": received_json["timestamp"],
|
"TIMESTAMP": received_json["timestamp"],
|
||||||
"PTT_STATE": str(static.PTT_STATE),
|
"PTT_STATE": str(static.PTT_STATE),
|
||||||
"CHANNEL_STATE": str(static.CHANNEL_STATE),
|
#"CHANNEL_STATE": str(static.CHANNEL_STATE),
|
||||||
"TNC_STATE": str(static.TNC_STATE),
|
"TNC_STATE": str(static.TNC_STATE),
|
||||||
"ARQ_STATE": str(static.ARQ_STATE),
|
"ARQ_STATE": str(static.ARQ_STATE),
|
||||||
"AUDIO_RMS": str(static.AUDIO_RMS),
|
"AUDIO_RMS": str(static.AUDIO_RMS),
|
||||||
|
|
|
@ -36,10 +36,10 @@ SOCKET_TIMEOUT = 3 # seconds
|
||||||
HAMLIB_PTT_TYPE = 'RTS'
|
HAMLIB_PTT_TYPE = 'RTS'
|
||||||
PTT_STATE = False
|
PTT_STATE = False
|
||||||
|
|
||||||
HAMLIB_DEVICE_ID = 'RIG_MODEL_DUMMY_NOVFO'
|
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
|
||||||
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
|
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
|
||||||
HAMLIB_SERIAL_SPEED = '9600'
|
HAMLIB_SERIAL_SPEED = '9600'
|
||||||
|
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
|
||||||
|
|
||||||
HAMLIB_FREQUENCY = 0
|
HAMLIB_FREQUENCY = 0
|
||||||
HAMLIB_MODE = ''
|
HAMLIB_MODE = ''
|
||||||
|
@ -71,7 +71,7 @@ ARQ_BITS_PER_SECOND = 0
|
||||||
ARQ_TRANSMISSION_PERCENT = 0
|
ARQ_TRANSMISSION_PERCENT = 0
|
||||||
TOTAL_BYTES = 0
|
TOTAL_BYTES = 0
|
||||||
|
|
||||||
CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||||
TNC_STATE = 'IDLE'
|
TNC_STATE = 'IDLE'
|
||||||
ARQ_STATE = 'IDLE'
|
ARQ_STATE = 'IDLE'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue