Merge pull request #95 from DJ2LS/ls-tnc-optimization

minor tnc changes
This commit is contained in:
DJ2LS 2021-12-26 19:32:50 +01:00 committed by GitHub
commit 5365a411ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 371 additions and 740 deletions

View file

@ -79,9 +79,9 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
os: [ubuntu-20.04]
include:
- os: ubuntu-latest
- os: ubuntu-20.04
zip_name: ubuntu_tnc
generator: Unix Makefiles
@ -97,7 +97,7 @@ jobs:
- name: Install Linux dependencies
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
run: |
sudo apt install portaudio19-dev libhamlib-dev libhamlib-utils build-essential cmake python3-libhamlib2
python -m pip install --upgrade pip
@ -128,7 +128,7 @@ jobs:
- name: Build codec2 Linux
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
#working-directory: tnc
run: |
cd ~
@ -139,7 +139,7 @@ jobs:
- name: Build Linux
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
working-directory: tnc
run: |
#pyinstaller -F daemon.py -n daemon
@ -171,7 +171,7 @@ jobs:
node-version: 14
- name: Copy TNC to GUI Linux
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
run: |
cp -R ./tnc/dist ./gui/tnc
ls -R
@ -218,7 +218,7 @@ jobs:
release:
name: Upload Release
needs: [build_linux_release, build_windows_release]
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:

View file

