Merge branch 'main' into refactor_N2KIQ-202205-2

This commit is contained in:
Paul Kronenwetter 2022-05-28 11:52:05 -04:00
commit 6a565ffe41
41 changed files with 305 additions and 346 deletions

View file

@ -4,7 +4,7 @@ on: [push]
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally
# The CMake configure and build commands are platform-agnostic and should work equally
# well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix

View file

@ -12,7 +12,7 @@ My attempt to create a free and open-source TNC with a GUI for [codec2](https://
Please keep in mind, that this project is still a prototype with many issues which need to be solved.
Build steps for other OS than Ubuntu are provided, but not fully working, yet.
Please check the [Releases](https://github.com/DJ2LS/FreeDATA/releases) section for downloading nightly builds
Please check the ['Releases'](https://github.com/DJ2LS/FreeDATA/releases) section for downloading nightly builds
## Preview
![preview](https://github.com/DJ2LS/FreeDATA/blob/main/documentation/FreeDATA_preview.gif?raw=true "Preview")
@ -22,7 +22,7 @@ Please check the [Releases](https://github.com/DJ2LS/FreeDATA/releases) section
FreeDV Codec 2 : https://github.com/drowe67/codec2
* xssfox, her repository helped me a lot in an early stage of development -
xssfox : https://github.com/xssfox/freedv-tnc
* Wolfgang, for lending me his radio so I'm able to do real hf tests
* Wolfgang, for lending me his radio, so I'm able to do real hf tests
## Running the Ubuntu app bundle
Download the latest developer release from the releases section, unpack it and just start the ".AppImage file". No more dependencies

View file

@ -217,7 +217,7 @@ exports.getDaemonState = function() {
// START TNC
// ` `== multi line string
exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwith_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq) {
exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq) {
var json_command = JSON.stringify({
type: 'set',
command: 'start_tnc',
@ -240,7 +240,7 @@ exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, de
enable_scatter: enable_scatter,
enable_fft: enable_fft,
enable_fsk: enable_fsk,
low_bandwith_mode : low_bandwith_mode,
low_bandwidth_mode : low_bandwidth_mode,
tuning_range_fmin : tuning_range_fmin,
tuning_range_fmax : tuning_range_fmax,
tx_audio_level : tx_audio_level,

View file

@ -68,7 +68,7 @@ const configDefaultSettings = '{\
"enable_scatter" : "False",\
"enable_fft" : "False",\
"enable_fsk" : "False",\
"low_bandwith_mode" : "False",\
"low_bandwidth_mode" : "False",\
"theme" : "default",\
"screen_height" : 430,\
"screen_width" : 1050,\

View file

@ -112,7 +112,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
document.getElementById("scatterSwitch").value = config.enable_scatter;
document.getElementById("fftSwitch").value = config.enable_fft;
//document.getElementById("500HzModeSwitch").value = config.low_bandwith_mode;
//document.getElementById("500HzModeSwitch").value = config.low_bandwidth_mode;
//document.getElementById("fskModeSwitch").value = config.enable_fsk;
//document.getElementById("respondCQSwitch").value = config.respond_to_cq;
@ -132,7 +132,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
document.getElementById("fftSwitch").checked = false;
}
if(config.low_bandwith_mode == 'True'){
if(config.low_bandwidth_mode == 'True'){
document.getElementById("500HzModeSwitch").checked = true;
} else {
document.getElementById("500HzModeSwitch").checked = false;
@ -522,9 +522,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
// enable 500z Switch clicked
document.getElementById("500HzModeSwitch").addEventListener("click", () => {
if(document.getElementById("500HzModeSwitch").checked == true){
config.low_bandwith_mode = "True";
config.low_bandwidth_mode = "True";
} else {
config.low_bandwith_mode = "False";
config.low_bandwidth_mode = "False";
}
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
});
@ -650,9 +650,9 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
}
if (document.getElementById("500HzModeSwitch").checked == true){
var low_bandwith_mode = "True";
var low_bandwidth_mode = "True";
} else {
var low_bandwith_mode = "False";
var low_bandwidth_mode = "False";
}
if (document.getElementById("fskModeSwitch").checked == true){
@ -732,7 +732,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
config.enable_scatter = enable_scatter;
config.enable_fft = enable_fft;
config.enable_fsk = enable_fsk;
config.low_bandwith_mode = low_bandwith_mode;
config.low_bandwidth_mode = low_bandwidth_mode;
config.tx_audio_level = tx_audio_level;
config.respond_to_cq = respond_to_cq;
@ -753,7 +753,7 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
*/
daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwith_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq);
daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq);
})
@ -1152,8 +1152,8 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
// SET MODE
document.getElementById("mode").innerHTML = arg.mode;
// SET BANDWITH
document.getElementById("bandwith").innerHTML = arg.bandwith;
// SET bandwidth
document.getElementById("bandwidth").innerHTML = arg.bandwidth;
// SET BYTES PER MINUTE
if (typeof(arg.arq_bytes_per_minute) == 'undefined') {

View file

@ -55,7 +55,7 @@ client.on('connect', function(data) {
//channel_state: "-",
frequency: "-",
mode: "-",
bandwith: "-",
bandwidth: "-",
rms_level: 0
};
ipcRenderer.send('request-update-tnc-state', Data);
@ -84,7 +84,7 @@ client.on('error', function(data) {
//channel_state: "-",
frequency: "-",
mode: "-",
bandwith: "-",
bandwidth: "-",
rms_level: 0
};
@ -199,7 +199,7 @@ client.on('data', function(socketdata) {
frequency: data['frequency'],
speed_level: data['speed_level'],
mode: data['mode'],
bandwith: data['bandwith'],
bandwidth: data['bandwidth'],
rms_level: data['audio_rms'],
fft: data['fft'],
channel_busy: data['channel_busy'],

View file

@ -32,7 +32,7 @@
<! ------Chats area ---------------------------------------------------------------------->
<div class="container-fluid m-0 p-0">
<div class="input-group bottom-0 m-0 w-100">
<input class="form-control w-50" maxlength="9" style="text-transform:uppercase;" id="chatModuleNewDxCall" placeholder="DX CALL"></input>
<input class="form-control w-50" maxlength="9" style="text-transform:uppercase;" id="chatModuleNewDxCall" placeholder="DX CALL">
<button class="btn btn-sm btn-success w-50" id="createNewChatButton" type="button"><i class="bi bi-pencil-square" style="font-size: 1.2rem;"></i></button>
</div>
</div>
@ -61,7 +61,7 @@
<div class="container-fluid mt-2 p-0">
<div class="input-group bottom-0 w-100">
<!--<input class="form-control" maxlength="8" style="max-width: 6rem; text-transform:uppercase; display:none" id="chatModuleDxCall" placeholder="DX CALL"></input>-->
<!--<button class="btn btn-sm btn-primary me-2" id="emojipickerbutton" type="button">--><i id="emojipickerbutton" class="bi bi-emoji-smile m-1" style="font-size: 1.5rem; color: grey;"></i></button>
<!--<button class="btn btn-sm btn-primary me-2" id="emojipickerbutton" type="button">--><i id="emojipickerbutton" class="bi bi-emoji-smile m-1" style="font-size: 1.5rem; color: grey;"></i><!--</button>-->
<!--<input class="form-control rounded-pill m-1 p-1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></input>-->
<textarea class="form-control rounded-pill m-1 p-1" rows="1" id="chatModuleMessage" placeholder="Message - Send with [Enter]"></textarea>

View file

@ -70,7 +70,7 @@
</button>
</span>
<span data-bs-placement="bottom" data-bs-toggle="tooltip" data-bs-html="false" title="Send files through HF. This is currently under development!">
<button class="btn btn-sm btn-primary me-2" id="openDataModule" data-bs-toggle="offcanvas" data-bs-target="#transmitFileSidebar" type="button" style="display: None;" disabeld> <strong>TX File </strong>
<button class="btn btn-sm btn-primary me-2" id="openDataModule" data-bs-toggle="offcanvas" data-bs-target="#transmitFileSidebar" type="button" style="display: None;"> <strong>TX File </strong>
<i class="bi bi-file-earmark-arrow-up-fill" style="font-size: 1rem; color: white;"></i>
</button>
</span>
@ -1023,7 +1023,6 @@
</div>
</div>
</div>
</div>
<!--end of blur div -->
<!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------>
<nav class="navbar fixed-bottom navbar-light bg-light">
@ -1054,7 +1053,7 @@
<div class="input-group input-group-sm">
<!--<span class="input-group-text" id="basic-addon1"><strong>Freq</strong></span>--> <span class="input-group-text" id="frequency">---</span>
<!--<span class="input-group-text" id="basic-addon1"><strong>Mode</strong></span>--> <span class="input-group-text" id="mode">---</span>
<!--<span class="input-group-text" id="basic-addon1"><strong>BW</strong></span>--> <span class="input-group-text" id="bandwith">---</span>
<!--<span class="input-group-text" id="basic-addon1"><strong>BW</strong></span>--> <span class="input-group-text" id="bandwidth">---</span>
</div>
</div>
<div class="container-fluid p-0" style="width:12rem">

View file

@ -102,7 +102,7 @@ python3 test_tx.py --mode datac1 --delay 500 --frames 2 --bursts 1 | python3 tes
## AUDIO test via virtual audio devices
### Important:
The virtual audio devices are great for testing, but they are also a little bit tricky to handle. So there's a high chance, the tests will fail, if you are running them via virtual audio devices. You should run the tests several times, while keeping this in mind. Most time the ctest is working even if it is failing.
The virtual audio devices are great for testing, but they are also a little tricky to handle. So there's a high chance, the tests will fail, if you are running them via virtual audio devices. You should run the tests several times, while keeping this in mind. Most time the ctest is working even if it is failing.
1. Create virtual audio devices. Note: This command needs to be run again after every reboot
```

View file

@ -18,6 +18,7 @@ class DEBUGLEVEL(Enum):
RIG_DEBUG_TRACE = 5
RIG_DEBUG_CACHE = 6
class RETCODE(Enum):
RIG_OK = 0
RIG_EINVAL = 1
@ -38,13 +39,9 @@ class RETCODE(Enum):
RIG_EVFO = 16
RIG_EDOM = 17
libname = pathlib.Path("../tnc/lib/hamlib/linux/libhamlib.so")
hamlib = ctypes.CDLL(libname)
class SERIAL(ctypes.Structure):
_fields_ = [
("data_bits", ctypes.c_int),
@ -53,17 +50,20 @@ class SERIAL(ctypes.Structure):
("parity", ctypes.c_int),
("handshake", ctypes.c_void_p),
]
class PARM(ctypes.Structure):
_fields_ = [
("serial", SERIAL),
]
class TYPE(ctypes.Structure):
_fields_ = [
("rig", ctypes.c_void_p),
]
class MYPORT(ctypes.Structure):
_fields_ = [
("pathname", ctypes.c_char),
@ -74,16 +74,14 @@ class MYPORT(ctypes.Structure):
]
hamlib.rig_set_debug(9) #6
myrig_model = 3085 #3085 = ICOM 6 = DUMMY
hamlib.rig_set_debug(9) # 6
myrig_model = 3085 # 3085 = ICOM 6 = DUMMY
myport = MYPORT()
myport.parm.serial.data_bits = 7
myport.parm.serial.stop_bits = 2
myport.parm.serial.rate = 9600
rig = hamlib.rig_init(myrig_model)
retcode = hamlib.rig_set_parm(rig, 'stop_bits', 5)
@ -111,15 +109,11 @@ print(retcode)
'''
retcode = hamlib.rig_open(rig)
print(retcode)
hamlib.rig_close(rig)
'''
#riginfo = create_string_buffer(1024)
#retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
# riginfo = create_string_buffer(1024)
# retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
'''
char riginfo[1024];

View file

@ -188,7 +188,7 @@ for i in range(N_BURSTS):
) # use this if CRC16 checksum is required ( DATA1-3)
buffer[
: len(data_out)
] = data_out # set buffersize to length of data which will be send
] = data_out # set buffer size to length of data which will be sent
crc = ctypes.c_ushort(
c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)

View file

@ -17,7 +17,7 @@ import threading
import sys
import argparse
#--------------------------------------------GET PARAMETER INPUTS
# --------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int)
parser.add_argument('--frames', dest="N_FRAMES_PER_BURST", default=0, type=int)
@ -44,23 +44,23 @@ DEBUGGING_MODE = args.DEBUGGING_MODE
AUDIO_FRAMES_PER_BUFFER = 2048
MODEM_SAMPLE_RATE = 8000
#-------------------------------------------- LOAD FREEDV
# -------------------------------------------- LOAD FREEDV
libname = pathlib.Path().absolute() / "codec2/build_linux/src/libcodec2.so"
c_lib = ctypes.CDLL(libname)
#--------------------------------------------CREATE PYAUDIO INSTANCE
# --------------------------------------------CREATE PYAUDIO INSTANCE
p = pyaudio.PyAudio()
#--------------------------------------------GET SUPPORTED SAMPLE RATES FROM SOUND DEVICE
# --------------------------------------------GET SUPPORTED SAMPLE RATES FROM SOUND DEVICE
#AUDIO_SAMPLE_RATE_TX = int(p.get_device_info_by_index(AUDIO_OUTPUT_DEVICE)['defaultSampleRate'])
#AUDIO_SAMPLE_RATE_RX = int(p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['defaultSampleRate'])
# AUDIO_SAMPLE_RATE_TX = int(p.get_device_info_by_index(AUDIO_OUTPUT_DEVICE)['defaultSampleRate'])
# AUDIO_SAMPLE_RATE_RX = int(p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['defaultSampleRate'])
AUDIO_SAMPLE_RATE_TX = 8000
AUDIO_SAMPLE_RATE_RX = 8000
#--------------------------------------------OPEN AUDIO CHANNEL RX
# --------------------------------------------OPEN AUDIO CHANNEL RX
stream_tx = p.open(format=pyaudio.paInt16,
channels=1,
rate=AUDIO_SAMPLE_RATE_TX,
frames_per_buffer=AUDIO_FRAMES_PER_BUFFER, #n_nom_modem_samples
frames_per_buffer=AUDIO_FRAMES_PER_BUFFER, # n_nom_modem_samples
output=True,
output_device_index=AUDIO_OUTPUT_DEVICE,
)
@ -74,7 +74,7 @@ stream_rx = p.open(format=pyaudio.paInt16,
)
# GENERAL PARAMETERS
# GENERAL PARAMETERS
c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
@ -93,26 +93,26 @@ def send_pong(burst,n_total_burst,frame,n_total_frame):
bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8)
payload_per_frame = bytes_per_frame -2
n_nom_modem_samples = c_lib.freedv_get_n_nom_modem_samples(freedv)
n_tx_modem_samples = c_lib.freedv_get_n_tx_modem_samples(freedv) #get n_tx_modem_samples which defines the size of the modulation object # --> *2
n_tx_modem_samples = c_lib.freedv_get_n_tx_modem_samples(freedv) # get n_tx_modem_samples which defines the size of the modulation object # --> *2
mod_out = ctypes.c_short * n_tx_modem_samples
mod_out = mod_out()
mod_out_preamble = ctypes.c_short * (1760*2) #1760 for mode 10,11,12 #4000 for mode 9
mod_out_preamble = ctypes.c_short * (1760*2) # 1760 for mode 10,11,12 #4000 for mode 9
mod_out_preamble = mod_out_preamble()
buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
buffer[:len(data_out)] = data_out # set buffersize to length of data which will be send
buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
buffer[:len(data_out)] = data_out # set buffer size to length of data which will be sent
crc = ctypes.c_ushort(c_lib.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
buffer += crc # append crc16 to buffer
crc = crc.value.to_bytes(2, byteorder='big') # convert crc to 2 byte hex string
buffer += crc # append crc16 to buffer
c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble);
txbuffer = bytearray()
txbuffer += bytes(mod_out_preamble)
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
c_lib.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer
c_lib.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer
txbuffer += bytes(mod_out)
stream_tx.write(bytes(txbuffer))
@ -126,30 +126,28 @@ def send_pong(burst,n_total_burst,frame,n_total_frame):
freedv = c_lib.freedv_open(FREEDV_RX_MODE)
bytes_per_frame = int(c_lib.freedv_get_bits_per_modem_frame(freedv)/8)
n_max_modem_samples = c_lib.freedv_get_n_max_modem_samples(freedv)
bytes_out = (ctypes.c_ubyte * bytes_per_frame) #bytes_per_frame
bytes_out = bytes_out() #get pointer from bytes_out
bytes_out = (ctypes.c_ubyte * bytes_per_frame) # bytes_per_frame
bytes_out = bytes_out() # get pointer from bytes_out
receive = True
while receive == True:
while receive:
time.sleep(0.01)
data_in = b''
nin = c_lib.freedv_nin(freedv)
nin_converted = int(nin*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE))
if DEBUGGING_MODE == True:
if DEBUGGING_MODE:
print("-----------------------------")
print("NIN: " + str(nin) + " [ " + str(nin_converted) + " ]")
data_in = stream_rx.read(nin_converted, exception_on_overflow = False)
data_in = data_in.rstrip(b'\x00')
c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), bytes_out, data_in] # check if really neccessary
nbytes = c_lib.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio
c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), bytes_out, data_in] # check if really neccessary
nbytes = c_lib.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio
if DEBUGGING_MODE == True:
if DEBUGGING_MODE:
print("SYNC: " + str(c_lib.freedv_get_rx_status(freedv)))
if nbytes == bytes_per_frame:

View file

@ -61,6 +61,7 @@ def test_highsnr_arq_short(freedv_mode: str, n_frames_per_burst: int):
# This test isn't complete yet, or is obsolete.
assert False
if __name__ == "__main__":
# Run pytest with the current script as the filename.
ecode = pytest.main(["-v", sys.argv[0]])

View file

@ -14,7 +14,7 @@ import numpy as np
import pytest
BUFFER_SZ = 1024
N_MAX = 100 # write a repeating sequence of 0..N_MAX-1
N_MAX = 100 # write a repeating sequence of 0....N_MAX-1
WRITE_SZ = 10 # different read and write sized buffers
READ_SZ = 8
NTESTS = 10000

View file

@ -72,7 +72,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices

View file

@ -71,7 +71,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices

View file

@ -77,7 +77,7 @@ class Test:
self.resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_OUTPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices
@ -189,7 +189,7 @@ class Test:
payload_per_frame = bytes_per_frame - 2
buffer = bytearray(payload_per_frame)
# set buffersize to length of data which will be send
# set buffer size to length of data which will be sent
buffer[: len(self.data_out)] = self.data_out
crc = ctypes.c_ushort(

View file

@ -76,7 +76,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices

View file

@ -76,7 +76,7 @@ class Test:
self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE
) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_INPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices

View file

@ -82,7 +82,7 @@ class Test:
self.resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if self.AUDIO_OUTPUT_DEVICE != -1:
self.p = pyaudio.PyAudio()
# auto search for loopback devices
@ -196,7 +196,7 @@ class Test:
) # use this if CRC16 checksum is required ( DATA1-3)
buffer[
: len(self.data_out)
] = self.data_out # set buffersize to length of data which will be send
] = self.data_out # set buffer size to length of data which will be sent
# create crc for data frame - we are using the crc function shipped with codec2 to avoid
# crc algorithm incompatibilities

View file

@ -67,7 +67,7 @@ def test_mm_rx():
resampler = codec2.resampler()
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if AUDIO_INPUT_DEVICE != -1:
p_audio = pyaudio.PyAudio()
# auto search for loopback devices

View file

@ -93,7 +93,7 @@ def test_mm_tx():
payload_per_frame = bytes_per_frame - 2
buffer = bytearray(payload_per_frame)
# Set buffersize to length of data which will be send
# Set buffer size to length of data which will be sent
buffer[: len(data_out)] = data_out
# Generate CRC16

View file

@ -47,7 +47,7 @@ def test_rx():
# make sure our resampler will work
assert (AUDIO_SAMPLE_RATE_RX / MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if AUDIO_INPUT_DEVICE != -1:
# auto search for loopback devices
if AUDIO_INPUT_DEVICE == -2:

View file

@ -107,7 +107,7 @@ def test_valid_disconnect(mycall: str, dxcall: str):
# Set the SSIDs we'll use for this test.
static.SSID_LIST = [0, 1, 2, 3, 4]
# Setup the static parameters for the connection.
# set up the static parameters for the connection.
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
static.MYCALLSIGN = mycallsign
@ -160,7 +160,7 @@ def test_foreign_disconnect(mycall: str, dxcall: str):
:return: Bytearray of the requested frame
:rtype: bytearray
"""
# Setup the static parameters for the connection.
# set up the static parameters for the connection.
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
static.MYCALLSIGN = mycallsign

View file

@ -37,7 +37,7 @@ def test_tx():
AUDIO_SAMPLE_RATE_TX = 48000
assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0
# check if we want to use an audio device then do an pyaudio init
# check if we want to use an audio device then do a pyaudio init
if AUDIO_OUTPUT_DEVICE != -1:
# auto search for loopback devices
if AUDIO_OUTPUT_DEVICE == -2:
@ -109,7 +109,7 @@ def test_tx():
# Create buffer for data
# Use this if CRC16 checksum is required (DATA1-3)
buffer = bytearray(payload_bytes_per_frame)
# set buffersize to length of data which will be send
# set buffer size to length of data which will be sent
buffer[: len(data_out)] = data_out
# Create CRC for data frame - we are using the CRC function shipped with codec2 to avoid

View file

@ -1,7 +1,8 @@
"""
Gather information about audio devices.
"""
import atexit
import json
import multiprocessing
import sys
import sounddevice as sd

View file

@ -150,6 +150,7 @@ api.FREEDV_MODE_DATAC3 = 12 # type: ignore
api.FREEDV_MODE_DATAC0 = 14 # type: ignore
api.FREEDV_MODE_FSK_LDPC = 9 # type: ignore
# -------------------------------- FSK LDPC MODE SETTINGS
@ -175,7 +176,7 @@ adv.Rs = 100 # symbol rate
adv.Fs = 8000 # sample rate
adv.first_tone = 1500 # first tone freq
adv.tone_spacing = 200 # shift between tones
adv.codename = 'H_128_256_5'.encode('utf-8') # code word
adv.codename = "H_128_256_5".encode("utf-8") # code word
HRA_112_112 rate 0.50 (224,112) BPF: 14 not working
HRA_56_56 rate 0.50 (112,56) BPF: 7 not working
@ -267,6 +268,7 @@ api.rx_sync_flags_to_text = [ # type: ignore
"EBST",
]
# Audio buffer ---------------------------------------------------------
class audio_buffer:
"""

View file

@ -55,8 +55,7 @@ class DAEMON:
Daemon class
"""
log = structlog.get_logger(__name__)
log = structlog.get_logger("DAEMON")
def __init__(self):
# load crc engine
@ -80,7 +79,7 @@ class DAEMON:
"""
Update audio devices and set to static
"""
while 1:
while True:
try:
if not static.TNCSTARTED:
(
@ -92,16 +91,14 @@ class DAEMON:
"[DMN] update_audio_devices: Exception gathering audio devices:",
e=err1,
)
# print(e)
time.sleep(1)
def update_serial_devices(self):
"""
Update serial devices and set to static
"""
while 1:
while True:
try:
# print("update serial")
serial_devices = []
ports = serial.tools.list_ports.comports()
for port, desc, hwid in ports:
@ -121,13 +118,12 @@ class DAEMON:
"[DMN] update_serial_devices: Exception gathering serial devices:",
e=err1,
)
# print(e)
def worker(self):
"""
Worker to handle the received commands
"""
while 1:
while True:
try:
data = self.daemon_queue.get()
@ -148,7 +144,7 @@ class DAEMON:
# data[15] rigctld_port
# data[16] send_scatter
# data[17] send_fft
# data[18] low_bandwith_mode
# data[18] low_bandwidth_mode
# data[19] tuning_range_fmin
# data[20] tuning_range_fmax
# data[21] enable FSK
@ -250,9 +246,9 @@ class DAEMON:
command.append("freedata-tnc.exe")
command += options
p = subprocess.Popen(command)
proc = subprocess.Popen(command)
atexit.register(p.kill)
atexit.register(proc.kill)
self.log.info("[DMN] TNC started", path="binary")
except FileNotFoundError as err1:
@ -265,12 +261,12 @@ class DAEMON:
command.append("main.py")
command += options
p = subprocess.Popen(command)
atexit.register(p.kill)
proc = subprocess.Popen(command)
atexit.register(proc.kill)
self.log.info("[DMN] TNC started", path="source")
static.TNCPROCESS = p # .pid
static.TNCPROCESS = proc
static.TNCSTARTED = True
"""
# WE HAVE THIS PART in SOCKET
@ -328,7 +324,7 @@ class DAEMON:
rigctld_port=rigctld_port,
)
hamlib_version = rig.hamlib_version
# hamlib_version = rig.hamlib_version
hamlib.set_ptt(True)
pttstate = hamlib.get_ptt()
@ -351,12 +347,11 @@ class DAEMON:
except Exception as err1:
self.log.error("[DMN] worker: Exception: ", e=err1)
# print(e)
if __name__ == "__main__":
mainlog = structlog.get_logger(__file__)
# we need to run this on windows for multiprocessing support
# we need to run this on Windows for multiprocessing support
multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS
@ -365,7 +360,7 @@ if __name__ == "__main__":
"--port",
dest="socket_port",
default=3001,
help="Socket port in the range of 1024-65536",
help="Socket port in the range of 1024-65535",
type=int,
)
ARGS = PARSER.parse_args()

View file

@ -34,7 +34,7 @@ DATA_QUEUE_RECEIVED = queue.Queue()
class DATA:
"""Terminal Node Controller for FreeDATA"""
log = structlog.get_logger(__name__)
log = structlog.get_logger("DATA")
def __init__(self) -> None:
# Initial call sign. Will be overwritten later
@ -76,7 +76,7 @@ class DATA:
self.n_retries_per_burst = 0
# Flag to indicate if we recevied a low bandwidth mode channel opener
self.received_low_bandwidth_mode = False
self.received_LOW_BANDWIDTH_MODE = False
self.data_channel_max_retries = 5
self.datachannel_timeout = False
@ -100,7 +100,7 @@ class DATA:
# Mode list for selecting between low bandwidth ( 500Hz ) and modes with higher bandwidth
# but ability to fall back to low bandwidth modes if needed.
if static.LOW_BANDWITH_MODE:
if static.LOW_BANDWIDTH_MODE:
# List of codec2 modes to use in "low bandwidth" mode.
self.mode_list = self.mode_list_low_bw
# list of times to wait for corresponding mode in seconds
@ -412,6 +412,7 @@ class DATA:
def send_retransmit_request_frame(self, freedv) -> None:
# check where a None is in our burst buffer and do frame+1, beacuse lists start at 0
# FIXME: Check to see if there's a `frame - 1` in the receive portion. Remove both if there is.
missing_frames = [
frame + 1
for frame, element in enumerate(static.RX_BURST_BUFFER)
@ -419,7 +420,7 @@ class DATA:
]
# set n frames per burst to modem
# this is an idea so its not getting lost....
# this is an idea, so it's not getting lost....
# we need to work on this
codec2.api.freedv_set_frames_per_burst(freedv, len(missing_frames))
@ -436,7 +437,7 @@ class DATA:
# Transmit frame
self.enqueue_frame_for_tx(rpt_frame)
def send_burst_nack_frame(self, snr=0) -> None:
def send_burst_nack_frame(self, snr: float = 0) -> None:
"""Build and send NACK frame for received DATA frame"""
nack_frame = bytearray(14)
nack_frame[:1] = bytes([63])
@ -448,7 +449,7 @@ class DATA:
# TRANSMIT NACK FRAME FOR BURST
self.enqueue_frame_for_tx(nack_frame)
def send_burst_nack_frame_watchdog(self, snr=0) -> None:
def send_burst_nack_frame_watchdog(self, snr: float = 0) -> None:
"""Build and send NACK frame for watchdog timeout"""
nack_frame = bytearray(14)
nack_frame[:1] = bytes([64])
@ -471,13 +472,13 @@ class DATA:
self.enqueue_frame_for_tx(disconnection_frame, copies=5, repeat_delay=250)
def arq_data_received(
self, data_in: bytes, bytes_per_frame: int, snr: int, freedv
self, data_in: bytes, bytes_per_frame: int, snr: float, freedv
) -> None:
"""
Args:
data_in:bytes:
bytes_per_frame:int:
snr:int:
snr:float:
freedv:
Returns:
@ -559,7 +560,7 @@ class DATA:
# Here we are going to search for our data in the last received bytes.
# This reduces the chance we will lose the entire frame in the case of signalling frame loss
# static.RX_FRAME_BUFFER --> exisitng data
# static.RX_FRAME_BUFFER --> existing data
# temp_burst_buffer --> new data
# search_area --> area where we want to search
search_area = 510
@ -582,12 +583,12 @@ class DATA:
area=search_area,
pos=get_position,
)
# if we dont find data n this range, we really have new data and going to replace it
# If we don't find data in this range, we really have new data and going to replace it
else:
static.RX_FRAME_BUFFER += temp_burst_buffer
self.log.debug("[TNC] ARQ | RX | appending data to buffer")
# lets check if we didnt receive a BOF and EOF yet to avoid sending
# Check if we didn't receive a BOF and EOF yet to avoid sending
# ack frames if we already received all data
if (
not self.rx_frame_bof_received
@ -623,6 +624,7 @@ class DATA:
# Check if we received last frame of burst - this is an indicator for missed frames.
# With this way of doing this, we always MUST receive the last
# frame of a burst otherwise the entire burst is lost
# TODO: See if a timeout on the send side with re-transmit last burst would help.
self.log.debug(
"[TNC] all frames in burst received:",
frame=RX_N_FRAME_OF_BURST,
@ -648,6 +650,7 @@ class DATA:
eof_position = static.RX_FRAME_BUFFER.find(self.data_frame_eof)
# get total bytes per transmission information as soon we recevied a frame with a BOF
if bof_position >= 0:
payload = static.RX_FRAME_BUFFER[
bof_position + len(self.data_frame_bof) : eof_position
@ -828,7 +831,7 @@ class DATA:
tx_start_of_transmission = time.time()
self.calculate_transfer_rate_tx(tx_start_of_transmission, 0, len(data_out))
# Append a crc and the begin and end of file indicators
# Append a crc at the beginning and end of file indicators
frame_payload_crc = helpers.get_crc_32(data_out)
self.log.debug("[TNC] frame payload CRC:", crc=frame_payload_crc)
@ -861,7 +864,7 @@ class DATA:
self.log.debug("[TNC] FIXED MODE:", mode=data_mode)
else:
# we are doing a modulo check of transmission retries of the actual burst
# every 2nd retry which failes, decreases speedlevel by 1.
# every 2nd retry which fails, decreases speedlevel by 1.
# as soon as we received an ACK for the current burst, speed_level will increase
# by 1.
# The intent is to optimize speed by adapting to the current RF conditions.
@ -1200,9 +1203,9 @@ class DATA:
missing = missing_area[i : i + 2]
self.rpt_request_buffer.insert(0, missing)
# ############################################################################################################
############################################################################################################
# ARQ SESSION HANDLER
# ############################################################################################################
############################################################################################################
def arq_session_handler(self) -> bool:
"""
Create a session with `static.DXCALLSIGN` and wait until the session is open.
@ -1211,7 +1214,7 @@ class DATA:
True if the session was opened successfully
False if the session open request failed
"""
# das hier müssen wir checken. Sollte vielleicht in INIT!!!
# TODO: we need to check this, maybe placing it to class init
self.datachannel_timeout = False
self.log.info(
"[TNC] SESSION ["
@ -1262,7 +1265,7 @@ class DATA:
+ "]>>?<<["
+ str(static.DXCALLSIGN, "UTF-8")
+ "]",
a=attempt + 1,
a=attempt + 1, # Adjust for 0-based for user display
state=static.ARQ_SESSION_STATE,
)
@ -1278,7 +1281,7 @@ class DATA:
return True
# Session connect timeout, send close_session frame to
# attempt to cleanup the far-side, if it received the
# attempt to clean up the far-side, if it received the
# open_session frame and can still hear us.
if not static.ARQ_SESSION:
self.close_session()
@ -1460,14 +1463,14 @@ class DATA:
self.transmission_uuid = transmission_uuid
# wait a moment for the case, an heartbeat is already on the way back to us
# wait a moment for the case, a heartbeat is already on the way back to us
if static.ARQ_SESSION:
time.sleep(0.5)
self.datachannel_timeout = False
# we need to compress data for gettin a compression factor.
# so we are compressing twice. This is not that nice and maybe theres another way
# so we are compressing twice. This is not that nice and maybe there is another way
# for calculating transmission statistics
static.ARQ_COMPRESSION_FACTOR = len(data_out) / len(zlib.compress(data_out))
@ -1502,7 +1505,7 @@ class DATA:
# Update data_channel timestamp
self.data_channel_last_received = int(time.time())
if static.LOW_BANDWITH_MODE and mode == 255:
if static.LOW_BANDWIDTH_MODE and mode == 255:
frametype = bytes([227])
self.log.debug("[TNC] Requesting low bandwidth mode")
@ -1595,11 +1598,11 @@ class DATA:
frametype = int.from_bytes(bytes(data_in[:1]), "big")
# check if we received low bandwidth mode
if frametype == 225:
self.received_low_bandwidth_mode = False
self.received_LOW_BANDWIDTH_MODE = False
self.mode_list = self.mode_list_high_bw
self.time_list = self.time_list_high_bw
else:
self.received_low_bandwidth_mode = True
self.received_LOW_BANDWIDTH_MODE = True
self.mode_list = self.mode_list_low_bw
self.time_list = self.time_list_low_bw
self.speed_level = len(self.mode_list) - 1
@ -1645,8 +1648,8 @@ class DATA:
# Update data_channel timestamp
self.data_channel_last_received = int(time.time())
# Select the frame type based on the mode we are in
if static.LOW_BANDWITH_MODE or self.received_low_bandwidth_mode:
# Select the frame type based on the current TNC mode
if static.LOW_BANDWIDTH_MODE or self.received_LOW_BANDWIDTH_MODE:
frametype = bytes([228])
self.log.debug("[TNC] Responding with low bandwidth mode")
else:
@ -1691,12 +1694,12 @@ class DATA:
frametype = int.from_bytes(bytes(data_in[:1]), "big")
if frametype == 228:
self.received_low_bandwidth_mode = True
self.received_LOW_BANDWIDTH_MODE = True
self.mode_list = self.mode_list_low_bw
self.time_list = self.time_list_low_bw
self.log.debug("[TNC] low bandwidth mode", modes=self.mode_list)
else:
self.received_low_bandwidth_mode = False
self.received_LOW_BANDWIDTH_MODE = False
self.mode_list = self.mode_list_high_bw
self.time_list = self.time_list_high_bw
self.log.debug("[TNC] high bandwidth mode", modes=self.mode_list)
@ -1728,6 +1731,7 @@ class DATA:
static.TNC_STATE = "IDLE"
static.ARQ_STATE = False
static.INFO.append("PROTOCOL;VERSION_MISMATCH")
# TODO: We should display a message to this effect on the UI.
self.log.warning(
"[TNC] protocol version mismatch:",
received=protocol_version,
@ -1901,13 +1905,14 @@ class DATA:
"""
Controlling function for running a beacon
Args:
self: arq class
Returns:
"""
try:
while 1:
while True:
time.sleep(0.5)
while static.BEACON_STATE:
if (
@ -1942,8 +1947,8 @@ class DATA:
):
time.sleep(0.01)
except Exception as e:
self.log.debug("[TNC] run_beacon: ", exception=e)
except Exception as err:
self.log.debug("[TNC] run_beacon: ", exception=err)
def received_beacon(self, data_in: bytes) -> None:
"""
@ -2156,8 +2161,8 @@ class DATA:
else:
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
except Exception as e:
self.log.error(f"[TNC] calculate_transfer_rate_rx: Exception: {e}")
except Exception as err:
self.log.error(f"[TNC] calculate_transfer_rate_rx: Exception: {err}")
static.ARQ_TRANSMISSION_PERCENT = 0.0
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
@ -2184,7 +2189,7 @@ class DATA:
self, tx_start_of_transmission: float, sentbytes: int, tx_buffer_length: int
) -> list:
"""
Calcualte Transferrate for transmission
Calculate transfer rate for transmission
Args:
tx_start_of_transmission:float:
sentbytes:int:
@ -2210,8 +2215,8 @@ class DATA:
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
except Exception as e:
self.log.error(f"[TNC] calculate_transfer_rate_tx: Exception: {e}")
except Exception as err:
self.log.error(f"[TNC] calculate_transfer_rate_tx: Exception: {err}")
static.ARQ_TRANSMISSION_PERCENT = 0.0
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
@ -2260,7 +2265,7 @@ class DATA:
static.ARQ_SPEED_LEVEL = self.speed_level
# low bandwidth mode indicator
self.received_low_bandwidth_mode = False
self.received_LOW_BANDWIDTH_MODE = False
# reset retry counter for rx channel / burst
self.n_retries_per_burst = 0
@ -2426,9 +2431,9 @@ class DATA:
def heartbeat(self) -> None:
"""
Heartbeat thread which auto resumes the heartbeat signal within an arq session
Heartbeat thread which auto pauses and resumes the heartbeat signal when in an arq session
"""
while 1:
while True:
time.sleep(0.01)
if (
static.ARQ_SESSION

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 25 21:25:14 2020
@ -255,13 +254,13 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
# we need to do this step to reduce the needed paypload by the callsign ( stripping "-" out of the callsign )
"""
callsign = bytes(bytestring[:7])
callsign = callsign.rstrip(b'\x00')
callsign = callsign.rstrip(b"\x00")
ssid = int.from_bytes(bytes(bytestring[7:8]), "big")
callsign = callsign + b'-'
callsign = callsign.decode('utf-8')
callsign = callsign + b"-"
callsign = callsign.decode("utf-8")
callsign = callsign + str(ssid)
callsign = callsign.encode('utf-8')
callsign = callsign.encode("utf-8")
return bytes(callsign)
"""
@ -310,7 +309,7 @@ def check_callsign(callsign: bytes, crc_to_check: bytes):
def encode_grid(grid):
"""
@auther: DB1UJ
@author: DB1UJ
Args:
grid:string: maidenhead QTH locater [a-r][a-r][0-9][0-9][a-x][a-x]
Returns:
@ -344,7 +343,7 @@ def encode_grid(grid):
def decode_grid(b_code_word: bytes):
"""
@auther: DB1UJ
@author: DB1UJ
Args:
b_code_word:bytes: 4 bytes with 26 bit valid data LSB
Returns:
@ -374,7 +373,7 @@ def decode_grid(b_code_word: bytes):
def encode_call(call):
"""
@auther: DB1UJ
@author: DB1UJ
Args:
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
@ -401,7 +400,7 @@ def encode_call(call):
def decode_call(b_code_word: bytes):
"""
@auther: DB1UJ
@author: DB1UJ
Args:
b_code_word:bytes: 6 bytes with 6 bits/sign valid data char signs LSB

View file

@ -25,7 +25,6 @@ import structlog
log = structlog.get_logger(__file__)
# signal handler for closing aplication
def signal_handler(sig, frame):
"""
a signal handler, which closes the network/socket when closing the application
@ -44,7 +43,7 @@ def signal_handler(sig, frame):
signal.signal(signal.SIGINT, signal_handler)
if __name__ == "__main__":
# we need to run this on windows for multiprocessing support
# This is for Windows multiprocessing support
multiprocessing.freeze_support()
# --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description="FreeDATA TNC")
@ -227,7 +226,7 @@ if __name__ == "__main__":
ARGS = PARSER.parse_args()
# additional step for beeing sure our callsign is correctly
# additional step for being sure our callsign is correctly
# in case we are not getting a station ssid
# then we are forcing a station ssid = 0
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
@ -255,7 +254,7 @@ if __name__ == "__main__":
static.ENABLE_SCATTER = ARGS.send_scatter
static.ENABLE_FFT = ARGS.send_fft
static.ENABLE_FSK = ARGS.enable_fsk
static.LOW_BANDWITH_MODE = ARGS.low_bandwith_mode
static.LOW_BANDWIDTH_MODE = ARGS.low_bandwidth_mode
static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
@ -313,5 +312,5 @@ if __name__ == "__main__":
except Exception as err:
log.error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
sys.exit(1)
while 1:
while True:
time.sleep(1)

View file

@ -44,10 +44,10 @@ RECEIVE_FSK_LDPC_1 = False
class RF:
"""Class to encapsulate interactions between the audio device and codec2"""
log = structlog.get_logger(__name__)
log = structlog.get_logger("RF")
def __init__(self) -> None:
""" """
self.sampler_avg = 0
self.buffer_avg = 0
@ -203,25 +203,17 @@ class RF:
blocksize=4800,
)
atexit.register(self.stream.stop)
self.log.info(
"[MDM] init: opened audio devices"
)
self.log.info("[MDM] init: opened audio devices")
except Exception as err:
self.log.error(
"[MDM] init: can't open audio device. Exit", e=err
)
self.log.error("[MDM] init: can't open audio device. Exit", e=err)
sys.exit(1)
try:
self.log.debug(
"[MDM] init: starting pyaudio callback"
)
self.log.debug("[MDM] init: starting pyaudio callback")
# self.audio_stream.start_stream()
self.stream.start()
except Exception as err:
self.log.error(
"[MDM] init: starting pyaudio callback failed", e=err
)
self.log.error("[MDM] init: starting pyaudio callback failed", e=err)
else:
class Object:
@ -237,9 +229,7 @@ class RF:
os.mkfifo(RXCHANNEL)
os.mkfifo(TXCHANNEL)
except Exception as err:
self.log.error(
f"[MDM] init:mkfifo: Exception: {err}"
)
self.log.info(f"[MDM] init:mkfifo: Exception: {err}")
mkfifo_write_callback_thread = threading.Thread(
target=self.mkfifo_write_callback,
@ -248,9 +238,7 @@ class RF:
)
mkfifo_write_callback_thread.start()
self.log.debug(
"[MDM] Starting mkfifo_read_callback"
)
self.log.debug("[MDM] Starting mkfifo_read_callback")
mkfifo_read_callback_thread = threading.Thread(
target=self.mkfifo_read_callback,
name="MKFIFO READ CALLBACK THREAD",
@ -338,7 +326,7 @@ class RF:
Support testing by reading the audio data from a pipe and
depositing the data into the codec data buffers.
"""
while 1:
while True:
time.sleep(0.01)
# -----read
data_in48k = bytes()
@ -368,7 +356,7 @@ class RF:
def mkfifo_write_callback(self) -> None:
"""Support testing by writing the audio data to a pipe."""
while 1:
while True:
time.sleep(0.01)
# -----write
@ -431,9 +419,7 @@ class RF:
try:
outdata[:] = data_out48k[:frames]
except IndexError as err:
self.log.debug(
f"[MDM] callback: IndexError: {err}"
)
self.log.debug(f"[MDM] callback: IndexError: {err}")
# return (data_out48k, audio.pyaudio.paContinue)
@ -568,6 +554,7 @@ class RF:
delta = chunk_length - len(c)
delta_zeros = np.zeros(delta, dtype=np.int16)
c = np.append(c, delta_zeros)
# self.log.debug("[MDM] mod out shorter than audio buffer", delta=delta)
self.modoutqueue.append(c)
@ -691,9 +678,7 @@ class RF:
while True:
data = self.modem_transmit_queue.get()
self.log.debug(
"[MDM] worker_transmit", mode=data[0]
)
self.log.debug("[MDM] worker_transmit", mode=data[0])
self.transmit(
mode=data[0], repeats=data[1], repeat_delay=data[2], frames=data[3]
)
@ -703,9 +688,7 @@ class RF:
"""Worker for FIFO queue for processing received frames"""
while True:
data = self.modem_received_queue.get()
self.log.debug(
"[MDM] worker_received: received data!"
)
self.log.debug("[MDM] worker_received: received data!")
# data[0] = bytes_out
# data[1] = freedv session
# data[2] = bytes_per_frame
@ -793,9 +776,7 @@ class RF:
) # limit to max value of -128/128 as a possible fix of #188
return static.SNR
except Exception as err:
self.log.error(
f"[MDM] calculate_snr: Exception: {err}"
)
self.log.error(f"[MDM] calculate_snr: Exception: {err}")
static.SNR = 0
return static.SNR
@ -811,7 +792,7 @@ class RF:
threading.Event().wait(0.5)
static.HAMLIB_FREQUENCY = self.hamlib.get_frequency()
static.HAMLIB_MODE = self.hamlib.get_mode()
static.HAMLIB_BANDWIDTH = self.hamlib.get_bandwith()
static.HAMLIB_BANDWIDTH = self.hamlib.get_bandwidth()
def calculate_fft(self) -> None:
"""
@ -874,9 +855,7 @@ class RF:
static.FFT = dfftlist[:320] # 320 --> bandwidth 3000
except Exception as err:
self.log.error(
f"[MDM] calculate_fft: Exception: {err}"
)
self.log.error(f"[MDM] calculate_fft: Exception: {err}")
self.log.debug("[MDM] Setting fft=0")
# else 0
static.FFT = [0]

View file

@ -32,7 +32,7 @@ try:
# installation path for Suse
sys.path.append(f"/usr/local/lib64/python{python_version}/site-packages")
# everything else... not nice, but an attempt to see how its running within app bundle
# everything else... not nice, but an attempt to see how it's running within app bundle
# this is not needed as python will be shipped with app bundle
sys.path.append("/usr/local/lib/python3.6/site-packages")
sys.path.append("/usr/local/lib/python3.7/site-packages")
@ -231,7 +231,7 @@ class radio:
return True
except Exception as err2:
mainlog.error(
self.log.error(
"[RIG] Hamlib - can't open rig", error=err2, e=sys.exc_info()[0]
)
return False
@ -245,7 +245,7 @@ class radio:
(hamlib_mode, bandwidth) = self.my_rig.get_mode()
return Hamlib.rig_strrmode(hamlib_mode)
def get_bandwith(self):
def get_bandwidth(self):
""" """
(hamlib_mode, bandwidth) = self.my_rig.get_mode()
return bandwidth

View file

@ -145,20 +145,20 @@ class radio:
def get_mode(self):
""" """
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
# (hamlib_mode, bandwidth) = self.my_rig.get_mode()
# return Hamlib.rig_strrmode(hamlib_mode)
try:
return "PKTUSB"
except Exception:
return False
def get_bandwith(self):
def get_bandwidth(self):
""" """
# (hamlib_mode, bandwith) = self.my_rig.get_mode()
bandwith = 2700
# (hamlib_mode, bandwidth) = self.my_rig.get_mode()
bandwidth = 2700
try:
return bandwith
return bandwidth
except Exception:
return False

View file

@ -21,7 +21,7 @@ class radio:
log = structlog.get_logger(__name__)
def __init__(self, hostname="localhost", port=4532, poll_rate=5, timeout=5):
"""Open a connection to rotctld, and test it for validity"""
"""Open a connection to rigctld, and test it for validity"""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# self.sock.settimeout(timeout)
@ -98,7 +98,7 @@ class radio:
self.sock.close()
self.connected = False
def send_command(self, command):
def send_command(self, command) -> bytes:
"""Send a command to the connected rotctld instance,
and return the return value.
@ -134,6 +134,8 @@ class radio:
time.sleep(0.5)
self.connect()
return b""
def get_mode(self):
""" """
try:
@ -144,13 +146,13 @@ class radio:
except Exception:
return 0
def get_bandwith(self):
def get_bandwidth(self):
""" """
try:
data = self.send_command(b"m")
data = data.split(b"\n")
bandwith = data[1]
return bandwith.decode("utf-8")
bandwidth = data[1]
return bandwidth.decode("utf-8")
except Exception:
return 0

View file

@ -26,7 +26,7 @@ class radio:
""" """
return None
def get_bandwith(self):
def get_bandwidth(self):
""" """
return None

View file

@ -5,18 +5,17 @@ Created on Fri Dec 25 21:25:14 2020
@author: DJ2LS
# GET COMMANDS
# "command" : "..."
# "command" : "..."
# SET COMMANDS
# "command" : "..."
# "parameter" : " ..."
# DATA COMMANDS
# "command" : "..."
# "type" : "..."
# "dxcallsign" : "..."
# "data" : "..."
# SET COMMANDS
# "command" : "..."
# "parameter" : " ..."
# DATA COMMANDS
# "command" : "..."
# "type" : "..."
# "dxcallsign" : "..."
# "data" : "..."
"""
import atexit
import base64
@ -85,7 +84,6 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
try:
client.send(sock_data)
except Exception as err:
# print("connection lost...")
self.log.info("[SCK] Connection lost", e=err)
self.connection_alive = False
@ -157,10 +155,12 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
self.sendThread = threading.Thread(
target=self.send_to_client, args=[], daemon=True
).start()
)
self.sendThread.start()
self.receiveThread = threading.Thread(
target=self.receive_from_client, args=[], daemon=True
).start()
)
self.receiveThread.start()
# keep connection alive until we close it
while self.connection_alive and not CLOSE_SIGNAL:
@ -192,7 +192,7 @@ def process_tnc_commands(data):
Returns:
"""
log = structlog.get_logger(__name__)
log = structlog.get_logger("process_tnc_commands")
# we need to do some error handling in case of socket timeout or decoding issue
try:
@ -456,7 +456,7 @@ def send_tnc_state():
"frequency": str(static.HAMLIB_FREQUENCY),
"speed_level": str(static.ARQ_SPEED_LEVEL),
"mode": str(static.HAMLIB_MODE),
"bandwith": str(static.HAMLIB_BANDWIDTH),
"bandwidth": str(static.HAMLIB_BANDWIDTH),
"fft": str(static.FFT),
"channel_busy": str(static.CHANNEL_BUSY),
"scatter": static.SCATTER,
@ -492,6 +492,9 @@ def send_tnc_state():
return json.dumps(output)
# This appears to have been taken out of a class, but is never called because
# the `self.request.sendall` call is a syntax error as `self` is undefined and
# we don't see errors in use.
def process_daemon_commands(data):
"""
process daemon commands
@ -570,7 +573,9 @@ def process_daemon_commands(data):
enable_scatter = str(received_json["parameter"][0]["enable_scatter"])
enable_fft = str(received_json["parameter"][0]["enable_fft"])
enable_fsk = str(received_json["parameter"][0]["enable_fsk"])
low_bandwith_mode = str(received_json["parameter"][0]["low_bandwith_mode"])
low_bandwidth_mode = str(
received_json["parameter"][0]["low_bandwidth_mode"]
)
tuning_range_fmin = str(received_json["parameter"][0]["tuning_range_fmin"])
tuning_range_fmax = str(received_json["parameter"][0]["tuning_range_fmax"])
tx_audio_level = str(received_json["parameter"][0]["tx_audio_level"])
@ -603,7 +608,7 @@ def process_daemon_commands(data):
rigctld_port,
enable_scatter,
enable_fft,
low_bandwith_mode,
low_bandwidth_mode,
tuning_range_fmin,
tuning_range_fmax,
enable_fsk,
@ -616,6 +621,7 @@ def process_daemon_commands(data):
except Exception as err:
command_response("start_tnc", False)
log.warning("[SCK] command execution error", e=err, command=received_json)
if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
try:
devicename = str(received_json["parameter"][0]["devicename"])
@ -692,9 +698,8 @@ def send_daemon_state():
else:
output["daemon_state"].append({"status": "stopped"})
jsondata = json.dumps(output)
return json.dumps(output)
return jsondata
except Exception as err:
log.warning("[SCK] error", e=err)
return None

View file

@ -8,116 +8,118 @@ Here we are saving application wide variables and stats, which have to be access
Not nice, suggestions are appreciated :-)
"""
import subprocess
VERSION = "0.4.0-alpha"
# DAEMON
DAEMONPORT = 3001
TNCSTARTED = False
TNCPROCESS = 0
DAEMONPORT: int = 3001
TNCSTARTED: bool = False
TNCPROCESS: subprocess.Popen
# Operator Defaults
MYCALLSIGN = b"AA0AA"
MYCALLSIGN_CRC = b"A"
MYCALLSIGN: bytes = b"AA0AA"
MYCALLSIGN_CRC: bytes = b"A"
DXCALLSIGN = b"AA0AA"
DXCALLSIGN_CRC = b"A"
DXCALLSIGN: bytes = b"AA0AA"
DXCALLSIGN_CRC: bytes = b"A"
MYGRID = b""
DXGRID = b""
MYGRID: bytes = b""
DXGRID: bytes = b""
SSID_LIST = [] # ssid list we are responding to
SSID_LIST: list = [] # ssid list we are responding to
LOW_BANDWITH_MODE = False
LOW_BANDWIDTH_MODE: bool = False
# ---------------------------------
# Server Defaults
HOST = "0.0.0.0"
PORT = 3000
SOCKET_TIMEOUT = 1 # seconds
HOST: str = "0.0.0.0"
PORT: int = 3000
SOCKET_TIMEOUT: int = 1 # seconds
# ---------------------------------
SERIAL_DEVICES = []
SERIAL_DEVICES: list = []
# ---------------------------------
PTT_STATE = False
TRANSMITTING = False
PTT_STATE: bool = False
TRANSMITTING: bool = False
HAMLIB_VERSION = "0"
HAMLIB_PTT_TYPE = "RTS"
HAMLIB_DEVICE_NAME = "RIG_MODEL_DUMMY_NOVFO"
HAMLIB_DEVICE_PORT = "/dev/ttyUSB0"
HAMLIB_SERIAL_SPEED = "9600"
HAMLIB_PTT_PORT = "/dev/ttyUSB0"
HAMLIB_STOP_BITS = "1"
HAMLIB_DATA_BITS = "8"
HAMLIB_HANDSHAKE = "None"
HAMLIB_RADIOCONTROL = "direct"
HAMLIB_RIGCTLD_IP = "127.0.0.1"
HAMLIB_RIGCTLD_PORT = "4532"
HAMLIB_VERSION: str = "0"
HAMLIB_PTT_TYPE: str = "RTS"
HAMLIB_DEVICE_NAME: str = "RIG_MODEL_DUMMY_NOVFO"
HAMLIB_DEVICE_PORT: str = "/dev/ttyUSB0"
HAMLIB_SERIAL_SPEED: str = "9600"
HAMLIB_PTT_PORT: str = "/dev/ttyUSB0"
HAMLIB_STOP_BITS: str = "1"
HAMLIB_DATA_BITS: str = "8"
HAMLIB_HANDSHAKE: str = "None"
HAMLIB_RADIOCONTROL: str = "direct"
HAMLIB_RIGCTLD_IP: str = "127.0.0.1"
HAMLIB_RIGCTLD_PORT: str = "4532"
HAMLIB_FREQUENCY = 0
HAMLIB_MODE = ""
HAMLIB_BANDWIDTH = 0
HAMLIB_FREQUENCY: int = 0
HAMLIB_MODE: str = ""
HAMLIB_BANDWIDTH: int = 0
# -------------------------
# FreeDV Defaults
SNR = 0
FREQ_OFFSET = 0
SCATTER = []
ENABLE_SCATTER = False
ENABLE_FSK = False
RESPOND_TO_CQ = False
SNR: float = 0
FREQ_OFFSET: float = 0
SCATTER: list = []
ENABLE_SCATTER: bool = False
ENABLE_FSK: bool = False
RESPOND_TO_CQ: bool = False
# ---------------------------------
# Audio Defaults
TX_AUDIO_LEVEL = 50
AUDIO_INPUT_DEVICES = []
AUDIO_OUTPUT_DEVICES = []
AUDIO_INPUT_DEVICE = -2
AUDIO_OUTPUT_DEVICE = -2
BUFFER_OVERFLOW_COUNTER = [0, 0, 0, 0, 0]
TX_AUDIO_LEVEL: int = 50
AUDIO_INPUT_DEVICES: list = []
AUDIO_OUTPUT_DEVICES: list = []
AUDIO_INPUT_DEVICE: int = -2
AUDIO_OUTPUT_DEVICE: int = -2
BUFFER_OVERFLOW_COUNTER: list = [0, 0, 0, 0, 0]
AUDIO_RMS = 0
FFT = [0]
ENABLE_FFT = False
CHANNEL_BUSY = None
AUDIO_RMS: int = 0
FFT: list = [0]
ENABLE_FFT: bool = False
CHANNEL_BUSY: bool = False
# ARQ PROTOCOL VERSION
ARQ_PROTOCOL_VERSION = 1
ARQ_PROTOCOL_VERSION: int = 1
# ARQ statistics
ARQ_BYTES_PER_MINUTE_BURST = 0
ARQ_BYTES_PER_MINUTE = 0
ARQ_BITS_PER_SECOND_BURST = 0
ARQ_BITS_PER_SECOND = 0
ARQ_COMPRESSION_FACTOR = 0
ARQ_TRANSMISSION_PERCENT = 0
ARQ_SPEED_LEVEL = 0
TOTAL_BYTES = 0
ARQ_BYTES_PER_MINUTE_BURST: int = 0
ARQ_BYTES_PER_MINUTE: int = 0
ARQ_BITS_PER_SECOND_BURST: int = 0
ARQ_BITS_PER_SECOND: int = 0
ARQ_COMPRESSION_FACTOR: int = 0
ARQ_TRANSMISSION_PERCENT: int = 0
ARQ_SPEED_LEVEL: int = 0
TOTAL_BYTES: int = 0
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
TNC_STATE = "IDLE"
ARQ_STATE = False
ARQ_SESSION = False
TNC_STATE: str = "IDLE"
ARQ_STATE: bool = False
ARQ_SESSION: bool = False
# disconnected, connecting, connected, disconnecting, failed
ARQ_SESSION_STATE = "disconnected"
ARQ_SESSION_STATE: str = "disconnected"
# BEACON STATE
BEACON_STATE = False
BEACON_PAUSE = False
BEACON_STATE: bool = False
BEACON_PAUSE: bool = False
# ------- RX BUFFER
RX_BUFFER = []
RX_MSG_BUFFER = []
RX_BURST_BUFFER = []
RX_FRAME_BUFFER = b""
# RX_BUFFER_SIZE = 0
RX_BUFFER: list = []
RX_MSG_BUFFER: list = []
RX_BURST_BUFFER: list = []
RX_FRAME_BUFFER: bytes = b""
# RX_BUFFER_SIZE: int = 0
# ------- HEARD STATIOS BUFFER
HEARD_STATIONS = []
# ------- HEARD STATIONS BUFFER
HEARD_STATIONS: list = []
# ------- INFO MESSAGE BUFFER
INFO = []
INFO: list = []
# ------- CODEC2 SETTINGS
TUNING_RANGE_FMIN = -50.0
TUNING_RANGE_FMAX = 50.0
TUNING_RANGE_FMIN: float = -50.0
TUNING_RANGE_FMAX: float = 50.0

View file

@ -6,19 +6,14 @@ import pyaudio
def list_audio_devices():
p = pyaudio.PyAudio()
devices = []
print("--------------------------------------------------------------------")
for x in range(0, p.get_device_count()):
devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}")
for line in devices:
print(line)
devices = [
f"{x} - {p.get_device_info_by_index(x)['name']}"
for x in range(p.get_device_count())
]
for line in devices:
print(line)
list_audio_devices()

View file

@ -11,10 +11,7 @@ import sys
import argparse
import time
#--------------------------------------------GET PARAMETER INPUTS
# --------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--port', dest="socket_port", default=3000, help="Set the port, the socket is listening on.", type=int)
parser.add_argument('--data', dest="data", default=False, help="data", type=str)

View file

@ -6,13 +6,14 @@ Created on Fri Dec 11 21:53:35 2020
@author: parallels
"""
import socket
import sys
import argparse
import random
import socket
#https://www.askpython.com/python/examples/generate-random-strings-in-python
def create_string(length):
# https://www.askpython.com/python/examples/generate-random-strings-in-python
random_string = ''
for _ in range(length):
# Considering only upper and lowercase letters
@ -22,47 +23,32 @@ def create_string(length):
random_integer = random_integer - 32 if flip_bit == 1 else random_integer
# Keep appending random characters using chr(x)
random_string += (chr(random_integer))
print("STR:" + str(random_string))
return random_string
print(f"STR: {random_string!s}")
#--------------------------------------------GET PARAMETER INPUTS
return random_string
# --------------------------------------------GET PARAMETER INPUTS
parser = argparse.ArgumentParser(description='Simons TEST TNC')
parser.add_argument('--port', dest="socket_port", default=9000, help="Set the port, the socket is listening on.", type=int)
#parser.add_argument('--data', dest="data", default=False, help="data", type=str)
parser.add_argument('--port', dest="socket_port", default=9000, help="Set the port, the socket is listening on.", type=int)
# parser.add_argument('--data', dest="data", default=False, help="data", type=str)
parser.add_argument('--random', dest="datalength", default=False, help="data", type=int)
args = parser.parse_args()
data = create_string(args.datalength)
data = bytes("ARQ:DATA:" + "" + data + "" + "\n", "utf-8")
#print(data)
HOST, PORT = "localhost", args.socket_port
#data = args.data
# data = args.data
# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
#sock.sendall(bytes(data + "\n", "utf-8"))
# sock.sendall(bytes(data + "\n", "utf-8"))
sock.sendall(data)
# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
print("Sent: {}".format(data))
print(f"Sent: {data}")