diff --git a/.github/workflows/build-project.yml b/.github/workflows/build-project.yml
index 4af5577e..9928ba61 100644
--- a/.github/workflows/build-project.yml
+++ b/.github/workflows/build-project.yml
@@ -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:
diff --git a/README.md b/README.md
index 9cfd7bda..e8d7282f 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/documentation/FreeDATA_preview.gif b/documentation/FreeDATA_preview.gif
new file mode 100644
index 00000000..4638daa2
Binary files /dev/null and b/documentation/FreeDATA_preview.gif differ
diff --git a/gui/daemon.js b/gui/daemon.js
index dc1060be..feec94d2 100644
--- a/gui/daemon.js
+++ b/gui/daemon.js
@@ -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,
diff --git a/gui/preload-main.js b/gui/preload-main.js
index 7c4dac95..adc7d274 100644
--- a/gui/preload-main.js
+++ b/gui/preload-main.js
@@ -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()
diff --git a/gui/sock.js b/gui/sock.js
index 429e79ea..fdfc8307 100644
--- a/gui/sock.js
+++ b/gui/sock.js
@@ -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'],
diff --git a/gui/src/index.html b/gui/src/index.html
index 4e134b9b..d2da0044 100644
--- a/gui/src/index.html
+++ b/gui/src/index.html
@@ -905,7 +905,6 @@
diff --git a/tnc/daemon.py b/tnc/daemon.py
index 01787030..3e1da96b 100755
--- a/tnc/daemon.py
+++ b/tnc/daemon.py
@@ -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))
diff --git a/tnc/data_handler.py b/tnc/data_handler.py
index fd64fafd..75acaf71 100644
--- a/tnc/data_handler.py
+++ b/tnc/data_handler.py
@@ -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') + "]<>[" + 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)
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()
diff --git a/tnc/lib/codec2/linux/libcodec2.so.1.0 b/tnc/lib/codec2/linux/libcodec2.so.1.0
index 34328f4a..a61dff0d 100755
Binary files a/tnc/lib/codec2/linux/libcodec2.so.1.0 and b/tnc/lib/codec2/linux/libcodec2.so.1.0 differ
diff --git a/tnc/main.py b/tnc/main.py
index 411f552c..54432dd1 100644
--- a/tnc/main.py
+++ b/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('--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()
- '''
+
diff --git a/tnc/modem.py b/tnc/modem.py
index ec60c510..157c36dc 100644
--- a/tnc/modem.py
+++ b/tnc/modem.py
@@ -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
diff --git a/tnc/rig.py b/tnc/rig.py
new file mode 100644
index 00000000..c974bd81
--- /dev/null
+++ b/tnc/rig.py
@@ -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()
diff --git a/tnc/rigctld.py b/tnc/rigctld.py
deleted file mode 100644
index 526d0e90..00000000
--- a/tnc/rigctld.py
+++ /dev/null
@@ -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]
-
diff --git a/tnc/sock.py b/tnc/sock.py
index 38e8f627..fe5df197 100644
--- a/tnc/sock.py
+++ b/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.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),
diff --git a/tnc/static.py b/tnc/static.py
index 060e988f..c110f064 100644
--- a/tnc/static.py
+++ b/tnc/static.py
@@ -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'