@ -1,10 +1,13 @@
# 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
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.
## Preview
![preview](https://github.com/DJ2LS/FreeDATA/blob/main/documentation/FreeDATA_preview.gif?raw=true "Preview")
## Credits
* David Rowe and the FreeDV team for developing the modem and libraries -
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
## 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
Please check the wiki for installation instructions
Please check the [wiki](https://github.com/DJ2LS/FreeDATA/wiki) for installation instructions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View file

@ -140,14 +140,14 @@ exports.getDaemonState = function() {
// START TNC
// ` `== 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({
type: 'SET',
command: 'STARTTNC',
parameter: [{
rx_audio: rx_audio,
tx_audio: tx_audio,
deviceid: deviceid,
devicename: devicename,
deviceport: deviceport,
pttprotocol: pttprotocol,
pttport: pttport,
@ -172,13 +172,13 @@ exports.stopTNC = function() {
}
// 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({
type: 'GET',
command: 'TEST_HAMLIB',
parameter: [{
deviceid: deviceid,
devicename: devicename,
deviceport: deviceport,
pttprotocol: pttprotocol,
pttport: pttport,

View file

@ -330,9 +330,6 @@ advancedHamlibSettingsModal
daemon.startTNC(rx_audio, tx_audio, deviceid, deviceport, pttprotocol, pttport, serialspeed, pttspeed, data_bits, stop_bits, handshake)
setTimeout(function() {
@ -340,7 +337,7 @@ advancedHamlibSettingsModal
}, 3000);
setTimeout(function() {
sock.saveMyGrid(config.mygrid);
}, 4000);
}, 3500);
})
// stopTNC button clicked
@ -649,7 +646,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
}
// BEACON STATE
console.log(arg.beacon_state)
if (arg.beacon_state == 'True') {
document.getElementById("startBeacon").className = "btn btn-success spinner-grow"
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("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
document.getElementById("frequency").innerHTML = arg.frequency
@ -1219,7 +1194,7 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
var fileName = document.createElement("td");
var fileNameText = document.createElement('span');
var fileNameString = arg.data[i]['RXDATA'][0]['filename']
var fileNameString = arg.data[i]['RXDATA'][0]['fn']
fileNameText.innerText = fileNameString
fileName.appendChild(fileNameText);
@ -1247,7 +1222,7 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
// 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
// https://www.codeblocq.com/2016/04/Convert-a-base64-string-to-a-file-in-Node/
var base64Data = base64String.split(';base64,').pop()

View file

@ -46,7 +46,7 @@ client.on('error', function(data) {
let Data = {
busy_state: "-",
arq_state: "-",
channel_state: "-",
//channel_state: "-",
frequency: "-",
mode: "-",
bandwith: "-",
@ -133,7 +133,7 @@ client.on('data', function(data) {
ptt_state: data['PTT_STATE'],
busy_state: data['TNC_STATE'],
arq_state: data['ARQ_STATE'],
channel_state: data['CHANNEL_STATE'],
//channel_state: data['CHANNEL_STATE'],
frequency: data['FREQUENCY'],
mode: data['MODE'],
bandwith: data['BANDWITH'],

View file

@ -905,7 +905,6 @@
<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">
<option selected value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
@ -973,22 +972,7 @@
</svg>
</button>
</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 class="container-fluid" style="width:30%">
<div class="input-group input-group-sm">

View file

@ -20,7 +20,7 @@ import serial.tools.list_ports
import static
import crcengine
import re
import rig
import logging, structlog, log_handler
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:
rx_audio = str(received_json["parameter"][0]["rx_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"])
serialspeed = str(received_json["parameter"][0]["serialspeed"])
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
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])
# command = "--rx "+ rx_audio +" \
@ -178,8 +178,8 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
options.append(tx_audio)
options.append('--deviceport')
options.append(deviceport)
options.append('--deviceid')
options.append(deviceid)
options.append('--devicename')
options.append(devicename)
options.append('--serialspeed')
options.append(serialspeed)
options.append('--pttprotocol')
@ -276,101 +276,38 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
if received_json["type"] == 'GET' and received_json["command"] == 'TEST_HAMLIB':
print(received_json["parameter"])
deviceid = str(received_json["parameter"][0]["deviceid"])
deviceport = str(received_json["parameter"][0]["deviceport"])
serialspeed = str(received_json["parameter"][0]["serialspeed"])
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
pttport = str(received_json["parameter"][0]["pttport"])
pttspeed = str(received_json["parameter"][0]["pttspeed"])
data_bits = str(received_json["parameter"][0]["data_bits"])
stop_bits = str(received_json["parameter"][0]["stop_bits"])
handshake = str(received_json["parameter"][0]["handshake"])
# try to init hamlib
try:
print(received_json["parameter"])
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
devicename = str(received_json["parameter"][0]["devicename"])
deviceport = str(received_json["parameter"][0]["deviceport"])
serialspeed = str(received_json["parameter"][0]["serialspeed"])
pttprotocol = str(received_json["parameter"][0]["pttprotocol"])
pttport = str(received_json["parameter"][0]["pttport"])
# get devicenumber by looking for deviceobject in Hamlib module
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)
pttspeed = str(received_json["parameter"][0]["pttspeed"])
data_bits = str(received_json["parameter"][0]["data_bits"])
stop_bits = str(received_json["parameter"][0]["stop_bits"])
handshake = str(received_json["parameter"][0]["handshake"])
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
hamlib = rig.radio()
hamlib.open_rig(devicename=devicename, deviceport=deviceport, hamlib_ptt_type=pttprotocol, serialspeed=serialspeed)
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:
hamlib.set_ptt(True)
pttstate = hamlib.get_ptt()
if pttstate:
structlog.get_logger("structlog").info("[DMN] Hamlib PTT", status = 'SUCCESS')
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'SUCCESS'}
elif pttstate == 0:
elif not pttstate:
structlog.get_logger("structlog").warning("[DMN] Hamlib PTT", status = 'NO SUCCESS')
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'NOSUCCESS'}
else:
structlog.get_logger("structlog").error("[DMN] Hamlib PTT", status = 'FAILED')
data = {'COMMAND': 'TEST_HAMLIB', 'RESULT': 'FAILED'}
my_rig.set_ptt(hamlib_ptt_type, 0)
my_rig.close
hamlib.set_ptt(False)
hamlib.close_rig()
jsondata = json.dumps(data)
self.request.sendall(bytes(jsondata, encoding))

View file

@ -13,7 +13,6 @@ from random import randrange
import asyncio
import ujson as json
import static
import modem
import helpers
@ -54,6 +53,7 @@ RX_START_OF_TRANSMISSION = 0 # time of transmission start
# ################################################
def arq_data_received(data_in, bytes_per_frame):
# we neeed to declare our global variables, so the thread has access to them
global RX_START_OF_TRANSMISSION
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)
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)
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!
# here we will save the N frame of a data frame to N list position so we can explicit search for it
@ -102,11 +102,7 @@ def arq_data_received(data_in, bytes_per_frame):
# but better doing this, to avoid problems caused by old chunks in data
if RX_N_FRAME_OF_DATA_FRAME == 1:
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:
static.RX_FRAME_BUFFER[RX_N_FRAME_OF_DATA_FRAME] = bytes(data_in)
@ -123,10 +119,6 @@ def arq_data_received(data_in, bytes_per_frame):
static.RX_FRAME_BUFFER.insert(i, None)
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:
@ -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
# 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
logging.info("ARQ | TX | BURST ACK")
structlog.get_logger("structlog").info("[TNC] ARQ TX BURST ACK")
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING BURST ACK")
# BUILDING ACK FRAME FOR BURST -----------------------------------------------
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[2:3] = static.MYCALLSIGN_CRC8
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
helpers.wait(0.3)
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
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')
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 -----------------------------------------------
rpt_frame = bytearray(14)
rpt_frame[:1] = bytes([62])
@ -192,17 +179,13 @@ def arq_data_received(data_in, bytes_per_frame):
# TRANSMIT RPT FRAME FOR BURST-----------------------------------------------
txbuffer = [rpt_frame]
modem.transmit('datac0', 1, txbuffer)
#while not modem.transmit_signalling(rpt_frame, 1):
# time.sleep(0.01)
static.CHANNEL_STATE = 'RECEIVING_DATA'
# ---------------------------- FRAME MACHINE
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
# ---------------------------- FRAME MACHINE
# --------------- IF LIST NOT CONTAINS "None" stick everything together
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
logging.debug("DECODING FRAME!")
#logging.debug("DECODING FRAME!")
for frame in range(1, len(static.RX_FRAME_BUFFER)):
raw_arq_frame = static.RX_FRAME_BUFFER[frame]
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[1]
logging.debug("BOF")
#logging.debug("BOF")
# -------- 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:
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_EOF)
arq_frame_payload = arq_frame_payload[0]
logging.debug("EOF")
#logging.debug("EOF")
# --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER
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 frame_payload_crc == data_frame_crc:
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)
# decode to utf-8 string
@ -250,15 +233,22 @@ def arq_data_received(data_in, bytes_per_frame):
# decode json objects from data frame to inspect if we received a file or message
rawdata = json.loads(complete_data_frame)
# if datatype is a file, we append to RX_BUFFER, which contains files only
if rawdata["datatype"] == "file":
logging.info("RECEIVED FILE --> MOVING DATA TO RX BUFFER")
# if datatype is a file, we append to RX_BUFFER, which contains files only
# dt = datatype
# --> 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])
# 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])
logging.info("RECEIVED MESSAGE --> MOVING DATA TO MESSAGE BUFFER")
#logging.debug("RECEIVED MESSAGE --> MOVING DATA TO MESSAGE BUFFER")
# BUILDING ACK FRAME FOR DATA FRAME -----------------------------------------------
ack_frame = bytearray(14)
@ -267,17 +257,11 @@ def arq_data_received(data_in, bytes_per_frame):
ack_frame[2:3] = static.MYCALLSIGN_CRC8
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
structlog.get_logger("structlog").info("[TNC] ARQ 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)
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING DATA FRAME ACK", snr=static.SNR, crc=data_frame_crc.hex())
txbuffer = [ack_frame]
modem.transmit('datac0', 1, txbuffer)
#while not modem.transmit_signalling(ack_frame, 3):
# time.sleep(0.01)
modem.transmit(mode=14, repeats=2, repeat_delay=250, frames=txbuffer)
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_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:
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)
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
#arq_reset_frame_machine()
@ -305,7 +289,7 @@ def arq_data_received(data_in, bytes_per_frame):
static.RX_BURST_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):
@ -329,7 +313,7 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
TX_BUFFER = [] # our buffer for appending new data
# 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
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
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)
# 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)
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-----------------------------------------------------------------
@ -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)
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)
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
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 = n_current_arq_frame.to_bytes(2, byteorder='big')
n_total_arq_frame = len(TX_BUFFER)
#static.ARQ_TX_N_TOTAL_ARQ_FRAMES = n_total_arq_frame
arqframe = frame_type + \
bytes([TX_N_FRAMES_PER_BURST]) + \
@ -430,30 +411,26 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
payload_data
tempbuffer.append(arqframe)
while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, 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)
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
# --------------------------- START TIMER FOR WAITING FOR ACK ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1
structlog.get_logger("structlog").debug("[TNC] ARQ | RX | WAITING FOR BURST ACK")
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | WAITING FOR BURST ACK")
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS
# --------------------------- 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':
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
# IF WE ARE NOT IN ARQ STATE, WE STOPPED THE TRANSMISSION
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)
# --------- BUILD RPT FRAME --------------
tempbuffer = []
@ -484,14 +461,8 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
payload_data
tempbuffer.append(arqframe)
while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, 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'
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
arq_reset_ack(False)
@ -536,25 +507,22 @@ def arq_transmit(data_out, mode, n_frames_per_burst):
TX_N_RETRIES_PER_BURST = 0
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]")
# lets wait a little bit before we are processing the next frame
helpers.wait(0.3)
logging.info("ARQ | RX | ACK [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
break
else:
logging.info("--->NO RULE MATCHED OR TRANSMISSION STOPPED!")
print("ARQ_ACK_RECEIVED " + str(BURST_ACK_RECEIVED))
logging.debug("--->NO RULE MATCHED OR TRANSMISSION STOPPED!")
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
# --------------------------------WAITING AREA FOR FRAME ACKs
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
frameacktimeout = time.time() + DATA_FRAME_ACK_TIMEOUT_SECONDS
# 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:
time.sleep(0.01) # lets reduce CPU load a little bit
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
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)
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
elif not DATA_FRAME_ACK_RECEIVED and time.time() > frameacktimeout:
@ -650,20 +617,14 @@ def burst_rpt_received(data_in):
def open_dc_and_transmit(data_out, mode, n_frames_per_burst):
global DATA_CHANNEL_READY_FOR_DATA
static.TNC_STATE = 'BUSY'
asyncio.run(arq_open_data_channel(mode))
# wait until data channel is open
while not DATA_CHANNEL_READY_FOR_DATA:
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)
@ -694,8 +655,7 @@ async def arq_open_data_channel(mode):
txbuffer = [connection_frame]
modem.transmit('datac0', 1, txbuffer)
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
timeout = time.time() + 3
while time.time() < timeout:
@ -742,14 +702,10 @@ def arq_received_data_channel_opener(data_in):
connection_frame[12:13] = bytes([mode])
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)
static.CHANNEL_STATE = 'RECEIVING_DATA'
# and now we are going to "RECEIVING_DATA" mode....
def arq_received_channel_is_open(data_in):
global DATA_CHANNEL_LAST_RECEIVED
@ -767,19 +723,13 @@ def arq_received_channel_is_open(data_in):
# we are forcing doing a transmission at the moment --> see else statement
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)
# 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
static.ARQ_STATE = 'DATA'
DATA_CHANNEL_READY_FOR_DATA = True
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
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")
helpers.wait(0.5)
# as soon as we set ARQ_STATE to DATA, transmission starts
static.ARQ_STATE = 'DATA'
DATA_CHANNEL_READY_FOR_DATA = True
@ -803,8 +753,7 @@ def transmit_ping(callsign):
ping_frame[3:9] = static.MYCALLSIGN
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):
@ -824,7 +773,7 @@ def received_ping(data_in, frequency_offset):
ping_frame[9:11] = frequency_offset.to_bytes(2, byteorder='big', signed=True)
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):
@ -858,8 +807,7 @@ def run_beacon(interval):
structlog.get_logger("structlog").info("[TNC] Sending beacon!", interval=interval)
txbuffer = [beacon_frame]
modem.transmit('datac0', 1, txbuffer)
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
time.sleep(interval)
@ -890,8 +838,8 @@ def transmit_cq():
cq_frame[8:14] = static.MYGRID
txbuffer = [cq_frame]
modem.transmit('datac0', 1, txbuffer)
#while not modem.transmit('datac0', 1, txbuffer):
modem.transmit(mode=14, repeats=1, repeat_delay=1000, frames=txbuffer)
#while not modem.transmit(14, 1, txbuffer):
# pass
@ -1008,7 +956,7 @@ def watchdog():
watchdog master function. Frome here we call the watchdogs
"""
while True:
time.sleep(0.01)
time.sleep(0.5)
data_channel_keep_alive_watchdog()

View file

@ -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('--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('--deviceport', dest="hamlib_device_port", default="/dev/ttyUSB0", help="Socket port", type=str)
PARSER.add_argument('--deviceid', dest="hamlib_device_id", default=2028, 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('--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('--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)
@ -39,10 +39,10 @@ if __name__ == '__main__':
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
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_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
# we need to wait until we got all parameters from argparse first before we can load the other modules
@ -59,36 +59,4 @@ if __name__ == '__main__':
CMD_SERVER_THREAD = threading.Thread(target=sock.start_cmd_socket, name="cmd server")
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()
'''

View file

@ -21,6 +21,7 @@ import data_handler
import re
import queue
import codec2
import rig
# option for testing miniaudio instead of audioop for sample rate conversion
#import miniaudio
@ -54,29 +55,6 @@ def noalsaerr():
# 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_NC_MAX = 51
@ -124,7 +102,9 @@ class RF():
# init FIFO queue to store modulation out in
self.modoutqueue = queue.Queue()
# define fft_data buffer
self.fft_data = bytes()
# open codec2 instance
self.datac0_freedv = cast(codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), c_void_p)
self.datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv)/8)
@ -185,90 +165,31 @@ class RF():
output=True,
input_device_index=static.AUDIO_INPUT_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
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.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.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 = self.resampler.resample48_to_8(x)
@ -276,11 +197,7 @@ class RF():
self.datac0_buffer.push(x)
self.datac1_buffer.push(x)
self.datac3_buffer.push(x)
# refill fft_data buffer so we can plot a fft
if len(self.fft_data) < 1024:
self.fft_data += bytes(x)
self.fft_data += bytes(x)
if self.modoutqueue.empty():
data_out48k = bytes(self.AUDIO_FRAMES_PER_BUFFER_TX*2*2)
@ -288,42 +205,15 @@ class RF():
data_out48k = self.modoutqueue.get()
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):
state_before_transmit = static.CHANNEL_STATE
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
def transmit(self, mode, repeats, repeat_delay, frames):
# 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)
# 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)
mod_out_postamble = create_string_buffer(n_tx_postamble_modem_samples * 2)
for i in range(1,count+1):
# 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):
# write preamble to txbuffer
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
for n in range(0,len(frames)):
# create buffer for data
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
@ -366,14 +260,20 @@ class RF():
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
time.sleep(0.01)
txbuffer += bytes(mod_out)
# append postamble to txbuffer
codec2.api.freedv_rawdatapostambletx(freedv, 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)
x = np.frombuffer(txbuffer, dtype=np.int16)
txbuffer_48k = self.resampler.resample8_to_48(x)
@ -389,167 +289,17 @@ class RF():
if len(c) < self.AUDIO_FRAMES_PER_BUFFER_RX*2:
c += bytes(self.AUDIO_FRAMES_PER_BUFFER_RX*2 - len(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
# 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
static.PTT_STATE = self.hamlib.set_ptt(False)
self.c_lib.freedv_close(freedv)
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):
try:
print(f"starting pyaudio callback", file=sys.stderr)
@ -565,7 +315,6 @@ class RF():
self.datac0_buffer.pop(self.datac0_nin)
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
if nbytes == self.datac0_bytes_per_frame:
print(len(self.datac0_bytes_out))
self.dataqueue.put([self.datac0_bytes_out, self.datac0_freedv ,self.datac0_bytes_per_frame])
self.get_scatter(self.datac0_freedv)
self.calculate_snr(self.datac0_freedv)
@ -597,7 +346,7 @@ class RF():
# worker for FIFO queue for processing received frames
def worker(self):
while True:
time.sleep(0.01)
time.sleep(0.1)
data = self.dataqueue.get()
self.process_data(data[0], data[1], data[2])
self.dataqueue.task_done()
@ -616,27 +365,21 @@ class RF():
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
frame = frametype - 10
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)
#print("Freq-Offset: " + str(frequency_offset))
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
data_handler.arq_data_received(bytes(bytes_out[:-2]), bytes_per_frame)
# send payload data to arq checker without CRC16
data_handler.arq_data_received(bytes(bytes_out[:-2]), bytes_per_frame)
#print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None)))
if static.RX_BURST_BUFFER.count(None) <= 1:
logging.debug("FULL BURST BUFFER ---> UNSYNC")
self.c_lib.freedv_set_sync(freedv, 0)
#print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None)))
if static.RX_BURST_BUFFER.count(None) <= 1:
logging.debug("FULL BURST BUFFER ---> UNSYNC")
self.c_lib.freedv_set_sync(freedv, 0)
else:
logging.critical("-------------SIMULATED MISSING FRAME")
force = True
# BURST ACK
elif frametype == 60:
@ -683,12 +426,12 @@ class RF():
# ARQ FILE TRANSFER RECEIVED!
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])
# ARQ CHANNEL IS OPENED
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])
# ARQ CONNECT ACK / KEEP ALIVE
@ -703,11 +446,12 @@ class RF():
else:
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
if frame == n_frames_per_burst:
logging.info("LAST FRAME ---> UNSYNC")
self.c_lib.freedv_set_sync(freedv, 0) # FORCE UNSYNC
else:
# for debugging purposes to receive all data
@ -747,19 +491,8 @@ class RF():
# only take every tenth data point
scatterdata_small = scatterdata[::10]
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):
modem_stats_snr = c_float()
@ -773,13 +506,15 @@ class RF():
except:
static.SNR = 0
def get_radio_stats(self):
while True:
time.sleep(0.1)
static.HAMLIB_FREQUENCY = int(self.my_rig.get_freq())
(hamlib_mode, static.HAMLIB_BANDWITH) = self.my_rig.get_mode()
static.HAMLIB_MODE = Hamlib.rig_strrmode(hamlib_mode)
def update_rig_data(self):
while True:
time.sleep(0.5)
#(static.HAMLIB_FREQUENCY, static.HAMLIB_MODE, static.HAMLIB_BANDWITH, static.PTT_STATE) = self.hamlib.get_rig_data()
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
static.HAMLIB_MODE = self.hamlib.get_mode()
static.HAMLIB_BANDWITH = self.hamlib.get_bandwith()
def calculate_fft(self):
while True:
time.sleep(0.01)
@ -802,12 +537,12 @@ class RF():
# round data to decrease size
dfft = np.around(dfft, 1)
dfftlist = dfft.tolist()
static.FFT = dfftlist[10:180] #200 --> bandwith 3000
static.FFT = dfftlist[0:320] #200 --> bandwith 3000
except:
structlog.get_logger("structlog").debug("[TNC] Setting fft=0")
# else 0
static.FFT = [0] * 400
static.FFT = [0] * 320
else:
pass

157
tnc/rig.py Normal file
View 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()

View file

@ -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]

View file

@ -100,14 +100,14 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
CQ_THREAD = threading.Thread(target=data_handler.transmit_cq, args=[], name="CQ")
CQ_THREAD.start()
# CQ CQ CQ -----------------------------------------------------
# START_BEACON -----------------------------------------------------
if received_json["command"] == "START_BEACON":
static.BEACON_STATE = True
interval = int(received_json["parameter"])
BEACON_THREAD = threading.Thread(target=data_handler.run_beacon, args=[interval], name="START BEACON")
BEACON_THREAD.start()
# CQ CQ CQ -----------------------------------------------------
# STOP_BEACON -----------------------------------------------------
if received_json["command"] == "STOP_BEACON":
static.BEACON_STATE = False
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
@ -140,8 +140,15 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
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)
data_out = bytes(dataframe, 'utf-8')
@ -158,15 +165,21 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
dxcallsign = received_json["dxcallsign"]
mode = int(received_json["mode"])
n_frames = int(received_json["n_frames"])
data = received_json["data"]
checksum = received_json["checksum"]
data = received_json["d"] # d = data
checksum = received_json["crc"] # crc = checksum
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(
static.DXCALLSIGN)
rawdata = {"datatype": "message","data": data, "checksum": checksum}
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
# dt = datatype
# --> f = file
# --> m = message
# fn = filename
# ft = filetype
# d = data
# crc = checksum
rawdata = {"dt": "m","d": data, "crc": checksum}
dataframe = json.dumps(rawdata)
data_out = bytes(dataframe, 'utf-8')
@ -221,7 +234,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
"COMMAND": "TNC_STATE",
"TIMESTAMP": received_json["timestamp"],
"PTT_STATE": str(static.PTT_STATE),
"CHANNEL_STATE": str(static.CHANNEL_STATE),
#"CHANNEL_STATE": str(static.CHANNEL_STATE),
"TNC_STATE": str(static.TNC_STATE),
"ARQ_STATE": str(static.ARQ_STATE),
"AUDIO_RMS": str(static.AUDIO_RMS),

View file

@ -36,10 +36,10 @@ SOCKET_TIMEOUT = 3 # seconds
HAMLIB_PTT_TYPE = 'RTS'
PTT_STATE = False
HAMLIB_DEVICE_ID = 'RIG_MODEL_DUMMY_NOVFO'
HAMLIB_DEVICE_NAME = 'RIG_MODEL_DUMMY_NOVFO'
HAMLIB_DEVICE_PORT = '/dev/ttyUSB0'
HAMLIB_SERIAL_SPEED = '9600'
HAMLIB_PTT_PORT = '/dev/ttyUSB0'
HAMLIB_FREQUENCY = 0
HAMLIB_MODE = ''
@ -71,7 +71,7 @@ ARQ_BITS_PER_SECOND = 0
ARQ_TRANSMISSION_PERCENT = 0
TOTAL_BYTES = 0
CHANNEL_STATE = 'RECEIVING_SIGNALLING'
#CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = 'IDLE'
ARQ_STATE = 'IDLE'