mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #399 from DJ2LS/ls-modem
Work on datac4, datac5, datac13, selective repeat ARQ
This commit is contained in:
commit
3cfaaec3da
54 changed files with 1979 additions and 1539 deletions
2
.github/workflows/build_multiplatform.yml
vendored
2
.github/workflows/build_multiplatform.yml
vendored
|
@ -112,6 +112,8 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
- uses: uraimo/run-on-arch-action@v2
|
- uses: uraimo/run-on-arch-action@v2
|
||||||
name: Build artifact
|
name: Build artifact
|
||||||
id: build
|
id: build
|
||||||
|
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -40,6 +40,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
|
|
2
.github/workflows/ctest.yml
vendored
2
.github/workflows/ctest.yml
vendored
|
@ -44,7 +44,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git clone https://github.com/drowe67/codec2.git
|
git clone https://github.com/drowe67/codec2.git
|
||||||
cd codec2 && git checkout master # This should be pinned to a release
|
cd codec2
|
||||||
mkdir -p build_linux && cd build_linux && cmake .. && make
|
mkdir -p build_linux && cd build_linux && cmake .. && make
|
||||||
|
|
||||||
- name: run ctests
|
- name: run ctests
|
||||||
|
|
|
@ -58,19 +58,19 @@ add_test(NAME tnc_irs_iss
|
||||||
# python3 test_chat_text.py")
|
# python3 test_chat_text.py")
|
||||||
# set_tests_properties(chat_text PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
# set_tests_properties(chat_text PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
||||||
|
|
||||||
add_test(NAME datac0_frames
|
add_test(NAME datac13_frames
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
export PYTHONPATH=../tnc;
|
export PYTHONPATH=../tnc;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 test_datac0.py")
|
python3 test_datac13.py")
|
||||||
set_tests_properties(datac0_frames PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
set_tests_properties(datac13_frames PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
||||||
|
|
||||||
add_test(NAME datac0_frames_negative
|
add_test(NAME datac13_frames_negative
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
export PYTHONPATH=../tnc;
|
export PYTHONPATH=../tnc;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 test_datac0_negative.py")
|
python3 test_datac13_negative.py")
|
||||||
set_tests_properties(datac0_frames_negative PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
set_tests_properties(datac13_frames_negative PROPERTIES PASS_REGULAR_EXPRESSION "errors: 0")
|
||||||
|
|
||||||
add_test(NAME helper_routines
|
add_test(NAME helper_routines
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
|
@ -87,7 +87,7 @@ add_test(NAME py_highsnr_stdio_P_P_multi
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 test_highsnr_stdio_P_P_multi.py")
|
python3 test_highsnr_stdio_P_P_multi.py")
|
||||||
set_tests_properties(py_highsnr_stdio_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: ${BURSTS}/${FRAMESPERBURST} DATAC1: ${BURSTS}/${FRAMESPERBURST} DATAC3: ${BURSTS}/${FRAMESPERBURST}")
|
set_tests_properties(py_highsnr_stdio_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC13: ${BURSTS}/${FRAMESPERBURST} DATAC1: ${BURSTS}/${FRAMESPERBURST} DATAC3: ${BURSTS}/${FRAMESPERBURST}")
|
||||||
|
|
||||||
add_test(NAME py_highsnr_stdio_P_P_datacx
|
add_test(NAME py_highsnr_stdio_P_P_datacx
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
|
@ -124,26 +124,26 @@ add_test(NAME highsnr_stdio_P_C_single
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 util_tx.py --mode datac0 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
python3 util_tx.py --mode datac13 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||||
sox -t .s16 -r 48000 -c 1 - -t .s16 -r 8000 -c 1 - |
|
sox -t .s16 -r 48000 -c 1 - -t .s16 -r 8000 -c 1 - |
|
||||||
freedv_data_raw_rx datac0 - - --framesperburst ${FRAMESPERBURST} | hexdump -C")
|
freedv_data_raw_rx datac13 - - --framesperburst ${FRAMESPERBURST} | hexdump -C")
|
||||||
set_tests_properties(highsnr_stdio_P_C_single PROPERTIES PASS_REGULAR_EXPRESSION "HELLO WORLD")
|
set_tests_properties(highsnr_stdio_P_C_single PROPERTIES PASS_REGULAR_EXPRESSION "HELLO WORLD")
|
||||||
|
|
||||||
add_test(NAME highsnr_stdio_C_P_single
|
add_test(NAME highsnr_stdio_C_P_single
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
freedv_data_raw_tx datac0 --testframes ${TESTFRAMES} --bursts ${BURSTS} --framesperburst ${FRAMESPERBURST} /dev/zero - |
|
freedv_data_raw_tx datac13 --testframes ${TESTFRAMES} --bursts ${BURSTS} --framesperburst ${FRAMESPERBURST} /dev/zero - |
|
||||||
sox -t .s16 -r 8000 -c 1 - -t .s16 -r 48000 -c 1 - |
|
sox -t .s16 -r 8000 -c 1 - -t .s16 -r 48000 -c 1 - |
|
||||||
python3 util_rx.py --mode datac0 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
python3 util_rx.py --mode datac13 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
||||||
set_tests_properties(highsnr_stdio_C_P_single PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
set_tests_properties(highsnr_stdio_C_P_single PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||||
|
|
||||||
add_test(NAME highsnr_stdio_P_P_single
|
add_test(NAME highsnr_stdio_P_P_single
|
||||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 util_tx.py --mode datac0 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
python3 util_tx.py --mode datac13 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||||
python3 util_rx.py --debug --mode datac0 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
python3 util_rx.py --debug --mode datac13 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
||||||
set_tests_properties(highsnr_stdio_P_P_single PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
set_tests_properties(highsnr_stdio_P_P_single PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||||
|
|
||||||
add_test(NAME highsnr_stdio_P_P_multi
|
add_test(NAME highsnr_stdio_P_P_multi
|
||||||
|
@ -151,8 +151,8 @@ add_test(NAME highsnr_stdio_P_P_multi
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
python3 util_multimode_tx.py --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
python3 util_multimode_tx.py --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||||
python3 util_multimode_rx.py --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} --timeout 20")
|
python3 util_multimode_rx.py --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} --timeout 60")
|
||||||
set_tests_properties(highsnr_stdio_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: ${BURSTS}/${FRAMESPERBURST} DATAC1: ${BURSTS}/${FRAMESPERBURST} DATAC3: ${BURSTS}/${FRAMESPERBURST}")
|
set_tests_properties(highsnr_stdio_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC13: ${BURSTS}/${FRAMESPERBURST} DATAC1: ${BURSTS}/${FRAMESPERBURST} DATAC3: ${BURSTS}/${FRAMESPERBURST}")
|
||||||
|
|
||||||
# These tests can't run on GitHub actions as we don't have a virtual sound card
|
# These tests can't run on GitHub actions as we don't have a virtual sound card
|
||||||
if(NOT DEFINED ENV{GITHUB_RUN_ID})
|
if(NOT DEFINED ENV{GITHUB_RUN_ID})
|
||||||
|
@ -179,7 +179,7 @@ add_test(NAME highsnr_virtual3_P_P_multi
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
./test_virtual_mm.sh")
|
./test_virtual_mm.sh")
|
||||||
set_tests_properties(highsnr_virtual3_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
set_tests_properties(highsnr_virtual3_P_P_multi PROPERTIES PASS_REGULAR_EXPRESSION "DATAC13: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
||||||
|
|
||||||
# let Python do audio I/O via pyaudio callback mode
|
# let Python do audio I/O via pyaudio callback mode
|
||||||
add_test(NAME highsnr_virtual4_P_P_single_callback
|
add_test(NAME highsnr_virtual4_P_P_single_callback
|
||||||
|
@ -203,7 +203,7 @@ add_test(NAME highsnr_virtual5_P_P_multi_callback
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
./test_virtual4a.sh")
|
./test_virtual4a.sh")
|
||||||
set_tests_properties(highsnr_virtual5_P_P_multi_callback PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
set_tests_properties(highsnr_virtual5_P_P_multi_callback PROPERTIES PASS_REGULAR_EXPRESSION "DATAC13: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
||||||
|
|
||||||
# let Python do audio I/O via pyaudio callback mode with code outside of callback
|
# let Python do audio I/O via pyaudio callback mode with code outside of callback
|
||||||
add_test(NAME highsnr_virtual5_P_P_multi_callback_outside
|
add_test(NAME highsnr_virtual5_P_P_multi_callback_outside
|
||||||
|
@ -211,7 +211,7 @@ add_test(NAME highsnr_virtual5_P_P_multi_callback_outside
|
||||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
cd ${CMAKE_CURRENT_SOURCE_DIR}/test;
|
||||||
./test_virtual4b.sh")
|
./test_virtual4b.sh")
|
||||||
set_tests_properties(highsnr_virtual5_P_P_multi_callback_outside PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
set_tests_properties(highsnr_virtual5_P_P_multi_callback_outside PROPERTIES PASS_REGULAR_EXPRESSION "DATAC13: 2/4 DATAC1: 2/4 DATAC3: 2/4")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -483,7 +483,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
||||||
command: "msg",
|
command: "msg",
|
||||||
dxcallsign: dxcallsign,
|
dxcallsign: dxcallsign,
|
||||||
mode: 255,
|
mode: 255,
|
||||||
frames: 1,
|
frames: 5,
|
||||||
data: data_with_attachment,
|
data: data_with_attachment,
|
||||||
checksum: file_checksum,
|
checksum: file_checksum,
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
|
@ -1443,7 +1443,7 @@ update_chat = function (obj) {
|
||||||
command: "msg",
|
command: "msg",
|
||||||
dxcallsign: doc.dxcallsign,
|
dxcallsign: doc.dxcallsign,
|
||||||
mode: 255,
|
mode: 255,
|
||||||
frames: 1,
|
frames: 5,
|
||||||
data: data_with_attachment,
|
data: data_with_attachment,
|
||||||
checksum: doc.checksum,
|
checksum: doc.checksum,
|
||||||
uuid: doc.uuid,
|
uuid: doc.uuid,
|
||||||
|
|
|
@ -1634,6 +1634,7 @@ ipcRenderer.on("action-update-reception-status", (event, arg) => {
|
||||||
var time_left = "<strong>" + time_left + " || Speed/min: ";
|
var time_left = "<strong>" + time_left + " || Speed/min: ";
|
||||||
|
|
||||||
// SET BYTES PER MINUTE
|
// SET BYTES PER MINUTE
|
||||||
|
|
||||||
if (typeof data.bytesperminute == "undefined") {
|
if (typeof data.bytesperminute == "undefined") {
|
||||||
var arq_bytes_per_minute = 0;
|
var arq_bytes_per_minute = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1648,7 +1649,7 @@ ipcRenderer.on("action-update-reception-status", (event, arg) => {
|
||||||
var arq_bytes_per_minute_compressed = Math.round(
|
var arq_bytes_per_minute_compressed = Math.round(
|
||||||
arq_bytes_per_minute * compress
|
arq_bytes_per_minute * compress
|
||||||
);
|
);
|
||||||
|
console.log(arq_bytes_per_minute);
|
||||||
time_left +=
|
time_left +=
|
||||||
formatBytes(arq_bytes_per_minute, 1) +
|
formatBytes(arq_bytes_per_minute, 1) +
|
||||||
" (comp: " +
|
" (comp: " +
|
||||||
|
@ -2210,11 +2211,14 @@ function updateHeardStations(arg) {
|
||||||
|
|
||||||
//https://stackoverflow.com/a/847196
|
//https://stackoverflow.com/a/847196
|
||||||
timestampRaw = arg.stations[i]["timestamp"];
|
timestampRaw = arg.stations[i]["timestamp"];
|
||||||
var date = new Date(timestampRaw * 1000);
|
|
||||||
var hours = date.getHours();
|
var datetime = new Date(timestampRaw * 1000).toLocaleString(
|
||||||
var minutes = "0" + date.getMinutes();
|
navigator.language
|
||||||
var seconds = "0" + date.getSeconds();
|
);
|
||||||
var datetime = hours + ":" + minutes.substr(-2) + ":" + seconds.substr(-2);
|
//var hours = date.getHours();
|
||||||
|
//var minutes = "0" + date.getMinutes();
|
||||||
|
//var seconds = "0" + date.getSeconds();
|
||||||
|
//var datetime = hours + ":" + minutes.substr(-2) + ":" + seconds.substr(-2);
|
||||||
|
|
||||||
var timestamp = document.createElement("td");
|
var timestamp = document.createElement("td");
|
||||||
var timestampText = document.createElement("span");
|
var timestampText = document.createElement("span");
|
||||||
|
|
|
@ -198,6 +198,7 @@ client.on("data", function (socketdata) {
|
||||||
dbfs_level: data["audio_dbfs"],
|
dbfs_level: data["audio_dbfs"],
|
||||||
fft: data["fft"],
|
fft: data["fft"],
|
||||||
channel_busy: data["channel_busy"],
|
channel_busy: data["channel_busy"],
|
||||||
|
channel_busy_slot: data["channel_busy_slot"],
|
||||||
scatter: data["scatter"],
|
scatter: data["scatter"],
|
||||||
info: data["info"],
|
info: data["info"],
|
||||||
rx_buffer_length: data["rx_buffer_length"],
|
rx_buffer_length: data["rx_buffer_length"],
|
||||||
|
|
|
@ -16,8 +16,8 @@ check_alsa_loopback
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
python3 util_callback_rx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2 --debug &
|
python3 util_callback_rx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
#sleep 1
|
#sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -204,7 +204,7 @@ for i in range(N_BURSTS):
|
||||||
|
|
||||||
# time.sleep(DELAY_BETWEEN_BURSTS)
|
# time.sleep(DELAY_BETWEEN_BURSTS)
|
||||||
|
|
||||||
# WAIT UNTIL WE RECEIVD AN ACK/DATAC0 FRAME
|
# WAIT UNTIL WE RECEIVD AN ACK/datac13 FRAME
|
||||||
while ACK_TIMEOUT >= time.time():
|
while ACK_TIMEOUT >= time.time():
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
Can be invoked from CMake, pytest, coverage or directly.
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
Uses util_datac0.py in separate process to perform the data transfer.
|
Uses util_datac13.py in separate process to perform the data transfer.
|
||||||
|
|
||||||
@author: N2KIQ
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
@ -28,9 +28,9 @@ import pytest
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import test.util_datac0 as util
|
import test.util_datac13 as util
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import util_datac0 as util
|
import util_datac13 as util
|
||||||
|
|
||||||
|
|
||||||
STATIONS = ["AA2BB", "ZZ9YY"]
|
STATIONS = ["AA2BB", "ZZ9YY"]
|
||||||
|
@ -48,11 +48,11 @@ def parameters() -> dict:
|
||||||
connect_data = {"type": "arq", "command": "connect", "dxcallsign": "ZZ9YY-0"}
|
connect_data = {"type": "arq", "command": "connect", "dxcallsign": "ZZ9YY-0"}
|
||||||
stop_data = {"type": "arq", "command": "stop_transmission", "dxcallsign": "ZZ9YY-0"}
|
stop_data = {"type": "arq", "command": "stop_transmission", "dxcallsign": "ZZ9YY-0"}
|
||||||
|
|
||||||
beacon_timeout = 6
|
beacon_timeout = 1
|
||||||
cq_timeout = 8
|
ping_timeout = 1
|
||||||
ping_timeout = 5
|
cq_timeout = 1
|
||||||
connect_timeout = 10
|
connect_timeout = 1
|
||||||
stop_timeout = 5
|
stop_timeout = 1
|
||||||
|
|
||||||
beacon_tx_check = '"beacon":"transmitting"'
|
beacon_tx_check = '"beacon":"transmitting"'
|
||||||
cq_tx_check = '"qrv":"received"'
|
cq_tx_check = '"qrv":"received"'
|
||||||
|
@ -192,13 +192,13 @@ def analyze_results(station1: list, station2: list, call_list: list):
|
||||||
pytest.param("beacon", marks=pytest.mark.flaky(reruns=2)),
|
pytest.param("beacon", marks=pytest.mark.flaky(reruns=2)),
|
||||||
pytest.param("ping", marks=pytest.mark.flaky(reruns=2)),
|
pytest.param("ping", marks=pytest.mark.flaky(reruns=2)),
|
||||||
pytest.param("cq", marks=pytest.mark.flaky(reruns=20)),
|
pytest.param("cq", marks=pytest.mark.flaky(reruns=20)),
|
||||||
# pytest.param("cq", marks=pytest.mark.xfail(reason="Too unstable for CI")),
|
#pytest.param("cq", marks=pytest.mark.xfail(reason="Too unstable for CI")),
|
||||||
pytest.param("stop", marks=pytest.mark.flaky(reruns=0)),
|
pytest.param("stop", marks=pytest.mark.flaky(reruns=2)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_datac0(frame_type: str, tmp_path):
|
def test_datac13(frame_type: str, tmp_path):
|
||||||
log_handler.setup_logging(filename=tmp_path / "test_datac0", level="DEBUG")
|
log_handler.setup_logging(filename=tmp_path / "test_datac13", level="DEBUG")
|
||||||
log = structlog.get_logger("test_datac0")
|
log = structlog.get_logger("test_datac13")
|
||||||
|
|
||||||
s1_data = []
|
s1_data = []
|
||||||
s2_data = []
|
s2_data = []
|
||||||
|
@ -227,7 +227,7 @@ def test_datac0(frame_type: str, tmp_path):
|
||||||
from_s2, s2_send = multiprocessing.Pipe()
|
from_s2, s2_send = multiprocessing.Pipe()
|
||||||
proc = [
|
proc = [
|
||||||
multiprocessing.Process(
|
multiprocessing.Process(
|
||||||
target=util.t_datac0_1,
|
target=util.t_datac13_1,
|
||||||
args=(
|
args=(
|
||||||
s1_send,
|
s1_send,
|
||||||
STATIONS[0],
|
STATIONS[0],
|
||||||
|
@ -238,7 +238,7 @@ def test_datac0(frame_type: str, tmp_path):
|
||||||
daemon=True,
|
daemon=True,
|
||||||
),
|
),
|
||||||
multiprocessing.Process(
|
multiprocessing.Process(
|
||||||
target=util.t_datac0_2,
|
target=util.t_datac13_2,
|
||||||
args=(
|
args=(
|
||||||
s2_send,
|
s2_send,
|
||||||
STATIONS[1],
|
STATIONS[1],
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Negative tests for datac0 frames.
|
Negative tests for datac13 frames.
|
||||||
|
|
||||||
@author: kronenpj
|
@author: kronenpj
|
||||||
"""
|
"""
|
||||||
|
@ -20,9 +20,9 @@ import pytest
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import test.util_datac0_negative as util
|
import test.util_datac13_negative as util
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import util_datac0_negative as util
|
import util_datac13_negative as util
|
||||||
|
|
||||||
|
|
||||||
STATIONS = ["AA2BB", "ZZ9YY"]
|
STATIONS = ["AA2BB", "ZZ9YY"]
|
||||||
|
@ -162,10 +162,13 @@ def analyze_results(station1: list, station2: list, call_list: list):
|
||||||
|
|
||||||
|
|
||||||
# @pytest.mark.parametrize("frame_type", ["beacon", "connect", "ping"])
|
# @pytest.mark.parametrize("frame_type", ["beacon", "connect", "ping"])
|
||||||
@pytest.mark.parametrize("frame_type", ["ping", "stop"])
|
@pytest.mark.parametrize("frame_type", [
|
||||||
def test_datac0_negative(frame_type: str, tmp_path):
|
"ping",
|
||||||
log_handler.setup_logging(filename=tmp_path / "test_datac0", level="DEBUG")
|
pytest.param("stop", marks=pytest.mark.flaky(reruns=10))
|
||||||
log = structlog.get_logger("test_datac0")
|
])
|
||||||
|
def test_datac13_negative(frame_type: str, tmp_path):
|
||||||
|
log_handler.setup_logging(filename=tmp_path / "test_datac13", level="DEBUG")
|
||||||
|
log = structlog.get_logger("test_datac13")
|
||||||
|
|
||||||
s1_data = []
|
s1_data = []
|
||||||
s2_data = []
|
s2_data = []
|
||||||
|
@ -194,7 +197,7 @@ def test_datac0_negative(frame_type: str, tmp_path):
|
||||||
from_s2, s2_send = multiprocessing.Pipe()
|
from_s2, s2_send = multiprocessing.Pipe()
|
||||||
proc = [
|
proc = [
|
||||||
multiprocessing.Process(
|
multiprocessing.Process(
|
||||||
target=util.t_datac0_1,
|
target=util.t_datac13_1,
|
||||||
args=(
|
args=(
|
||||||
s1_send,
|
s1_send,
|
||||||
STATIONS[0],
|
STATIONS[0],
|
||||||
|
@ -205,7 +208,7 @@ def test_datac0_negative(frame_type: str, tmp_path):
|
||||||
daemon=True,
|
daemon=True,
|
||||||
),
|
),
|
||||||
multiprocessing.Process(
|
multiprocessing.Process(
|
||||||
target=util.t_datac0_2,
|
target=util.t_datac13_2,
|
||||||
args=(
|
args=(
|
||||||
s2_send,
|
s2_send,
|
||||||
STATIONS[1],
|
STATIONS[1],
|
|
@ -14,7 +14,7 @@ import sys
|
||||||
|
|
||||||
import helpers
|
import helpers
|
||||||
import pytest
|
import pytest
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("callsign", ["AA1AA", "DE2DE", "E4AWQ-4"])
|
@pytest.mark.parametrize("callsign", ["AA1AA", "DE2DE", "E4AWQ-4"])
|
||||||
|
@ -22,7 +22,7 @@ def test_check_callsign(callsign: str):
|
||||||
"""
|
"""
|
||||||
Execute test to demonstrate how to create and verify callsign checksums.
|
Execute test to demonstrate how to create and verify callsign checksums.
|
||||||
"""
|
"""
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||||
|
|
||||||
t_callsign_bytes = helpers.callsign_to_bytes(callsign)
|
t_callsign_bytes = helpers.callsign_to_bytes(callsign)
|
||||||
t_callsign = helpers.bytes_to_callsign(t_callsign_bytes)
|
t_callsign = helpers.bytes_to_callsign(t_callsign_bytes)
|
||||||
|
@ -41,7 +41,7 @@ def test_callsign_to_bytes(callsign: str):
|
||||||
"""
|
"""
|
||||||
Execute test to demonsrate symmetry when converting callsigns to and from byte arrays.
|
Execute test to demonsrate symmetry when converting callsigns to and from byte arrays.
|
||||||
"""
|
"""
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||||
|
|
||||||
t_callsign_crc = helpers.get_crc_24(bytes(callsign, "UTF-8"))
|
t_callsign_crc = helpers.get_crc_24(bytes(callsign, "UTF-8"))
|
||||||
t_callsign_bytes = helpers.callsign_to_bytes(callsign)
|
t_callsign_bytes = helpers.callsign_to_bytes(callsign)
|
||||||
|
|
|
@ -49,7 +49,7 @@ def t_HighSNR_C_P_DATACx(
|
||||||
bursts: int, frames_per_burst: int, testframes: int, mode: str
|
bursts: int, frames_per_burst: int, testframes: int, mode: str
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Test a high signal-to-noise ratio path with DATAC0.
|
Test a high signal-to-noise ratio path with datac13.
|
||||||
|
|
||||||
:param bursts: Number of bursts
|
:param bursts: Number of bursts
|
||||||
:type bursts: str
|
:type bursts: str
|
||||||
|
@ -152,7 +152,7 @@ def t_HighSNR_C_P_DATACx(
|
||||||
@pytest.mark.parametrize("bursts", [BURSTS])
|
@pytest.mark.parametrize("bursts", [BURSTS])
|
||||||
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
||||||
@pytest.mark.parametrize("testframes", [TESTFRAMES])
|
@pytest.mark.parametrize("testframes", [TESTFRAMES])
|
||||||
@pytest.mark.parametrize("mode", ["datac0", "datac1", "datac3"])
|
@pytest.mark.parametrize("mode", ["datac13", "datac1", "datac3"])
|
||||||
def test_HighSNR_C_P_DATACx(
|
def test_HighSNR_C_P_DATACx(
|
||||||
bursts: int, frames_per_burst: int, testframes: int, mode: str
|
bursts: int, frames_per_burst: int, testframes: int, mode: str
|
||||||
):
|
):
|
||||||
|
|
|
@ -47,7 +47,7 @@ if os.path.exists("test"):
|
||||||
|
|
||||||
def t_HighSNR_P_C_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
def t_HighSNR_P_C_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
||||||
"""
|
"""
|
||||||
Test a high signal-to-noise ratio path with DATAC0.
|
Test a high signal-to-noise ratio path with datac13.
|
||||||
|
|
||||||
:param bursts: Number of bursts
|
:param bursts: Number of bursts
|
||||||
:type bursts: str
|
:type bursts: str
|
||||||
|
@ -154,7 +154,7 @@ def t_HighSNR_P_C_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
||||||
# @pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST, 2, 3])
|
# @pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST, 2, 3])
|
||||||
@pytest.mark.parametrize("bursts", [BURSTS])
|
@pytest.mark.parametrize("bursts", [BURSTS])
|
||||||
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
||||||
@pytest.mark.parametrize("mode", ["datac0", "datac1", "datac3"])
|
@pytest.mark.parametrize("mode", ["datac13", "datac1", "datac3"])
|
||||||
def test_HighSNR_P_C_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
def test_HighSNR_P_C_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
||||||
proc = multiprocessing.Process(
|
proc = multiprocessing.Process(
|
||||||
target=t_HighSNR_P_C_DATACx,
|
target=t_HighSNR_P_C_DATACx,
|
||||||
|
|
|
@ -115,7 +115,7 @@ def t_HighSNR_P_P_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
||||||
# @pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST, 2, 3])
|
# @pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST, 2, 3])
|
||||||
@pytest.mark.parametrize("bursts", [BURSTS])
|
@pytest.mark.parametrize("bursts", [BURSTS])
|
||||||
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
@pytest.mark.parametrize("frames_per_burst", [FRAMESPERBURST])
|
||||||
@pytest.mark.parametrize("mode", ["datac0", "datac1", "datac3"])
|
@pytest.mark.parametrize("mode", ["datac13", "datac1", "datac3"])
|
||||||
def test_HighSNR_P_P_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
def test_HighSNR_P_P_DATACx(bursts: int, frames_per_burst: int, mode: str):
|
||||||
proc = multiprocessing.Process(
|
proc = multiprocessing.Process(
|
||||||
target=t_HighSNR_P_P_DATACx,
|
target=t_HighSNR_P_P_DATACx,
|
||||||
|
|
|
@ -46,7 +46,7 @@ if os.path.exists("test"):
|
||||||
|
|
||||||
def t_HighSNR_P_P_Multi(bursts: int, frames_per_burst: int):
|
def t_HighSNR_P_P_Multi(bursts: int, frames_per_burst: int):
|
||||||
"""
|
"""
|
||||||
Test a high signal-to-noise ratio path with DATAC0, DATAC1 and DATAC3.
|
Test a high signal-to-noise ratio path with datac13, DATAC1 and DATAC3.
|
||||||
|
|
||||||
:param bursts: Number of bursts
|
:param bursts: Number of bursts
|
||||||
:type bursts: int
|
:type bursts: int
|
||||||
|
@ -101,7 +101,7 @@ def t_HighSNR_P_P_Multi(bursts: int, frames_per_burst: int):
|
||||||
if "DATAC" in str(line, "UTF-8")
|
if "DATAC" in str(line, "UTF-8")
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert f"DATAC0: {bursts}/{frames_per_burst * bursts}" in lastline
|
assert f"DATAC13: {bursts}/{frames_per_burst * bursts}" in lastline
|
||||||
assert f"DATAC1: {bursts}/{frames_per_burst * bursts}" in lastline
|
assert f"DATAC1: {bursts}/{frames_per_burst * bursts}" in lastline
|
||||||
assert f"DATAC3: {bursts}/{frames_per_burst * bursts}" in lastline
|
assert f"DATAC3: {bursts}/{frames_per_burst * bursts}" in lastline
|
||||||
print(lastline)
|
print(lastline)
|
||||||
|
|
|
@ -9,7 +9,7 @@ queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
Can be invoked from CMake, pytest, coverage or directly.
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
Uses util_datac0.py in separate process to perform the data transfer.
|
Uses util_datac13.py in separate process to perform the data transfer.
|
||||||
|
|
||||||
@author: N2KIQ
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
@ -26,7 +26,7 @@ sys.path.insert(0, "..")
|
||||||
sys.path.insert(0, "../tnc")
|
sys.path.insert(0, "../tnc")
|
||||||
import data_handler
|
import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
|
|
||||||
|
|
||||||
def print_frame(data: bytearray):
|
def print_frame(data: bytearray):
|
||||||
|
@ -148,18 +148,18 @@ def t_foreign_disconnect(mycall: str, dxcall: str):
|
||||||
:rtype: bytearray
|
:rtype: bytearray
|
||||||
"""
|
"""
|
||||||
# Set the SSIDs we'll use for this test.
|
# Set the SSIDs we'll use for this test.
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4]
|
Station.ssid_list = [0, 1, 2, 3, 4]
|
||||||
|
|
||||||
# Setup the static parameters for the connection.
|
# Setup the static parameters for the connection.
|
||||||
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(mycallsign)
|
Station.mycallsign_crc = helpers.get_crc_24(mycallsign)
|
||||||
|
|
||||||
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(dxcallsign)
|
Station.dxcallsign_crc = helpers.get_crc_24(dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc = data_handler.DATA()
|
||||||
|
@ -173,12 +173,12 @@ def t_foreign_disconnect(mycall: str, dxcall: str):
|
||||||
print_frame(create_frame)
|
print_frame(create_frame)
|
||||||
tnc.received_session_opener(create_frame)
|
tnc.received_session_opener(create_frame)
|
||||||
|
|
||||||
assert helpers.callsign_to_bytes(static.MYCALLSIGN) == mycallsign_bytes
|
assert helpers.callsign_to_bytes(Station.mycallsign) == mycallsign_bytes
|
||||||
assert helpers.callsign_to_bytes(static.DXCALLSIGN) == dxcallsign_bytes
|
assert helpers.callsign_to_bytes(Station.dxcallsign) == dxcallsign_bytes
|
||||||
|
|
||||||
assert static.ARQ_SESSION is True
|
assert ARQ.arq_session is True
|
||||||
assert static.TNC_STATE == "BUSY"
|
assert TNC.tnc_state == "BUSY"
|
||||||
assert static.ARQ_SESSION_STATE == "connecting"
|
assert ARQ.arq_session_state == "connecting"
|
||||||
|
|
||||||
# Set up a frame from a non-associated station.
|
# Set up a frame from a non-associated station.
|
||||||
# foreigncall_bytes = helpers.callsign_to_bytes("ZZ0ZZ-0")
|
# foreigncall_bytes = helpers.callsign_to_bytes("ZZ0ZZ-0")
|
||||||
|
@ -193,8 +193,8 @@ def t_foreign_disconnect(mycall: str, dxcall: str):
|
||||||
print_frame(close_frame)
|
print_frame(close_frame)
|
||||||
|
|
||||||
# assert (
|
# assert (
|
||||||
# helpers.check_callsign(static.DXCALLSIGN, bytes(close_frame[4:7]))[0] is False
|
# helpers.check_callsign(Station.dxcallsign, bytes(close_frame[4:7]))[0] is False
|
||||||
# ), f"{helpers.get_crc_24(static.DXCALLSIGN)} == {bytes(close_frame[4:7])} but should be not equal."
|
# ), f"{helpers.get_crc_24(Station.dxcallsign)} == {bytes(close_frame[4:7])} but should be not equal."
|
||||||
|
|
||||||
# assert (
|
# assert (
|
||||||
# helpers.check_callsign(foreigncall, bytes(close_frame[4:7]))[0] is True
|
# helpers.check_callsign(foreigncall, bytes(close_frame[4:7]))[0] is True
|
||||||
|
@ -203,16 +203,16 @@ def t_foreign_disconnect(mycall: str, dxcall: str):
|
||||||
# Send the non-associated session close frame to the TNC
|
# Send the non-associated session close frame to the TNC
|
||||||
tnc.received_session_close(close_frame)
|
tnc.received_session_close(close_frame)
|
||||||
|
|
||||||
assert helpers.callsign_to_bytes(static.MYCALLSIGN) == helpers.callsign_to_bytes(
|
assert helpers.callsign_to_bytes(Station.mycallsign) == helpers.callsign_to_bytes(
|
||||||
mycall
|
mycall
|
||||||
), f"{static.MYCALLSIGN} != {mycall} but should equal."
|
), f"{Station.mycallsign} != {mycall} but should equal."
|
||||||
assert helpers.callsign_to_bytes(static.DXCALLSIGN) == helpers.callsign_to_bytes(
|
assert helpers.callsign_to_bytes(Station.dxcallsign) == helpers.callsign_to_bytes(
|
||||||
dxcall
|
dxcall
|
||||||
), f"{static.DXCALLSIGN} != {dxcall} but should equal."
|
), f"{Station.dxcallsign} != {dxcall} but should equal."
|
||||||
|
|
||||||
assert static.ARQ_SESSION is True
|
assert ARQ.arq_session is True
|
||||||
assert static.TNC_STATE == "BUSY"
|
assert TNC.tnc_state == "BUSY"
|
||||||
assert static.ARQ_SESSION_STATE == "connecting"
|
assert ARQ.arq_session_state == "connecting"
|
||||||
|
|
||||||
|
|
||||||
def t_valid_disconnect(mycall: str, dxcall: str):
|
def t_valid_disconnect(mycall: str, dxcall: str):
|
||||||
|
@ -228,18 +228,18 @@ def t_valid_disconnect(mycall: str, dxcall: str):
|
||||||
:rtype: bytearray
|
:rtype: bytearray
|
||||||
"""
|
"""
|
||||||
# Set the SSIDs we'll use for this test.
|
# Set the SSIDs we'll use for this test.
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4]
|
Station.ssid_list = [0, 1, 2, 3, 4]
|
||||||
|
|
||||||
# Setup the static parameters for the connection.
|
# Setup the static parameters for the connection.
|
||||||
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(mycallsign)
|
Station.mycallsign_crc = helpers.get_crc_24(mycallsign)
|
||||||
|
|
||||||
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(dxcallsign)
|
Station.dxcallsign_crc = helpers.get_crc_24(dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc = data_handler.DATA()
|
||||||
|
@ -253,9 +253,9 @@ def t_valid_disconnect(mycall: str, dxcall: str):
|
||||||
print_frame(create_frame)
|
print_frame(create_frame)
|
||||||
tnc.received_session_opener(create_frame)
|
tnc.received_session_opener(create_frame)
|
||||||
|
|
||||||
assert static.ARQ_SESSION is True
|
assert ARQ.arq_session is True
|
||||||
assert static.TNC_STATE == "BUSY"
|
assert TNC.tnc_state == "BUSY"
|
||||||
assert static.ARQ_SESSION_STATE == "connecting"
|
assert ARQ.arq_session_state == "connecting"
|
||||||
|
|
||||||
# Create packet to be 'received' by this station.
|
# Create packet to be 'received' by this station.
|
||||||
# close_frame = t_create_session_close_old(mycall=dxcall, dxcall=mycall)
|
# close_frame = t_create_session_close_old(mycall=dxcall, dxcall=mycall)
|
||||||
|
@ -267,12 +267,12 @@ def t_valid_disconnect(mycall: str, dxcall: str):
|
||||||
print_frame(close_frame)
|
print_frame(close_frame)
|
||||||
tnc.received_session_close(close_frame)
|
tnc.received_session_close(close_frame)
|
||||||
|
|
||||||
assert helpers.callsign_to_bytes(static.MYCALLSIGN) == mycallsign_bytes
|
assert helpers.callsign_to_bytes(Station.mycallsign) == mycallsign_bytes
|
||||||
assert helpers.callsign_to_bytes(static.DXCALLSIGN) == dxcallsign_bytes
|
assert helpers.callsign_to_bytes(Station.dxcallsign) == dxcallsign_bytes
|
||||||
|
|
||||||
assert static.ARQ_SESSION is False
|
assert ARQ.arq_session is False
|
||||||
assert static.TNC_STATE == "IDLE"
|
assert TNC.tnc_state == "IDLE"
|
||||||
assert static.ARQ_SESSION_STATE == "disconnected"
|
assert ARQ.arq_session_state == "disconnected"
|
||||||
|
|
||||||
|
|
||||||
# These tests are pushed into separate processes as a workaround. These tests
|
# These tests are pushed into separate processes as a workaround. These tests
|
||||||
|
|
|
@ -15,13 +15,13 @@ function check_alsa_loopback {
|
||||||
check_alsa_loopback
|
check_alsa_loopback
|
||||||
|
|
||||||
RX_LOG=$(mktemp)
|
RX_LOG=$(mktemp)
|
||||||
MAX_RUN_TIME=2600
|
MAX_RUN_TIME=2700
|
||||||
|
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
arecord --device="plughw:CARD=CHAT2,DEV=0" -r 48000 -f S16_LE -d $MAX_RUN_TIME | python3 util_rx.py --mode datac0 --frames 2 --bursts 5 --debug &
|
arecord --device="plughw:CARD=CHAT2,DEV=0" -r 48000 -f S16_LE -d $MAX_RUN_TIME | python3 util_rx.py --mode datac13 --frames 2 --bursts 5 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 | aplay --device="plughw:CARD=CHAT2,DEV=1" -r 48000 -f S16_LE
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 5 --delay 500 | aplay --device="plughw:CARD=CHAT2,DEV=1" -r 48000 -f S16_LE
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -8,9 +8,9 @@ MAX_RUN_TIME=2600
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \
|
arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \
|
||||||
python3 util_rx.py --mode datac0 --frames 2 --bursts 5 --debug &
|
python3 util_rx.py --mode datac13 --frames 2 --bursts 5 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 | \
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 5 --delay 500 | \
|
||||||
aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE
|
aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -8,8 +8,8 @@ MAX_RUN_TIME=2600
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \
|
arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \
|
||||||
python3 util_rx.py --mode datac0 --frames 2 --bursts 5 --debug --timeout 20 &
|
python3 util_rx.py --mode datac13 --frames 2 --bursts 5 --debug --timeout 20 &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 5 --delay 2000 --audiodev -2
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 5 --delay 2000 --audiodev -2
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -7,9 +7,9 @@ MAX_RUN_TIME=2600
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
python3 util_rx.py --mode datac0 --frames 2 --bursts 5 --debug --audiodev -2 &
|
python3 util_rx.py --mode datac13 --frames 2 --bursts 5 --debug --audiodev -2 &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 5 | \
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 5 | \
|
||||||
aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE
|
aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -16,8 +16,8 @@ check_alsa_loopback
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
python3 util_callback_rx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2 --debug &
|
python3 util_callback_rx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -16,8 +16,8 @@ check_alsa_loopback
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
python3 util_callback_rx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2 --debug &
|
python3 util_callback_rx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
#sleep 1
|
#sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -16,8 +16,8 @@ check_alsa_loopback
|
||||||
# make sure all child processes are killed when we exit
|
# make sure all child processes are killed when we exit
|
||||||
trap 'jobs -p | xargs -r kill' EXIT
|
trap 'jobs -p | xargs -r kill' EXIT
|
||||||
|
|
||||||
python3 util_callback_rx_outside.py --mode datac0 --frames 2 --bursts 3 --audiodev -2 --debug &
|
python3 util_callback_rx_outside.py --mode datac13 --frames 2 --bursts 3 --audiodev -2 --debug &
|
||||||
rx_pid=$!
|
rx_pid=$!
|
||||||
#sleep 1
|
#sleep 1
|
||||||
python3 util_tx.py --mode datac0 --frames 2 --bursts 3 --audiodev -2
|
python3 util_tx.py --mode datac13 --frames 2 --bursts 3 --audiodev -2
|
||||||
wait ${rx_pid}
|
wait ${rx_pid}
|
||||||
|
|
|
@ -112,20 +112,20 @@ class Test:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# open codec2 instance
|
# open codec2 instance
|
||||||
self.datac0_freedv = ctypes.cast(
|
self.datac13_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac13.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac0_bytes_per_frame = int(
|
self.datac13_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac13_freedv) / 8
|
||||||
)
|
)
|
||||||
self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame)
|
self.datac13_bytes_out = ctypes.create_string_buffer(self.datac13_bytes_per_frame)
|
||||||
codec2.api.freedv_set_frames_per_burst(
|
codec2.api.freedv_set_frames_per_burst(
|
||||||
self.datac0_freedv, self.N_FRAMES_PER_BURST
|
self.datac13_freedv, self.N_FRAMES_PER_BURST
|
||||||
)
|
)
|
||||||
self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac13_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
self.datac1_freedv = ctypes.cast(
|
self.datac1_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac1.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac1_bytes_per_frame = int(
|
self.datac1_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8
|
||||||
|
@ -137,7 +137,7 @@ class Test:
|
||||||
self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
self.datac3_freedv = ctypes.cast(
|
self.datac3_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac3.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac3_bytes_per_frame = int(
|
self.datac3_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8
|
||||||
|
@ -149,9 +149,9 @@ class Test:
|
||||||
self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
# SET COUNTERS
|
# SET COUNTERS
|
||||||
self.rx_total_frames_datac0 = 0
|
self.rx_total_frames_datac13 = 0
|
||||||
self.rx_frames_datac0 = 0
|
self.rx_frames_datac13 = 0
|
||||||
self.rx_bursts_datac0 = 0
|
self.rx_bursts_datac13 = 0
|
||||||
|
|
||||||
self.rx_total_frames_datac1 = 0
|
self.rx_total_frames_datac1 = 0
|
||||||
self.rx_frames_datac1 = 0
|
self.rx_frames_datac1 = 0
|
||||||
|
@ -173,7 +173,7 @@ class Test:
|
||||||
self.frx = open("rx48_callback_multimode.raw", mode="wb")
|
self.frx = open("rx48_callback_multimode.raw", mode="wb")
|
||||||
|
|
||||||
# initial nin values
|
# initial nin values
|
||||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
self.datac13_nin = codec2.api.freedv_nin(self.datac13_freedv)
|
||||||
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||||
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||||
|
|
||||||
|
@ -187,26 +187,26 @@ class Test:
|
||||||
x.tofile(self.frx)
|
x.tofile(self.frx)
|
||||||
x = self.resampler.resample48_to_8(x)
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
|
||||||
self.datac0_buffer.push(x)
|
self.datac13_buffer.push(x)
|
||||||
self.datac1_buffer.push(x)
|
self.datac1_buffer.push(x)
|
||||||
self.datac3_buffer.push(x)
|
self.datac3_buffer.push(x)
|
||||||
|
|
||||||
while self.datac0_buffer.nbuffer >= self.datac0_nin:
|
while self.datac13_buffer.nbuffer >= self.datac13_nin:
|
||||||
# demodulate audio
|
# demodulate audio
|
||||||
nbytes = codec2.api.freedv_rawdatarx(
|
nbytes = codec2.api.freedv_rawdatarx(
|
||||||
self.datac0_freedv,
|
self.datac13_freedv,
|
||||||
self.datac0_bytes_out,
|
self.datac13_bytes_out,
|
||||||
self.datac0_buffer.buffer.ctypes,
|
self.datac13_buffer.buffer.ctypes,
|
||||||
)
|
)
|
||||||
self.datac0_buffer.pop(self.datac0_nin)
|
self.datac13_buffer.pop(self.datac13_nin)
|
||||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
self.datac13_nin = codec2.api.freedv_nin(self.datac13_freedv)
|
||||||
if nbytes == self.datac0_bytes_per_frame:
|
if nbytes == self.datac13_bytes_per_frame:
|
||||||
self.rx_total_frames_datac0 = self.rx_total_frames_datac0 + 1
|
self.rx_total_frames_datac13 = self.rx_total_frames_datac13 + 1
|
||||||
self.rx_frames_datac0 = self.rx_frames_datac0 + 1
|
self.rx_frames_datac13 = self.rx_frames_datac13 + 1
|
||||||
|
|
||||||
if self.rx_frames_datac0 == self.N_FRAMES_PER_BURST:
|
if self.rx_frames_datac13 == self.N_FRAMES_PER_BURST:
|
||||||
self.rx_frames_datac0 = 0
|
self.rx_frames_datac13 = 0
|
||||||
self.rx_bursts_datac0 = self.rx_bursts_datac0 + 1
|
self.rx_bursts_datac13 = self.rx_bursts_datac13 + 1
|
||||||
|
|
||||||
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
||||||
# demodulate audio
|
# demodulate audio
|
||||||
|
@ -243,7 +243,7 @@ class Test:
|
||||||
self.rx_bursts_datac3 = self.rx_bursts_datac3 + 1
|
self.rx_bursts_datac3 = self.rx_bursts_datac3 + 1
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.rx_bursts_datac0 and self.rx_bursts_datac1 and self.rx_bursts_datac3
|
self.rx_bursts_datac13 and self.rx_bursts_datac1 and self.rx_bursts_datac3
|
||||||
) == self.N_BURSTS:
|
) == self.N_BURSTS:
|
||||||
self.receive = False
|
self.receive = False
|
||||||
|
|
||||||
|
@ -253,11 +253,11 @@ class Test:
|
||||||
while self.receive:
|
while self.receive:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
if self.DEBUGGING_MODE:
|
if self.DEBUGGING_MODE:
|
||||||
self.datac0_rxstatus = codec2.api.freedv_get_rx_status(
|
self.datac13_rxstatus = codec2.api.freedv_get_rx_status(
|
||||||
self.datac0_freedv
|
self.datac13_freedv
|
||||||
)
|
)
|
||||||
self.datac0_rxstatus = codec2.api.rx_sync_flags_to_text[
|
self.datac13_rxstatus = codec2.api.rx_sync_flags_to_text[
|
||||||
self.datac0_rxstatus
|
self.datac13_rxstatus
|
||||||
]
|
]
|
||||||
|
|
||||||
self.datac1_rxstatus = codec2.api.freedv_get_rx_status(
|
self.datac1_rxstatus = codec2.api.freedv_get_rx_status(
|
||||||
|
@ -277,8 +277,8 @@ class Test:
|
||||||
print(
|
print(
|
||||||
"NIN0: %5d RX_STATUS0: %4s NIN1: %5d RX_STATUS1: %4s NIN3: %5d RX_STATUS3: %4s"
|
"NIN0: %5d RX_STATUS0: %4s NIN1: %5d RX_STATUS1: %4s NIN3: %5d RX_STATUS3: %4s"
|
||||||
% (
|
% (
|
||||||
self.datac0_nin,
|
self.datac13_nin,
|
||||||
self.datac0_rxstatus,
|
self.datac13_rxstatus,
|
||||||
self.datac1_nin,
|
self.datac1_nin,
|
||||||
self.datac1_rxstatus,
|
self.datac1_rxstatus,
|
||||||
self.datac3_nin,
|
self.datac3_nin,
|
||||||
|
@ -309,7 +309,7 @@ class Test:
|
||||||
)
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"DATAC0: {self.rx_bursts_datac0}/{self.rx_total_frames_datac0} DATAC1: {self.rx_bursts_datac1}/{self.rx_total_frames_datac1} DATAC3: {self.rx_bursts_datac3}/{self.rx_total_frames_datac3}",
|
f"datac13: {self.rx_bursts_datac13}/{self.rx_total_frames_datac13} DATAC1: {self.rx_bursts_datac1}/{self.rx_total_frames_datac1} DATAC3: {self.rx_bursts_datac3}/{self.rx_total_frames_datac3}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
self.frx.close()
|
self.frx.close()
|
||||||
|
|
|
@ -110,20 +110,20 @@ class Test:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# open codec2 instance
|
# open codec2 instance
|
||||||
self.datac0_freedv = ctypes.cast(
|
self.datac13_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac13.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac0_bytes_per_frame = int(
|
self.datac13_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac0_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac13_freedv) / 8
|
||||||
)
|
)
|
||||||
self.datac0_bytes_out = ctypes.create_string_buffer(self.datac0_bytes_per_frame)
|
self.datac13_bytes_out = ctypes.create_string_buffer(self.datac13_bytes_per_frame)
|
||||||
codec2.api.freedv_set_frames_per_burst(
|
codec2.api.freedv_set_frames_per_burst(
|
||||||
self.datac0_freedv, self.N_FRAMES_PER_BURST
|
self.datac13_freedv, self.N_FRAMES_PER_BURST
|
||||||
)
|
)
|
||||||
self.datac0_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac13_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
self.datac1_freedv = ctypes.cast(
|
self.datac1_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC1), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac1.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac1_bytes_per_frame = int(
|
self.datac1_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac1_freedv) / 8
|
||||||
|
@ -135,7 +135,7 @@ class Test:
|
||||||
self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac1_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
self.datac3_freedv = ctypes.cast(
|
self.datac3_freedv = ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC3), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac3.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
self.datac3_bytes_per_frame = int(
|
self.datac3_bytes_per_frame = int(
|
||||||
codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8
|
codec2.api.freedv_get_bits_per_modem_frame(self.datac3_freedv) / 8
|
||||||
|
@ -147,9 +147,9 @@ class Test:
|
||||||
self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
self.datac3_buffer = codec2.audio_buffer(2 * self.AUDIO_FRAMES_PER_BUFFER)
|
||||||
|
|
||||||
# SET COUNTERS
|
# SET COUNTERS
|
||||||
self.rx_total_frames_datac0 = 0
|
self.rx_total_frames_datac13 = 0
|
||||||
self.rx_frames_datac0 = 0
|
self.rx_frames_datac13 = 0
|
||||||
self.rx_bursts_datac0 = 0
|
self.rx_bursts_datac13 = 0
|
||||||
|
|
||||||
self.rx_total_frames_datac1 = 0
|
self.rx_total_frames_datac1 = 0
|
||||||
self.rx_frames_datac1 = 0
|
self.rx_frames_datac1 = 0
|
||||||
|
@ -171,7 +171,7 @@ class Test:
|
||||||
self.frx = open("rx48_callback_multimode.raw", mode="wb")
|
self.frx = open("rx48_callback_multimode.raw", mode="wb")
|
||||||
|
|
||||||
# initial nin values
|
# initial nin values
|
||||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
self.datac13_nin = codec2.api.freedv_nin(self.datac13_freedv)
|
||||||
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
self.datac1_nin = codec2.api.freedv_nin(self.datac1_freedv)
|
||||||
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
self.datac3_nin = codec2.api.freedv_nin(self.datac3_freedv)
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ class Test:
|
||||||
x.tofile(self.frx)
|
x.tofile(self.frx)
|
||||||
x = self.resampler.resample48_to_8(x)
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
|
||||||
self.datac0_buffer.push(x)
|
self.datac13_buffer.push(x)
|
||||||
self.datac1_buffer.push(x)
|
self.datac1_buffer.push(x)
|
||||||
self.datac3_buffer.push(x)
|
self.datac3_buffer.push(x)
|
||||||
|
|
||||||
|
@ -189,9 +189,9 @@ class Test:
|
||||||
|
|
||||||
def print_stats(self):
|
def print_stats(self):
|
||||||
if self.DEBUGGING_MODE:
|
if self.DEBUGGING_MODE:
|
||||||
self.datac0_rxstatus = codec2.api.freedv_get_rx_status(self.datac0_freedv)
|
self.datac13_rxstatus = codec2.api.freedv_get_rx_status(self.datac13_freedv)
|
||||||
self.datac0_rxstatus = codec2.api.rx_sync_flags_to_text[
|
self.datac13_rxstatus = codec2.api.rx_sync_flags_to_text[
|
||||||
self.datac0_rxstatus
|
self.datac13_rxstatus
|
||||||
]
|
]
|
||||||
|
|
||||||
self.datac1_rxstatus = codec2.api.freedv_get_rx_status(self.datac1_freedv)
|
self.datac1_rxstatus = codec2.api.freedv_get_rx_status(self.datac1_freedv)
|
||||||
|
@ -207,8 +207,8 @@ class Test:
|
||||||
print(
|
print(
|
||||||
"NIN0: %5d RX_STATUS0: %4s NIN1: %5d RX_STATUS1: %4s NIN3: %5d RX_STATUS3: %4s"
|
"NIN0: %5d RX_STATUS0: %4s NIN1: %5d RX_STATUS1: %4s NIN3: %5d RX_STATUS3: %4s"
|
||||||
% (
|
% (
|
||||||
self.datac0_nin,
|
self.datac13_nin,
|
||||||
self.datac0_rxstatus,
|
self.datac13_rxstatus,
|
||||||
self.datac1_nin,
|
self.datac1_nin,
|
||||||
self.datac1_rxstatus,
|
self.datac1_rxstatus,
|
||||||
self.datac3_nin,
|
self.datac3_nin,
|
||||||
|
@ -225,22 +225,22 @@ class Test:
|
||||||
print(f"pyAudio error: {e}", file=sys.stderr)
|
print(f"pyAudio error: {e}", file=sys.stderr)
|
||||||
|
|
||||||
while self.receive and time.time() < self.timeout:
|
while self.receive and time.time() < self.timeout:
|
||||||
while self.datac0_buffer.nbuffer >= self.datac0_nin:
|
while self.datac13_buffer.nbuffer >= self.datac13_nin:
|
||||||
# demodulate audio
|
# demodulate audio
|
||||||
nbytes = codec2.api.freedv_rawdatarx(
|
nbytes = codec2.api.freedv_rawdatarx(
|
||||||
self.datac0_freedv,
|
self.datac13_freedv,
|
||||||
self.datac0_bytes_out,
|
self.datac13_bytes_out,
|
||||||
self.datac0_buffer.buffer.ctypes,
|
self.datac13_buffer.buffer.ctypes,
|
||||||
)
|
)
|
||||||
self.datac0_buffer.pop(self.datac0_nin)
|
self.datac13_buffer.pop(self.datac13_nin)
|
||||||
self.datac0_nin = codec2.api.freedv_nin(self.datac0_freedv)
|
self.datac13_nin = codec2.api.freedv_nin(self.datac13_freedv)
|
||||||
if nbytes == self.datac0_bytes_per_frame:
|
if nbytes == self.datac13_bytes_per_frame:
|
||||||
self.rx_total_frames_datac0 = self.rx_total_frames_datac0 + 1
|
self.rx_total_frames_datac13 = self.rx_total_frames_datac13 + 1
|
||||||
self.rx_frames_datac0 = self.rx_frames_datac0 + 1
|
self.rx_frames_datac13 = self.rx_frames_datac13 + 1
|
||||||
|
|
||||||
if self.rx_frames_datac0 == self.N_FRAMES_PER_BURST:
|
if self.rx_frames_datac13 == self.N_FRAMES_PER_BURST:
|
||||||
self.rx_frames_datac0 = 0
|
self.rx_frames_datac13 = 0
|
||||||
self.rx_bursts_datac0 = self.rx_bursts_datac0 + 1
|
self.rx_bursts_datac13 = self.rx_bursts_datac13 + 1
|
||||||
self.print_stats()
|
self.print_stats()
|
||||||
|
|
||||||
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
while self.datac1_buffer.nbuffer >= self.datac1_nin:
|
||||||
|
@ -280,7 +280,7 @@ class Test:
|
||||||
self.print_stats()
|
self.print_stats()
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.rx_bursts_datac0
|
self.rx_bursts_datac13
|
||||||
and self.rx_bursts_datac1
|
and self.rx_bursts_datac1
|
||||||
and self.rx_bursts_datac3
|
and self.rx_bursts_datac3
|
||||||
) == self.N_BURSTS:
|
) == self.N_BURSTS:
|
||||||
|
@ -297,7 +297,7 @@ class Test:
|
||||||
)
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"DATAC0: {self.rx_bursts_datac0}/{self.rx_total_frames_datac0} DATAC1: {self.rx_bursts_datac1}/{self.rx_total_frames_datac1} DATAC3: {self.rx_bursts_datac3}/{self.rx_total_frames_datac3}",
|
f"datac13: {self.rx_bursts_datac13}/{self.rx_total_frames_datac13} DATAC1: {self.rx_bursts_datac1}/{self.rx_total_frames_datac1} DATAC3: {self.rx_bursts_datac3}/{self.rx_total_frames_datac3}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
self.frx.close()
|
self.frx.close()
|
||||||
|
|
|
@ -158,9 +158,9 @@ class Test:
|
||||||
def create_modulation(self):
|
def create_modulation(self):
|
||||||
|
|
||||||
modes = [
|
modes = [
|
||||||
codec2.api.FREEDV_MODE_DATAC0,
|
codec2.FREEDV_MODE.datac13.value,
|
||||||
codec2.api.FREEDV_MODE_DATAC1,
|
codec2.FREEDV_MODE.datac1.value,
|
||||||
codec2.api.FREEDV_MODE_DATAC3,
|
codec2.FREEDV_MODE.datac3.value,
|
||||||
]
|
]
|
||||||
for m in modes:
|
for m in modes:
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ parser = argparse.ArgumentParser(description="FreeDATA audio test")
|
||||||
parser.add_argument("--bursts", dest="N_BURSTS", default=1, type=int)
|
parser.add_argument("--bursts", dest="N_BURSTS", default=1, type=int)
|
||||||
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode", dest="FREEDV_MODE", type=str, choices=["datac0", "datac1", "datac3"]
|
"--mode", dest="FREEDV_MODE", type=str, choices=["datac13", "datac1", "datac3"]
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--audiodev",
|
"--audiodev",
|
||||||
|
@ -35,7 +35,7 @@ parser.add_argument("--debug", dest="DEBUGGING_MODE", action="store_true")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--timeout",
|
"--timeout",
|
||||||
dest="TIMEOUT",
|
dest="TIMEOUT",
|
||||||
default=10,
|
default=60,
|
||||||
type=int,
|
type=int,
|
||||||
help="Timeout (seconds) before test ends",
|
help="Timeout (seconds) before test ends",
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,7 +22,7 @@ parser = argparse.ArgumentParser(description="FreeDATA audio test")
|
||||||
parser.add_argument("--bursts", dest="N_BURSTS", default=1, type=int)
|
parser.add_argument("--bursts", dest="N_BURSTS", default=1, type=int)
|
||||||
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode", dest="FREEDV_MODE", type=str, choices=["datac0", "datac1", "datac3"]
|
"--mode", dest="FREEDV_MODE", type=str, choices=["datac13", "datac1", "datac3"]
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--audiodev",
|
"--audiodev",
|
||||||
|
|
|
@ -25,7 +25,7 @@ parser.add_argument("--bursts", dest="N_BURSTS", default=1, type=int)
|
||||||
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
parser.add_argument("--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int)
|
||||||
parser.add_argument("--delay", dest="DELAY_BETWEEN_BURSTS", default=500, type=int)
|
parser.add_argument("--delay", dest="DELAY_BETWEEN_BURSTS", default=500, type=int)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode", dest="FREEDV_MODE", type=str, choices=["datac0", "datac1", "datac3"]
|
"--mode", dest="FREEDV_MODE", type=str, choices=["datac13", "datac1", "datac3"]
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--audiodev",
|
"--audiodev",
|
||||||
|
|
|
@ -22,7 +22,7 @@ import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import modem
|
import modem
|
||||||
import sock
|
import sock
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,23 +39,23 @@ def t_setup(
|
||||||
modem.RXCHANNEL = tmp_path / "hfchannel1"
|
modem.RXCHANNEL = tmp_path / "hfchannel1"
|
||||||
modem.TESTMODE = True
|
modem.TESTMODE = True
|
||||||
modem.TXCHANNEL = tmp_path / "hfchannel2"
|
modem.TXCHANNEL = tmp_path / "hfchannel2"
|
||||||
static.HAMLIB_RADIOCONTROL = "disabled"
|
HamlibParam.hamlib_radiocontrol = "disabled"
|
||||||
static.LOW_BANDWIDTH_MODE = lowbwmode
|
TNC.low_bandwidth_mode = lowbwmode
|
||||||
static.MYGRID = bytes("AA12aa", "utf-8")
|
Station.mygrid = bytes("AA12aa", "utf-8")
|
||||||
static.RESPOND_TO_CQ = True
|
TNC.respond_to_cq = True
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
# override ARQ SESSION STATE for allowing disconnect command
|
# override ARQ SESSION STATE for allowing disconnect command
|
||||||
static.ARQ_SESSION_STATE = "connected"
|
ARQ.arq_session_state = "connected"
|
||||||
|
|
||||||
mycallsign = helpers.callsign_to_bytes(mycall)
|
mycallsign = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
|
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc = data_handler.DATA()
|
||||||
|
@ -105,7 +105,7 @@ def t_highsnr_arq_short_station1(
|
||||||
log.info("S1 TX: ", mode=static.FRAME_TYPE(frametype).name)
|
log.info("S1 TX: ", mode=static.FRAME_TYPE(frametype).name)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
static.LOW_BANDWIDTH_MODE
|
TNC.low_bandwidth_mode
|
||||||
and frametype == static.FRAME_TYPE.ARQ_DC_OPEN_W.value
|
and frametype == static.FRAME_TYPE.ARQ_DC_OPEN_W.value
|
||||||
):
|
):
|
||||||
mesg = (
|
mesg = (
|
||||||
|
@ -116,7 +116,7 @@ def t_highsnr_arq_short_station1(
|
||||||
log.error(mesg)
|
log.error(mesg)
|
||||||
assert False, mesg
|
assert False, mesg
|
||||||
if (
|
if (
|
||||||
not static.LOW_BANDWIDTH_MODE
|
not TNC.low_bandwidth_mode
|
||||||
and frametype == static.FRAME_TYPE.ARQ_DC_OPEN_N.value
|
and frametype == static.FRAME_TYPE.ARQ_DC_OPEN_N.value
|
||||||
):
|
):
|
||||||
mesg = (
|
mesg = (
|
||||||
|
@ -184,23 +184,23 @@ def t_highsnr_arq_short_station1(
|
||||||
log.warning("station1 TIMEOUT", first=True)
|
log.warning("station1 TIMEOUT", first=True)
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
log.info("station1, first", arq_state=pformat(static.ARQ_STATE))
|
log.info("station1, first", arq_state=pformat(ARQ.arq_state))
|
||||||
|
|
||||||
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
||||||
sock.process_tnc_commands(json.dumps(data, indent=None))
|
sock.process_tnc_commands(json.dumps(data, indent=None))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
# override ARQ SESSION STATE for allowing disconnect command
|
# override ARQ SESSION STATE for allowing disconnect command
|
||||||
static.ARQ_SESSION_STATE = "connected"
|
ARQ.arq_session_state = "connected"
|
||||||
sock.process_tnc_commands(json.dumps(data, indent=None))
|
sock.process_tnc_commands(json.dumps(data, indent=None))
|
||||||
|
|
||||||
# Allow enough time for this side to process the disconnect frame.
|
# Allow enough time for this side to process the disconnect frame.
|
||||||
timeout = time.time() + 20
|
timeout = time.time() + 20
|
||||||
while static.ARQ_STATE or tnc.data_queue_transmit.queue:
|
while ARQ.arq_state or tnc.data_queue_transmit.queue:
|
||||||
if time.time() > timeout:
|
if time.time() > timeout:
|
||||||
log.error("station1", TIMEOUT=True)
|
log.error("station1", TIMEOUT=True)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station1", arq_state=pformat(static.ARQ_STATE))
|
log.info("station1", arq_state=pformat(ARQ.arq_state))
|
||||||
|
|
||||||
# log.info("S1 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
# log.info("S1 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
||||||
# log.info("S1 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
# log.info("S1 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
||||||
|
|
|
@ -19,7 +19,7 @@ import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import modem
|
import modem
|
||||||
import sock
|
import sock
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,23 +36,23 @@ def t_setup(
|
||||||
modem.RXCHANNEL = tmp_path / "hfchannel2"
|
modem.RXCHANNEL = tmp_path / "hfchannel2"
|
||||||
modem.TESTMODE = True
|
modem.TESTMODE = True
|
||||||
modem.TXCHANNEL = tmp_path / "hfchannel1"
|
modem.TXCHANNEL = tmp_path / "hfchannel1"
|
||||||
static.HAMLIB_RADIOCONTROL = "disabled"
|
HamlibParam.hamlib_radiocontrol = "disabled"
|
||||||
static.LOW_BANDWIDTH_MODE = lowbwmode
|
TNC.low_bandwidth_mode = lowbwmode
|
||||||
static.MYGRID = bytes("AA12aa", "utf-8")
|
Station.mygrid = bytes("AA12aa", "utf-8")
|
||||||
static.RESPOND_TO_CQ = True
|
TNC.respond_to_cq = True
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
# override ARQ SESSION STATE for allowing disconnect command
|
# override ARQ SESSION STATE for allowing disconnect command
|
||||||
static.ARQ_SESSION_STATE = "connected"
|
ARQ.arq_session_state = "connected"
|
||||||
|
|
||||||
mycallsign = helpers.callsign_to_bytes(mycall)
|
mycallsign = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
|
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc = data_handler.DATA()
|
||||||
|
@ -136,13 +136,13 @@ def t_highsnr_arq_short_station2(
|
||||||
# the queue to an object for comparisons.
|
# the queue to an object for comparisons.
|
||||||
while (
|
while (
|
||||||
'"arq":"transmission","status":"received"' not in str(sock.SOCKET_QUEUE.queue)
|
'"arq":"transmission","status":"received"' not in str(sock.SOCKET_QUEUE.queue)
|
||||||
or static.ARQ_STATE
|
or ARQ.arq_state
|
||||||
):
|
):
|
||||||
if time.time() > timeout:
|
if time.time() > timeout:
|
||||||
log.warning("station2 TIMEOUT", first=True)
|
log.warning("station2 TIMEOUT", first=True)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station2, first", arq_state=pformat(static.ARQ_STATE))
|
log.info("station2, first", arq_state=pformat(ARQ.arq_state))
|
||||||
|
|
||||||
# Allow enough time for this side to receive the disconnect frame.
|
# Allow enough time for this side to receive the disconnect frame.
|
||||||
timeout = time.time() + 20
|
timeout = time.time() + 20
|
||||||
|
@ -151,7 +151,7 @@ def t_highsnr_arq_short_station2(
|
||||||
log.warning("station2", TIMEOUT=True)
|
log.warning("station2", TIMEOUT=True)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station2", arq_state=pformat(static.ARQ_STATE))
|
log.info("station2", arq_state=pformat(ARQ.arq_state))
|
||||||
|
|
||||||
# log.info("S2 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
# log.info("S2 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
||||||
# log.info("S2 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
# log.info("S2 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
||||||
|
|
|
@ -5,9 +5,9 @@ simulated audio channel.
|
||||||
|
|
||||||
Near end-to-end test for sending / receiving control frames through the TNC and modem
|
Near end-to-end test for sending / receiving control frames through the TNC and modem
|
||||||
and back through on the other station. Data injection initiates from the queue used
|
and back through on the other station. Data injection initiates from the queue used
|
||||||
by the daemon process into and out of the TNC.
|
by the daemon process into and out of the TNCParam.
|
||||||
|
|
||||||
Invoked from test_datac0.py.
|
Invoked from test_datac13.py.
|
||||||
|
|
||||||
@author: N2KIQ
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
@ -21,9 +21,10 @@ import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import modem
|
import modem
|
||||||
import sock
|
import sock
|
||||||
import static
|
from static import ARQ, HamlibParam, ModemParam, Station, TNC as TNCParam
|
||||||
import structlog
|
|
||||||
from static import FRAME_TYPE as FR_TYPE
|
from static import FRAME_TYPE as FR_TYPE
|
||||||
|
import structlog
|
||||||
|
#from static import FRAME_TYPE as FR_TYPE
|
||||||
|
|
||||||
|
|
||||||
def t_setup(
|
def t_setup(
|
||||||
|
@ -46,33 +47,35 @@ def t_setup(
|
||||||
modem.RXCHANNEL = tmp_path / rx_channel
|
modem.RXCHANNEL = tmp_path / rx_channel
|
||||||
modem.TESTMODE = True
|
modem.TESTMODE = True
|
||||||
modem.TXCHANNEL = tmp_path / tx_channel
|
modem.TXCHANNEL = tmp_path / tx_channel
|
||||||
static.HAMLIB_RADIOCONTROL = "disabled"
|
HamlibParam.hamlib_radiocontrol = "disabled"
|
||||||
static.LOW_BANDWIDTH_MODE = lowbwmode or True
|
TNCParam.low_bandwidth_mode = lowbwmode or True
|
||||||
static.MYGRID = bytes("AA12aa", "utf-8")
|
Station.mygrid = bytes("AA12aa", "utf-8")
|
||||||
static.RESPOND_TO_CQ = True
|
TNCParam.respond_to_cq = True
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
mycallsign = helpers.callsign_to_bytes(mycall)
|
mycallsign = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
|
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc_data_handler = data_handler.DATA()
|
||||||
orig_rx_func = data_handler.DATA.process_data
|
orig_rx_func = data_handler.DATA.process_data
|
||||||
data_handler.DATA.process_data = t_process_data
|
data_handler.DATA.process_data = t_process_data
|
||||||
tnc.log = structlog.get_logger(f"station{station}_DATA")
|
tnc_data_handler.log = structlog.get_logger(f"station{station}_DATA")
|
||||||
# Limit the frame-ack timeout
|
# Limit the frame-ack timeout
|
||||||
tnc.time_list_low_bw = [3, 1, 1]
|
tnc_data_handler.time_list_low_bw = [8, 8, 8]
|
||||||
tnc.time_list_high_bw = [3, 1, 1]
|
tnc_data_handler.time_list_high_bw = [8, 8, 8]
|
||||||
tnc.time_list = [3, 1, 1]
|
tnc_data_handler.time_list = [8, 8, 8]
|
||||||
# Limit number of retries
|
# Limit number of retries
|
||||||
tnc.rx_n_max_retries_per_burst = 4
|
tnc_data_handler.rx_n_max_retries_per_burst = 4
|
||||||
|
ModemParam.tx_delay = 50 # add additional delay time for passing test
|
||||||
|
|
||||||
|
|
||||||
# Create the modem
|
# Create the modem
|
||||||
t_modem = modem.RF()
|
t_modem = modem.RF()
|
||||||
|
@ -80,10 +83,10 @@ def t_setup(
|
||||||
modem.RF.transmit = t_transmit
|
modem.RF.transmit = t_transmit
|
||||||
t_modem.log = structlog.get_logger(f"station{station}_RF")
|
t_modem.log = structlog.get_logger(f"station{station}_RF")
|
||||||
|
|
||||||
return tnc, orig_rx_func, orig_tx_func
|
return tnc_data_handler, orig_rx_func, orig_tx_func
|
||||||
|
|
||||||
|
|
||||||
def t_datac0_1(
|
def t_datac13_1(
|
||||||
parent_pipe,
|
parent_pipe,
|
||||||
mycall: str,
|
mycall: str,
|
||||||
dxcall: str,
|
dxcall: str,
|
||||||
|
@ -93,7 +96,7 @@ def t_datac0_1(
|
||||||
log = structlog.get_logger("station1")
|
log = structlog.get_logger("station1")
|
||||||
orig_tx_func: Callable
|
orig_tx_func: Callable
|
||||||
orig_rx_func: Callable
|
orig_rx_func: Callable
|
||||||
log.debug("t_datac0_1:", TMP_PATH=tmp_path)
|
log.debug("t_datac13_1:", TMP_PATH=tmp_path)
|
||||||
|
|
||||||
# Unpack tuple
|
# Unpack tuple
|
||||||
data, timeout_duration, tx_check, _, final_tx_check, _ = config
|
data, timeout_duration, tx_check, _, final_tx_check, _ = config
|
||||||
|
@ -131,7 +134,7 @@ def t_datac0_1(
|
||||||
# original function captured before this one was put in place.
|
# original function captured before this one was put in place.
|
||||||
orig_rx_func(self, bytes_out, freedv, bytes_per_frame) # type: ignore
|
orig_rx_func(self, bytes_out, freedv, bytes_per_frame) # type: ignore
|
||||||
|
|
||||||
tnc, orig_rx_func, orig_tx_func = t_setup(
|
tnc_data_handler, orig_rx_func, orig_tx_func = t_setup(
|
||||||
1,
|
1,
|
||||||
mycall,
|
mycall,
|
||||||
dxcall,
|
dxcall,
|
||||||
|
@ -143,14 +146,14 @@ def t_datac0_1(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.info("t_datac0_1:", RXCHANNEL=modem.RXCHANNEL)
|
log.info("t_datac13_1:", RXCHANNEL=modem.RXCHANNEL)
|
||||||
log.info("t_datac0_1:", TXCHANNEL=modem.TXCHANNEL)
|
log.info("t_datac13_1:", TXCHANNEL=modem.TXCHANNEL)
|
||||||
|
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if "stop" in data["command"]:
|
if "stop" in data["command"]:
|
||||||
log.debug("t_datac0_1: STOP test, setting TNC state")
|
log.debug("t_datac13_1: STOP test, setting TNC state")
|
||||||
static.TNC_STATE = "BUSY"
|
TNCParam.tnc_state = "BUSY"
|
||||||
static.ARQ_STATE = True
|
ARQ.arq_state = True
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
|
@ -166,25 +169,25 @@ def t_datac0_1(
|
||||||
tx_check=tx_check,
|
tx_check=tx_check,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.5)
|
||||||
log.info("station1, first")
|
log.info("station1, first")
|
||||||
# override ARQ SESSION STATE for allowing disconnect command
|
# override ARQ SESSION STATE for allowing disconnect command
|
||||||
static.ARQ_SESSION_STATE = "connected"
|
ARQ.arq_session_state = "connected"
|
||||||
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
# Allow enough time for this side to process the disconnect frame.
|
# Allow enough time for this side to process the disconnect frame.
|
||||||
timeout = time.time() + timeout_duration
|
timeout = time.time() + timeout_duration
|
||||||
while tnc.data_queue_transmit.queue:
|
while tnc_data_handler.data_queue_transmit.queue:
|
||||||
if time.time() > timeout:
|
if time.time() > timeout:
|
||||||
log.warning("station1", TIMEOUT=True, dq_tx=tnc.data_queue_transmit.queue)
|
log.warning("station1", TIMEOUT=True, dq_tx=tnc_data_handler.data_queue_transmit.queue)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station1, final")
|
log.info("station1, final")
|
||||||
|
|
||||||
# log.info("S1 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
# log.info("S1 DQT: ", DQ_Tx=pformat(TNCParam.data_queue_transmit.queue))
|
||||||
# log.info("S1 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
# log.info("S1 DQR: ", DQ_Rx=pformat(TNCParam.data_queue_received.queue))
|
||||||
log.debug("S1 Socket: ", socket_queue=pformat(sock.SOCKET_QUEUE.queue))
|
log.debug("S1 Socket: ", socket_queue=pformat(sock.SOCKET_QUEUE.queue))
|
||||||
|
|
||||||
for item in final_tx_check:
|
for item in final_tx_check:
|
||||||
|
@ -199,7 +202,7 @@ def t_datac0_1(
|
||||||
log.warning("station1: Exiting!")
|
log.warning("station1: Exiting!")
|
||||||
|
|
||||||
|
|
||||||
def t_datac0_2(
|
def t_datac13_2(
|
||||||
parent_pipe,
|
parent_pipe,
|
||||||
mycall: str,
|
mycall: str,
|
||||||
dxcall: str,
|
dxcall: str,
|
||||||
|
@ -209,7 +212,7 @@ def t_datac0_2(
|
||||||
log = structlog.get_logger("station2")
|
log = structlog.get_logger("station2")
|
||||||
orig_tx_func: Callable
|
orig_tx_func: Callable
|
||||||
orig_rx_func: Callable
|
orig_rx_func: Callable
|
||||||
log.debug("t_datac0_2:", TMP_PATH=tmp_path)
|
log.debug("t_datac13_2:", TMP_PATH=tmp_path)
|
||||||
|
|
||||||
# Unpack tuple
|
# Unpack tuple
|
||||||
data, timeout_duration, _, rx_check, _, final_rx_check = config
|
data, timeout_duration, _, rx_check, _, final_rx_check = config
|
||||||
|
@ -259,8 +262,8 @@ def t_datac0_2(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.info("t_datac0_2:", RXCHANNEL=modem.RXCHANNEL)
|
log.info("t_datac13_2:", RXCHANNEL=modem.RXCHANNEL)
|
||||||
log.info("t_datac0_2:", TXCHANNEL=modem.TXCHANNEL)
|
log.info("t_datac13_2:", TXCHANNEL=modem.TXCHANNEL)
|
||||||
|
|
||||||
if "cq" in data:
|
if "cq" in data:
|
||||||
t_data = {"type": "arq", "command": "stop_transmission"}
|
t_data = {"type": "arq", "command": "stop_transmission"}
|
||||||
|
@ -292,8 +295,8 @@ def t_datac0_2(
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station2, final")
|
log.info("station2, final")
|
||||||
|
|
||||||
# log.info("S2 DQT: ", DQ_Tx=pformat(tnc.data_queue_transmit.queue))
|
# log.info("S2 DQT: ", DQ_Tx=pformat(TNCParam.data_queue_transmit.queue))
|
||||||
# log.info("S2 DQR: ", DQ_Rx=pformat(tnc.data_queue_received.queue))
|
# log.info("S2 DQR: ", DQ_Rx=pformat(TNCParam.data_queue_received.queue))
|
||||||
log.debug("S2 Socket: ", socket_queue=pformat(sock.SOCKET_QUEUE.queue))
|
log.debug("S2 Socket: ", socket_queue=pformat(sock.SOCKET_QUEUE.queue))
|
||||||
|
|
||||||
for item in final_rx_check:
|
for item in final_rx_check:
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Negative test utilities for datac0 frames.
|
Negative test utilities for datac13 frames.
|
||||||
|
|
||||||
@author: kronenpj
|
@author: kronenpj
|
||||||
"""
|
"""
|
||||||
|
@ -15,9 +15,9 @@ import data_handler
|
||||||
import helpers
|
import helpers
|
||||||
import modem
|
import modem
|
||||||
import sock
|
import sock
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC, FRAME_TYPE as FR_TYPE
|
||||||
import structlog
|
import structlog
|
||||||
from static import FRAME_TYPE as FR_TYPE
|
#from static import FRAME_TYPE as FR_TYPE
|
||||||
|
|
||||||
|
|
||||||
def t_setup(
|
def t_setup(
|
||||||
|
@ -40,44 +40,44 @@ def t_setup(
|
||||||
modem.RXCHANNEL = tmp_path / rx_channel
|
modem.RXCHANNEL = tmp_path / rx_channel
|
||||||
modem.TESTMODE = True
|
modem.TESTMODE = True
|
||||||
modem.TXCHANNEL = tmp_path / tx_channel
|
modem.TXCHANNEL = tmp_path / tx_channel
|
||||||
static.HAMLIB_RADIOCONTROL = "disabled"
|
HamlibParam.hamlib_radiocontrol = "disabled"
|
||||||
static.LOW_BANDWIDTH_MODE = lowbwmode or True
|
TNC.low_bandwidth_mode = lowbwmode or True
|
||||||
static.MYGRID = bytes("AA12aa", "utf-8")
|
Station.mygrid = bytes("AA12aa", "utf-8")
|
||||||
static.RESPOND_TO_CQ = True
|
TNC.respond_to_cq = True
|
||||||
static.SSID_LIST = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
Station.ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
mycallsign = helpers.callsign_to_bytes(mycall)
|
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
||||||
static.MYCALLSIGN = mycallsign
|
Station.mycallsign = mycallsign
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(mycallsign)
|
||||||
|
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcall)
|
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(dxcallsign)
|
||||||
|
|
||||||
# Create the TNC
|
# Create the TNC
|
||||||
tnc = data_handler.DATA()
|
tnc_data_handler = data_handler.DATA()
|
||||||
orig_rx_func = data_handler.DATA.process_data
|
orig_rx_func = data_handler.DATA.process_data
|
||||||
data_handler.DATA.process_data = t_process_data
|
data_handler.DATA.process_data = t_process_data
|
||||||
tnc.log = structlog.get_logger(f"station{station}_DATA")
|
tnc_data_handler.log = structlog.get_logger(f"station{station}_DATA")
|
||||||
# Limit the frame-ack timeout
|
# Limit the frame-ack timeout
|
||||||
tnc.time_list_low_bw = [3, 1, 1]
|
tnc_data_handler.time_list_low_bw = [8, 8, 8]
|
||||||
tnc.time_list_high_bw = [3, 1, 1]
|
tnc_data_handler.time_list_high_bw = [8, 8, 8]
|
||||||
tnc.time_list = [3, 1, 1]
|
tnc_data_handler.time_list = [8, 8, 8]
|
||||||
# Limit number of retries
|
# Limit number of retries
|
||||||
tnc.rx_n_max_retries_per_burst = 4
|
tnc_data_handler.rx_n_max_retries_per_burst = 4
|
||||||
|
ModemParam.tx_delay = 50 # add additional delay time for passing test
|
||||||
# Create the modem
|
# Create the modem
|
||||||
t_modem = modem.RF()
|
t_modem = modem.RF()
|
||||||
orig_tx_func = modem.RF.transmit
|
orig_tx_func = modem.RF.transmit
|
||||||
modem.RF.transmit = t_transmit
|
modem.RF.transmit = t_transmit
|
||||||
t_modem.log = structlog.get_logger(f"station{station}_RF")
|
t_modem.log = structlog.get_logger(f"station{station}_RF")
|
||||||
|
|
||||||
return tnc, orig_rx_func, orig_tx_func
|
return tnc_data_handler, orig_rx_func, orig_tx_func
|
||||||
|
|
||||||
|
|
||||||
def t_datac0_1(
|
def t_datac13_1(
|
||||||
parent_pipe,
|
parent_pipe,
|
||||||
mycall: str,
|
mycall: str,
|
||||||
dxcall: str,
|
dxcall: str,
|
||||||
|
@ -87,7 +87,7 @@ def t_datac0_1(
|
||||||
log = structlog.get_logger("station1")
|
log = structlog.get_logger("station1")
|
||||||
orig_tx_func: Callable
|
orig_tx_func: Callable
|
||||||
orig_rx_func: Callable
|
orig_rx_func: Callable
|
||||||
log.debug("t_datac0_1:", TMP_PATH=tmp_path)
|
log.debug("t_datac13_1:", TMP_PATH=tmp_path)
|
||||||
|
|
||||||
# Unpack tuple
|
# Unpack tuple
|
||||||
data, timeout_duration, tx_check, _, final_tx_check, _ = config
|
data, timeout_duration, tx_check, _, final_tx_check, _ = config
|
||||||
|
@ -125,7 +125,7 @@ def t_datac0_1(
|
||||||
# original function captured before this one was put in place.
|
# original function captured before this one was put in place.
|
||||||
orig_rx_func(self, bytes_out, freedv, bytes_per_frame) # type: ignore
|
orig_rx_func(self, bytes_out, freedv, bytes_per_frame) # type: ignore
|
||||||
|
|
||||||
tnc, orig_rx_func, orig_tx_func = t_setup(
|
tnc_data_handler, orig_rx_func, orig_tx_func = t_setup(
|
||||||
1,
|
1,
|
||||||
mycall,
|
mycall,
|
||||||
dxcall,
|
dxcall,
|
||||||
|
@ -137,21 +137,21 @@ def t_datac0_1(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.info("t_datac0_1:", RXCHANNEL=modem.RXCHANNEL)
|
log.info("t_datac13_1:", RXCHANNEL=modem.RXCHANNEL)
|
||||||
log.info("t_datac0_1:", TXCHANNEL=modem.TXCHANNEL)
|
log.info("t_datac13_1:", TXCHANNEL=modem.TXCHANNEL)
|
||||||
|
|
||||||
orig_dxcall = static.DXCALLSIGN
|
orig_dxcall = Station.dxcallsign
|
||||||
if "stop" in data["command"]:
|
if "stop" in data["command"]:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.debug(
|
log.debug(
|
||||||
"t_datac0_1: STOP test, setting TNC state",
|
"t_datac13_1: STOP test, setting TNC state",
|
||||||
mycall=static.MYCALLSIGN,
|
mycall=Station.mycallsign,
|
||||||
dxcall=static.DXCALLSIGN,
|
dxcall=Station.dxcallsign,
|
||||||
)
|
)
|
||||||
static.DXCALLSIGN = helpers.callsign_to_bytes(data["dxcallsign"])
|
Station.dxcallsign = helpers.callsign_to_bytes(data["dxcallsign"])
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_CRC = helpers.get_crc_24(Station.dxcallsign)
|
||||||
static.TNC_STATE = "BUSY"
|
TNC.tnc_state = "BUSY"
|
||||||
static.ARQ_STATE = True
|
ARQ.arq_state = True
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
|
|
||||||
|
@ -172,19 +172,19 @@ def t_datac0_1(
|
||||||
if "stop" in data["command"]:
|
if "stop" in data["command"]:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.debug("STOP test, resetting DX callsign")
|
log.debug("STOP test, resetting DX callsign")
|
||||||
static.DXCALLSIGN = orig_dxcall
|
Station.dxcallsign = orig_dxcall
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_CRC = helpers.get_crc_24(Station.dxcallsign)
|
||||||
# override ARQ SESSION STATE for allowing disconnect command
|
# override ARQ SESSION STATE for allowing disconnect command
|
||||||
static.ARQ_SESSION_STATE = "connected"
|
ARQ.arq_session_state = "connected"
|
||||||
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
data = {"type": "arq", "command": "disconnect", "dxcallsign": dxcall}
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
# Allow enough time for this side to process the disconnect frame.
|
# Allow enough time for this side to process the disconnect frame.
|
||||||
timeout = time.time() + timeout_duration
|
timeout = time.time() + timeout_duration
|
||||||
while tnc.data_queue_transmit.queue:
|
while tnc_data_handler.data_queue_transmit.queue:
|
||||||
if time.time() > timeout:
|
if time.time() > timeout:
|
||||||
log.warning("station1", TIMEOUT=True, dq_tx=tnc.data_queue_transmit.queue)
|
log.warning("station1", TIMEOUT=True, dq_tx=tnc_data_handler.data_queue_transmit.queue)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
log.info("station1, final")
|
log.info("station1, final")
|
||||||
|
@ -204,7 +204,7 @@ def t_datac0_1(
|
||||||
log.warning("station1: Exiting!")
|
log.warning("station1: Exiting!")
|
||||||
|
|
||||||
|
|
||||||
def t_datac0_2(
|
def t_datac13_2(
|
||||||
parent_pipe,
|
parent_pipe,
|
||||||
mycall: str,
|
mycall: str,
|
||||||
dxcall: str,
|
dxcall: str,
|
||||||
|
@ -214,7 +214,7 @@ def t_datac0_2(
|
||||||
log = structlog.get_logger("station2")
|
log = structlog.get_logger("station2")
|
||||||
orig_tx_func: Callable
|
orig_tx_func: Callable
|
||||||
orig_rx_func: Callable
|
orig_rx_func: Callable
|
||||||
log.debug("t_datac0_2:", TMP_PATH=tmp_path)
|
log.debug("t_datac13_2:", TMP_PATH=tmp_path)
|
||||||
|
|
||||||
# Unpack tuple
|
# Unpack tuple
|
||||||
data, timeout_duration, _, rx_check, _, final_rx_check = config
|
data, timeout_duration, _, rx_check, _, final_rx_check = config
|
||||||
|
@ -264,9 +264,9 @@ def t_datac0_2(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.info("t_datac0_2:", RXCHANNEL=modem.RXCHANNEL)
|
log.info("t_datac13_2:", RXCHANNEL=modem.RXCHANNEL)
|
||||||
log.info("t_datac0_2:", TXCHANNEL=modem.TXCHANNEL)
|
log.info("t_datac13_2:", TXCHANNEL=modem.TXCHANNEL)
|
||||||
log.info("t_datac0_2:", mycall=static.MYCALLSIGN)
|
log.info("t_datac13_2:", mycall=Station.mycallsign)
|
||||||
|
|
||||||
if "cq" in data:
|
if "cq" in data:
|
||||||
t_data = {"type": "arq", "command": "stop_transmission"}
|
t_data = {"type": "arq", "command": "stop_transmission"}
|
||||||
|
@ -292,9 +292,6 @@ def t_datac0_2(
|
||||||
# Allow enough time for this side to receive the disconnect frame.
|
# Allow enough time for this side to receive the disconnect frame.
|
||||||
timeout = time.time() + timeout_duration
|
timeout = time.time() + timeout_duration
|
||||||
while '"arq":"session", "status":"close"' not in str(sock.SOCKET_QUEUE.queue):
|
while '"arq":"session", "status":"close"' not in str(sock.SOCKET_QUEUE.queue):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if time.time() > timeout:
|
if time.time() > timeout:
|
||||||
log.warning("station2", TIMEOUT=True, queue=str(sock.SOCKET_QUEUE.queue))
|
log.warning("station2", TIMEOUT=True, queue=str(sock.SOCKET_QUEUE.queue))
|
||||||
break
|
break
|
|
@ -67,7 +67,7 @@ def test_mm_rx():
|
||||||
for idx in range(3):
|
for idx in range(3):
|
||||||
datac_freedv.append(
|
datac_freedv.append(
|
||||||
ctypes.cast(
|
ctypes.cast(
|
||||||
codec2.api.freedv_open(codec2.api.FREEDV_MODE_DATAC0), ctypes.c_void_p
|
codec2.api.freedv_open(codec2.FREEDV_MODE.datac13.value), ctypes.c_void_p
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
datac_bytes_per_frame.append(
|
datac_bytes_per_frame.append(
|
||||||
|
@ -121,11 +121,11 @@ def test_mm_rx():
|
||||||
for idx in range(3):
|
for idx in range(3):
|
||||||
datac_nin[idx] = codec2.api.freedv_nin(datac_freedv[idx])
|
datac_nin[idx] = codec2.api.freedv_nin(datac_freedv[idx])
|
||||||
|
|
||||||
def print_stats(time_datac0, time_datac1, time_datac3):
|
def print_stats(time_datac13, time_datac1, time_datac3):
|
||||||
if not DEBUGGING_MODE:
|
if not DEBUGGING_MODE:
|
||||||
return
|
return
|
||||||
|
|
||||||
time_datac = [time_datac0, time_datac1, time_datac3]
|
time_datac = [time_datac13, time_datac1, time_datac3]
|
||||||
datac_rxstatus = ["", "", ""]
|
datac_rxstatus = ["", "", ""]
|
||||||
for idx in range(3):
|
for idx in range(3):
|
||||||
datac_rxstatus[idx] = codec2.api.rx_sync_flags_to_text[
|
datac_rxstatus[idx] = codec2.api.rx_sync_flags_to_text[
|
||||||
|
@ -206,7 +206,7 @@ def test_mm_rx():
|
||||||
print("TIMEOUT REACHED", file=sys.stderr)
|
print("TIMEOUT REACHED", file=sys.stderr)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"DATAC0: {rx_bursts_datac[0]}/{rx_total_frames_datac[0]} "
|
f"DATAC13: {rx_bursts_datac[0]}/{rx_total_frames_datac[0]} "
|
||||||
f"DATAC1: {rx_bursts_datac[1]}/{rx_total_frames_datac[1]} "
|
f"DATAC1: {rx_bursts_datac[1]}/{rx_total_frames_datac[1]} "
|
||||||
f"DATAC3: {rx_bursts_datac[2]}/{rx_total_frames_datac[2]}",
|
f"DATAC3: {rx_bursts_datac[2]}/{rx_total_frames_datac[2]}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
|
@ -241,7 +241,7 @@ def parse_arguments():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--timeout",
|
"--timeout",
|
||||||
dest="TIMEOUT",
|
dest="TIMEOUT",
|
||||||
default=10,
|
default=60,
|
||||||
type=int,
|
type=int,
|
||||||
help="Timeout (seconds) before test ends",
|
help="Timeout (seconds) before test ends",
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,9 +49,9 @@ def test_mm_tx():
|
||||||
data_out = b"HELLO WORLD!"
|
data_out = b"HELLO WORLD!"
|
||||||
|
|
||||||
modes = [
|
modes = [
|
||||||
codec2.api.FREEDV_MODE_DATAC0,
|
codec2.FREEDV_MODE.datac13.value,
|
||||||
codec2.api.FREEDV_MODE_DATAC1,
|
codec2.FREEDV_MODE.datac1.value,
|
||||||
codec2.api.FREEDV_MODE_DATAC3,
|
codec2.FREEDV_MODE.datac3.value,
|
||||||
]
|
]
|
||||||
|
|
||||||
if AUDIO_OUTPUT_DEVICE != -1:
|
if AUDIO_OUTPUT_DEVICE != -1:
|
||||||
|
|
|
@ -221,7 +221,7 @@ def parse_arguments():
|
||||||
"--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int
|
"--framesperburst", dest="N_FRAMES_PER_BURST", default=1, type=int
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode", dest="FREEDV_MODE", type=str, choices=["datac0", "datac1", "datac3"]
|
"--mode", dest="FREEDV_MODE", type=str, choices=["datac13", "datac1", "datac3"]
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--audiodev",
|
"--audiodev",
|
||||||
|
@ -234,7 +234,7 @@ def parse_arguments():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--timeout",
|
"--timeout",
|
||||||
dest="TIMEOUT",
|
dest="TIMEOUT",
|
||||||
default=10,
|
default=60,
|
||||||
type=int,
|
type=int,
|
||||||
help="Timeout (seconds) before test ends",
|
help="Timeout (seconds) before test ends",
|
||||||
)
|
)
|
||||||
|
|
|
@ -122,18 +122,18 @@ def t_arq_iss(*args):
|
||||||
else:
|
else:
|
||||||
assert not MESSAGE, f"{MESSAGE} not known to test."
|
assert not MESSAGE, f"{MESSAGE} not known to test."
|
||||||
|
|
||||||
time.sleep(0.5)
|
time.sleep(2.5)
|
||||||
|
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
|
|
||||||
time.sleep(1.5)
|
time.sleep(7.5)
|
||||||
|
|
||||||
data = {"type": "arq", "command": "stop_transmission"}
|
data = {"type": "arq", "command": "stop_transmission"}
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
|
|
||||||
time.sleep(0.5)
|
time.sleep(2.5)
|
||||||
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
sock.ThreadedTCPRequestHandler.process_tnc_commands(None,json.dumps(data, indent=None))
|
||||||
|
|
||||||
# Set timeout
|
# Set timeout
|
||||||
|
|
|
@ -198,7 +198,7 @@ def parse_arguments():
|
||||||
help="delay between bursts in ms",
|
help="delay between bursts in ms",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode", dest="FREEDV_MODE", type=str, choices=["datac0", "datac1", "datac3"]
|
"--mode", dest="FREEDV_MODE", type=str, choices=["datac13", "datac1", "datac3"]
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--audiodev",
|
"--audiodev",
|
||||||
|
|
|
@ -18,20 +18,38 @@ import structlog
|
||||||
|
|
||||||
log = structlog.get_logger("codec2")
|
log = structlog.get_logger("codec2")
|
||||||
|
|
||||||
|
|
||||||
# Enum for codec2 modes
|
# Enum for codec2 modes
|
||||||
class FREEDV_MODE(Enum):
|
class FREEDV_MODE(Enum):
|
||||||
"""
|
"""
|
||||||
Enumeration for codec2 modes and names
|
Enumeration for codec2 modes and names
|
||||||
"""
|
"""
|
||||||
sig0 = 14
|
sig0 = 19
|
||||||
sig1 = 14
|
sig1 = 19
|
||||||
datac0 = 14
|
datac0 = 14
|
||||||
datac1 = 10
|
datac1 = 10
|
||||||
datac3 = 12
|
datac3 = 12
|
||||||
|
datac4 = 18
|
||||||
|
datac13 = 19
|
||||||
fsk_ldpc = 9
|
fsk_ldpc = 9
|
||||||
fsk_ldpc_0 = 200
|
fsk_ldpc_0 = 200
|
||||||
fsk_ldpc_1 = 201
|
fsk_ldpc_1 = 201
|
||||||
|
|
||||||
|
class FREEDV_MODE_USED_SLOTS(Enum):
|
||||||
|
"""
|
||||||
|
Enumeration for codec2 used slots
|
||||||
|
"""
|
||||||
|
sig0 = [False, False, True, False, False]
|
||||||
|
sig1 = [False, False, True, False, False]
|
||||||
|
datac0 = [False, False, True, False, False]
|
||||||
|
datac1 = [False, True, True, True, False]
|
||||||
|
datac3 = [False, False, True, False, False]
|
||||||
|
datac4 = [False, False, True, False, False]
|
||||||
|
datac13 = [False, False, True, False, False]
|
||||||
|
fsk_ldpc = [False, False, True, False, False]
|
||||||
|
fsk_ldpc_0 = [False, False, True, False, False]
|
||||||
|
fsk_ldpc_1 = [False, False, True, False, False]
|
||||||
|
|
||||||
# Function for returning the mode value
|
# Function for returning the mode value
|
||||||
def freedv_get_mode_value_by_name(mode: str) -> int:
|
def freedv_get_mode_value_by_name(mode: str) -> int:
|
||||||
"""
|
"""
|
||||||
|
@ -101,6 +119,9 @@ if api is None or "api" not in locals():
|
||||||
api.freedv_open.argype = [ctypes.c_int] # type: ignore
|
api.freedv_open.argype = [ctypes.c_int] # type: ignore
|
||||||
api.freedv_open.restype = ctypes.c_void_p
|
api.freedv_open.restype = ctypes.c_void_p
|
||||||
|
|
||||||
|
api.freedv_set_sync.argype = [ctypes.c_void_p, ctypes.c_int] # type: ignore
|
||||||
|
api.freedv_set_sync.restype = ctypes.c_void_p
|
||||||
|
|
||||||
api.freedv_open_advanced.argtype = [ctypes.c_int, ctypes.c_void_p] # type: ignore
|
api.freedv_open_advanced.argtype = [ctypes.c_int, ctypes.c_void_p] # type: ignore
|
||||||
api.freedv_open_advanced.restype = ctypes.c_void_p
|
api.freedv_open_advanced.restype = ctypes.c_void_p
|
||||||
|
|
||||||
|
@ -150,10 +171,6 @@ api.freedv_get_n_max_modem_samples.argtype = [ctypes.c_void_p] # type: ignore
|
||||||
api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
|
api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
|
||||||
|
|
||||||
api.FREEDV_FS_8000 = 8000 # type: ignore
|
api.FREEDV_FS_8000 = 8000 # type: ignore
|
||||||
api.FREEDV_MODE_DATAC1 = 10 # type: ignore
|
|
||||||
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
|
# -------------------------------- FSK LDPC MODE SETTINGS
|
||||||
|
|
||||||
|
@ -216,7 +233,7 @@ api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_4096_8192_3d".encode("utf-8") # co
|
||||||
|
|
||||||
# ------- MODEM STATS STRUCTURES
|
# ------- MODEM STATS STRUCTURES
|
||||||
MODEM_STATS_NC_MAX = 50 + 1 * 2
|
MODEM_STATS_NC_MAX = 50 + 1 * 2
|
||||||
MODEM_STATS_NR_MAX = 160 * 2
|
MODEM_STATS_NR_MAX = 320 * 2
|
||||||
MODEM_STATS_ET_MAX = 8
|
MODEM_STATS_ET_MAX = 8
|
||||||
MODEM_STATS_EYE_IND_MAX = 160
|
MODEM_STATS_EYE_IND_MAX = 160
|
||||||
MODEM_STATS_NSPEC = 512
|
MODEM_STATS_NSPEC = 512
|
||||||
|
|
|
@ -4,20 +4,20 @@ tncport = 3000
|
||||||
|
|
||||||
[STATION]
|
[STATION]
|
||||||
#station settings
|
#station settings
|
||||||
mycall = DJ2LS-9
|
mycall = DN2LS-0
|
||||||
mygrid = JN12AA
|
mygrid = JN48cs
|
||||||
ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
[AUDIO]
|
[AUDIO]
|
||||||
#audio settings
|
#audio settings
|
||||||
rx = 0
|
rx = 0
|
||||||
tx = 1
|
tx = 0
|
||||||
txaudiolevel = 78
|
txaudiolevel = 250
|
||||||
auto_tune = False
|
auto_tune = False
|
||||||
|
|
||||||
[RADIO]
|
[RADIO]
|
||||||
#radio settings
|
#radio settings
|
||||||
radiocontrol = rigctld
|
radiocontrol = disabled
|
||||||
rigctld_ip = 127.0.0.1
|
rigctld_ip = 127.0.0.1
|
||||||
rigctld_port = 4532
|
rigctld_port = 4532
|
||||||
|
|
||||||
|
@ -26,12 +26,12 @@ rigctld_port = 4532
|
||||||
scatter = True
|
scatter = True
|
||||||
fft = True
|
fft = True
|
||||||
narrowband = False
|
narrowband = False
|
||||||
fmin = -250.0
|
fmin = -150.0
|
||||||
fmax = 250.0
|
fmax = 150.0
|
||||||
qrv = True
|
qrv = True
|
||||||
rxbuffersize = 16
|
rxbuffersize = 16
|
||||||
explorer = False
|
explorer = False
|
||||||
stats = False
|
stats = False
|
||||||
fsk = False
|
fsk = False
|
||||||
tx_delay = 0
|
tx_delay = 800
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ import crcengine
|
||||||
import log_handler
|
import log_handler
|
||||||
import serial.tools.list_ports
|
import serial.tools.list_ports
|
||||||
import sock
|
import sock
|
||||||
import static
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import config
|
import config
|
||||||
|
@ -82,10 +83,10 @@ class DAEMON:
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if not static.TNCSTARTED:
|
if not Daemon.tncstarted:
|
||||||
(
|
(
|
||||||
static.AUDIO_INPUT_DEVICES,
|
AudioParam.audio_input_devices,
|
||||||
static.AUDIO_OUTPUT_DEVICES,
|
AudioParam.audio_output_devices,
|
||||||
) = audio.get_audio_devices()
|
) = audio.get_audio_devices()
|
||||||
except Exception as err1:
|
except Exception as err1:
|
||||||
self.log.error(
|
self.log.error(
|
||||||
|
@ -112,7 +113,7 @@ class DAEMON:
|
||||||
{"port": str(port), "description": str(description)}
|
{"port": str(port), "description": str(description)}
|
||||||
)
|
)
|
||||||
|
|
||||||
static.SERIAL_DEVICES = serial_devices
|
Daemon.serial_devices = serial_devices
|
||||||
threading.Event().wait(1)
|
threading.Event().wait(1)
|
||||||
except Exception as err1:
|
except Exception as err1:
|
||||||
self.log.error(
|
self.log.error(
|
||||||
|
@ -210,10 +211,10 @@ class DAEMON:
|
||||||
self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
self.log.warning("[DMN] Starting TNC", rig=data[5], port=data[6])
|
||||||
|
|
||||||
# list of parameters, necessary for running subprocess command as a list
|
# list of parameters, necessary for running subprocess command as a list
|
||||||
options = ["--port", str(static.DAEMONPORT - 1)]
|
options = ["--port", str(DAEMON.port - 1)]
|
||||||
|
|
||||||
# create an additional list entry for parameters not covered by gui
|
# create an additional list entry for parameters not covered by gui
|
||||||
data[50] = int(static.DAEMONPORT - 1)
|
data[50] = int(DAEMON.port - 1)
|
||||||
|
|
||||||
options.append("--mycall")
|
options.append("--mycall")
|
||||||
options.extend((data[1], "--mygrid"))
|
options.extend((data[1], "--mygrid"))
|
||||||
|
@ -317,8 +318,8 @@ class DAEMON:
|
||||||
|
|
||||||
self.log.info("[DMN] TNC started", path="source")
|
self.log.info("[DMN] TNC started", path="source")
|
||||||
|
|
||||||
static.TNCPROCESS = proc
|
Daemon.tncprocess = proc
|
||||||
static.TNCSTARTED = True
|
Daemon.tncstarted = True
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
mainlog = structlog.get_logger(__file__)
|
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
|
||||||
|
@ -335,7 +336,7 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
ARGS = PARSER.parse_args()
|
ARGS = PARSER.parse_args()
|
||||||
|
|
||||||
static.DAEMONPORT = ARGS.socket_port
|
DAEMON.port = ARGS.socket_port
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.platform == "linux":
|
if sys.platform == "linux":
|
||||||
|
@ -363,11 +364,11 @@ if __name__ == "__main__":
|
||||||
config = config.CONFIG("config.ini")
|
config = config.CONFIG("config.ini")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mainlog.info("[DMN] Starting TCP/IP socket", port=static.DAEMONPORT)
|
mainlog.info("[DMN] Starting TCP/IP socket", port=DAEMON.port)
|
||||||
# https://stackoverflow.com/a/16641793
|
# https://stackoverflow.com/a/16641793
|
||||||
socketserver.TCPServer.allow_reuse_address = True
|
socketserver.TCPServer.allow_reuse_address = True
|
||||||
cmdserver = sock.ThreadedTCPServer(
|
cmdserver = sock.ThreadedTCPServer(
|
||||||
(static.HOST, static.DAEMONPORT), sock.ThreadedTCPRequestHandler
|
(TNC.host, DAEMON.port), sock.ThreadedTCPRequestHandler
|
||||||
)
|
)
|
||||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||||
server_thread.daemon = True
|
server_thread.daemon = True
|
||||||
|
@ -375,7 +376,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
mainlog.error(
|
mainlog.error(
|
||||||
"[DMN] Starting TCP/IP socket failed", port=static.DAEMONPORT, e=err
|
"[DMN] Starting TCP/IP socket failed", port=DAEMON.port, e=err
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
daemon = DAEMON()
|
daemon = DAEMON()
|
||||||
|
@ -384,7 +385,7 @@ if __name__ == "__main__":
|
||||||
"[DMN] Starting FreeDATA Daemon",
|
"[DMN] Starting FreeDATA Daemon",
|
||||||
author="DJ2LS",
|
author="DJ2LS",
|
||||||
year="2023",
|
year="2023",
|
||||||
version=static.VERSION,
|
version=TNC.version,
|
||||||
)
|
)
|
||||||
while True:
|
while True:
|
||||||
threading.Event().wait(1)
|
threading.Event().wait(1)
|
||||||
|
|
1294
tnc/data_handler.py
1294
tnc/data_handler.py
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,8 @@ import time
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import structlog
|
import structlog
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
|
|
||||||
|
|
||||||
log = structlog.get_logger("explorer")
|
log = structlog.get_logger("explorer")
|
||||||
|
|
||||||
|
@ -32,30 +34,31 @@ class explorer():
|
||||||
|
|
||||||
def push(self):
|
def push(self):
|
||||||
|
|
||||||
frequency = 0 if static.HAMLIB_FREQUENCY is None else static.HAMLIB_FREQUENCY
|
frequency = 0 if HamlibParam.hamlib_frequency is None else HamlibParam.hamlib_frequency
|
||||||
band = "USB"
|
band = "USB"
|
||||||
callsign = str(static.MYCALLSIGN, "utf-8")
|
callsign = str(Station.mycallsign, "utf-8")
|
||||||
gridsquare = str(static.MYGRID, "utf-8")
|
gridsquare = str(Station.mygrid, "utf-8")
|
||||||
version = str(static.VERSION)
|
version = str(TNC.version)
|
||||||
bandwidth = str(static.LOW_BANDWIDTH_MODE)
|
bandwidth = str(TNC.low_bandwidth_mode)
|
||||||
beacon = str(static.BEACON_STATE)
|
beacon = str(Beacon.beacon_state)
|
||||||
strength = str(static.HAMLIB_STRENGTH)
|
strength = str(HamlibParam.hamlib_strength)
|
||||||
|
|
||||||
log.info("[EXPLORER] publish", frequency=frequency, band=band, callsign=callsign, gridsquare=gridsquare, version=version, bandwidth=bandwidth)
|
log.info("[EXPLORER] publish", frequency=frequency, band=band, callsign=callsign, gridsquare=gridsquare, version=version, bandwidth=bandwidth)
|
||||||
|
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
station_data = {'callsign': callsign, 'gridsquare': gridsquare, 'frequency': frequency, 'strength': strength, 'band': band, 'version': version, 'bandwidth': bandwidth, 'beacon': beacon, "lastheard": []}
|
station_data = {'callsign': callsign, 'gridsquare': gridsquare, 'frequency': frequency, 'strength': strength, 'band': band, 'version': version, 'bandwidth': bandwidth, 'beacon': beacon, "lastheard": []}
|
||||||
|
|
||||||
for i in static.HEARD_STATIONS:
|
for i in TNC.heard_stations:
|
||||||
try:
|
try:
|
||||||
callsign = str(i[0], "UTF-8")
|
callsign = str(i[0], "UTF-8")
|
||||||
grid = str(i[1], "UTF-8")
|
grid = str(i[1], "UTF-8")
|
||||||
timestamp = i[2]
|
timestamp = i[2]
|
||||||
|
frequency = i[6]
|
||||||
try:
|
try:
|
||||||
snr = i[4].split("/")[1]
|
snr = i[4].split("/")[1]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
snr = str(i[4])
|
snr = str(i[4])
|
||||||
station_data["lastheard"].append({"callsign": callsign, "grid": grid, "snr": snr, "timestamp": timestamp})
|
station_data["lastheard"].append({"callsign": callsign, "grid": grid, "snr": snr, "timestamp": timestamp, "frequency": frequency})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug("[EXPLORER] not publishing station", e=e)
|
log.debug("[EXPLORER] not publishing station", e=e)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import time
|
||||||
from datetime import datetime,timezone
|
from datetime import datetime,timezone
|
||||||
import crcengine
|
import crcengine
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
import structlog
|
import structlog
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import threading
|
import threading
|
||||||
|
@ -130,16 +131,16 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||||
Nothing
|
Nothing
|
||||||
"""
|
"""
|
||||||
# check if buffer empty
|
# check if buffer empty
|
||||||
if len(static.HEARD_STATIONS) == 0:
|
if len(TNC.heard_stations) == 0:
|
||||||
static.HEARD_STATIONS.append(
|
TNC.heard_stations.append(
|
||||||
[dxcallsign, dxgrid, int(datetime.now(timezone.utc).timestamp()), datatype, snr, offset, frequency]
|
[dxcallsign, dxgrid, int(datetime.now(timezone.utc).timestamp()), datatype, snr, offset, frequency]
|
||||||
)
|
)
|
||||||
# if not, we search and update
|
# if not, we search and update
|
||||||
else:
|
else:
|
||||||
for i in range(len(static.HEARD_STATIONS)):
|
for i in range(len(TNC.heard_stations)):
|
||||||
# Update callsign with new timestamp
|
# Update callsign with new timestamp
|
||||||
if static.HEARD_STATIONS[i].count(dxcallsign) > 0:
|
if TNC.heard_stations[i].count(dxcallsign) > 0:
|
||||||
static.HEARD_STATIONS[i] = [
|
TNC.heard_stations[i] = [
|
||||||
dxcallsign,
|
dxcallsign,
|
||||||
dxgrid,
|
dxgrid,
|
||||||
int(time.time()),
|
int(time.time()),
|
||||||
|
@ -150,8 +151,8 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
# Insert if nothing found
|
# Insert if nothing found
|
||||||
if i == len(static.HEARD_STATIONS) - 1:
|
if i == len(TNC.heard_stations) - 1:
|
||||||
static.HEARD_STATIONS.append(
|
TNC.heard_stations.append(
|
||||||
[
|
[
|
||||||
dxcallsign,
|
dxcallsign,
|
||||||
dxgrid,
|
dxgrid,
|
||||||
|
@ -165,10 +166,10 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# for idx, item in enumerate(static.HEARD_STATIONS):
|
# for idx, item in enumerate(TNC.heard_stations):
|
||||||
# if dxcallsign in item:
|
# if dxcallsign in item:
|
||||||
# item = [dxcallsign, int(time.time())]
|
# item = [dxcallsign, int(time.time())]
|
||||||
# static.HEARD_STATIONS[idx] = item
|
# TNC.heard_stations[idx] = item
|
||||||
|
|
||||||
|
|
||||||
def callsign_to_bytes(callsign) -> bytes:
|
def callsign_to_bytes(callsign) -> bytes:
|
||||||
|
@ -305,7 +306,7 @@ def check_callsign(callsign: bytes, crc_to_check: bytes):
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.debug("[HLP] check_callsign: Error callsign SSID to integer:", e=err)
|
log.debug("[HLP] check_callsign: Error callsign SSID to integer:", e=err)
|
||||||
|
|
||||||
for ssid in static.SSID_LIST:
|
for ssid in Station.ssid_list:
|
||||||
call_with_ssid = bytearray(callsign)
|
call_with_ssid = bytearray(callsign)
|
||||||
call_with_ssid.extend("-".encode("utf-8"))
|
call_with_ssid.extend("-".encode("utf-8"))
|
||||||
call_with_ssid.extend(str(ssid).encode("utf-8"))
|
call_with_ssid.extend(str(ssid).encode("utf-8"))
|
||||||
|
|
139
tnc/main.py
139
tnc/main.py
|
@ -29,6 +29,7 @@ import helpers
|
||||||
import log_handler
|
import log_handler
|
||||||
import modem
|
import modem
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
import structlog
|
import structlog
|
||||||
import explorer
|
import explorer
|
||||||
import json
|
import json
|
||||||
|
@ -255,7 +256,7 @@ if __name__ == "__main__":
|
||||||
ARGS = PARSER.parse_args()
|
ARGS = PARSER.parse_args()
|
||||||
|
|
||||||
# set save to folder state for allowing downloading files to local file system
|
# set save to folder state for allowing downloading files to local file system
|
||||||
static.ARQ_SAVE_TO_FOLDER = ARGS.savetofolder
|
ARQ.arq_save_to_folder = ARGS.savetofolder
|
||||||
|
|
||||||
if not ARGS.configfile:
|
if not ARGS.configfile:
|
||||||
|
|
||||||
|
@ -266,46 +267,46 @@ if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
|
mycallsign = bytes(ARGS.mycall.upper(), "utf-8")
|
||||||
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
||||||
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
Station.mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
static.SSID_LIST = ARGS.ssid_list
|
Station.ssid_list = ARGS.ssid_list
|
||||||
# check if own ssid is always part of ssid list
|
# check if own ssid is always part of ssid list
|
||||||
own_ssid = int(static.MYCALLSIGN.split(b"-")[1])
|
own_ssid = int(Station.mycallsign.split(b"-")[1])
|
||||||
if own_ssid not in static.SSID_LIST:
|
if own_ssid not in Station.ssid_list:
|
||||||
static.SSID_LIST.append(own_ssid)
|
Station.ssid_list.append(own_ssid)
|
||||||
|
|
||||||
static.MYGRID = bytes(ARGS.mygrid, "utf-8")
|
Station.mygrid = bytes(ARGS.mygrid, "utf-8")
|
||||||
|
|
||||||
# check if we have an int or str as device name
|
# check if we have an int or str as device name
|
||||||
try:
|
try:
|
||||||
static.AUDIO_INPUT_DEVICE = int(ARGS.audio_input_device)
|
AudioParam.audio_input_device = int(ARGS.audio_input_device)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
static.AUDIO_INPUT_DEVICE = ARGS.audio_input_device
|
AudioParam.audio_input_device = ARGS.audio_input_device
|
||||||
try:
|
try:
|
||||||
static.AUDIO_OUTPUT_DEVICE = int(ARGS.audio_output_device)
|
AudioParam.audio_output_device = int(ARGS.audio_output_device)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
static.AUDIO_OUTPUT_DEVICE = ARGS.audio_output_device
|
AudioParam.audio_output_device = ARGS.audio_output_device
|
||||||
|
|
||||||
static.PORT = ARGS.socket_port
|
TNC.port = ARGS.socket_port
|
||||||
static.HAMLIB_RADIOCONTROL = ARGS.hamlib_radiocontrol
|
HamlibParam.hamlib_radiocontrol = ARGS.hamlib_radiocontrol
|
||||||
static.HAMLIB_RIGCTLD_IP = ARGS.rigctld_ip
|
HamlibParam.hamlib_rigctld_ip = ARGS.rigctld_ip
|
||||||
static.HAMLIB_RIGCTLD_PORT = str(ARGS.rigctld_port)
|
HamlibParam.hamlib_rigctld_port = str(ARGS.rigctld_port)
|
||||||
static.ENABLE_SCATTER = ARGS.send_scatter
|
ModemParam.enable_scatter = ARGS.send_scatter
|
||||||
static.ENABLE_FFT = ARGS.send_fft
|
AudioParam.enable_fft = ARGS.send_fft
|
||||||
static.ENABLE_FSK = ARGS.enable_fsk
|
TNC.enable_fsk = ARGS.enable_fsk
|
||||||
static.LOW_BANDWIDTH_MODE = ARGS.low_bandwidth_mode
|
TNC.low_bandwidth_mode = ARGS.low_bandwidth_mode
|
||||||
static.TUNING_RANGE_FMIN = ARGS.tuning_range_fmin
|
ModemParam.tuning_range_fmin = ARGS.tuning_range_fmin
|
||||||
static.TUNING_RANGE_FMAX = ARGS.tuning_range_fmax
|
ModemParam.tuning_range_fmax = ARGS.tuning_range_fmax
|
||||||
static.TX_AUDIO_LEVEL = ARGS.tx_audio_level
|
AudioParam.tx_audio_level = ARGS.tx_audio_level
|
||||||
static.RESPOND_TO_CQ = ARGS.enable_respond_to_cq
|
TNC.respond_to_cq = ARGS.enable_respond_to_cq
|
||||||
static.RX_BUFFER_SIZE = ARGS.rx_buffer_size
|
ARQ.rx_buffer_size = ARGS.rx_buffer_size
|
||||||
static.ENABLE_EXPLORER = ARGS.enable_explorer
|
TNC.enable_explorer = ARGS.enable_explorer
|
||||||
static.AUDIO_AUTO_TUNE = ARGS.enable_audio_auto_tune
|
AudioParam.audio_auto_tune = ARGS.enable_audio_auto_tune
|
||||||
static.ENABLE_STATS = ARGS.enable_stats
|
TNC.enable_stats = ARGS.enable_stats
|
||||||
static.AUDIO_ENABLE_TCI = ARGS.audio_enable_tci
|
AudioParam.audio_enable_tci = ARGS.audio_enable_tci
|
||||||
static.TCI_IP = ARGS.tci_ip
|
TCIParam.ip = ARGS.tci_ip
|
||||||
static.TCI_PORT = ARGS.tci_port
|
TCIParam.port = ARGS.tci_port
|
||||||
static.TX_DELAY = ARGS.tx_delay
|
ModemParam.tx_delay = ARGS.tx_delay
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error("[DMN] Error reading config file", exception=e)
|
log.error("[DMN] Error reading config file", exception=e)
|
||||||
|
@ -320,52 +321,52 @@ if __name__ == "__main__":
|
||||||
# then we are forcing a station ssid = 0
|
# then we are forcing a station ssid = 0
|
||||||
mycallsign = bytes(conf.get('STATION', 'mycall', 'AA0AA'), "utf-8")
|
mycallsign = bytes(conf.get('STATION', 'mycall', 'AA0AA'), "utf-8")
|
||||||
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
||||||
static.MYCALLSIGN = helpers.bytes_to_callsign(mycallsign)
|
Station.mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
|
|
||||||
#json.loads = for converting str list to list
|
#json.loads = for converting str list to list
|
||||||
static.SSID_LIST = json.loads(conf.get('STATION', 'ssid_list', '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'))
|
Station.ssid_list = json.loads(conf.get('STATION', 'ssid_list', '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'))
|
||||||
|
|
||||||
static.MYGRID = bytes(conf.get('STATION', 'mygrid', 'JN12aa'), "utf-8")
|
Station.mygrid = bytes(conf.get('STATION', 'mygrid', 'JN12aa'), "utf-8")
|
||||||
# check if we have an int or str as device name
|
# check if we have an int or str as device name
|
||||||
try:
|
try:
|
||||||
static.AUDIO_INPUT_DEVICE = int(conf.get('AUDIO', 'rx', '0'))
|
AudioParam.audio_input_device = int(conf.get('AUDIO', 'rx', '0'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
static.AUDIO_INPUT_DEVICE = conf.get('AUDIO', 'rx', '0')
|
AudioParam.audio_input_device = conf.get('AUDIO', 'rx', '0')
|
||||||
try:
|
try:
|
||||||
static.AUDIO_OUTPUT_DEVICE = int(conf.get('AUDIO', 'tx', '0'))
|
AudioParam.audio_output_device = int(conf.get('AUDIO', 'tx', '0'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
static.AUDIO_OUTPUT_DEVICE = conf.get('AUDIO', 'tx', '0')
|
AudioParam.audio_output_device = conf.get('AUDIO', 'tx', '0')
|
||||||
|
|
||||||
static.PORT = int(conf.get('NETWORK', 'tncport', '3000'))
|
TNC.port = int(conf.get('NETWORK', 'tncport', '3000'))
|
||||||
static.HAMLIB_RADIOCONTROL = conf.get('RADIO', 'radiocontrol', 'rigctld')
|
HamlibParam.hamlib_radiocontrol = conf.get('RADIO', 'radiocontrol', 'rigctld')
|
||||||
static.HAMLIB_RIGCTLD_IP = conf.get('RADIO', 'rigctld_ip', '127.0.0.1')
|
HamlibParam.hamlib_rigctld_ip = conf.get('RADIO', 'rigctld_ip', '127.0.0.1')
|
||||||
static.HAMLIB_RIGCTLD_PORT = str(conf.get('RADIO', 'rigctld_port', '4532'))
|
HamlibParam.hamlib_rigctld_port = str(conf.get('RADIO', 'rigctld_port', '4532'))
|
||||||
static.ENABLE_SCATTER = conf.get('TNC', 'scatter', 'True')
|
ModemParam.enable_scatter = conf.get('TNC', 'scatter', 'True')
|
||||||
static.ENABLE_FFT = conf.get('TNC', 'fft', 'True')
|
AudioParam.enable_fft = conf.get('TNC', 'fft', 'True')
|
||||||
static.ENABLE_FSK = conf.get('TNC', 'fsk', 'False')
|
TNC.enable_fsk = conf.get('TNC', 'fsk', 'False')
|
||||||
static.LOW_BANDWIDTH_MODE = conf.get('TNC', 'narrowband', 'False')
|
TNC.low_bandwidth_mode = conf.get('TNC', 'narrowband', 'False')
|
||||||
static.TUNING_RANGE_FMIN = float(conf.get('TNC', 'fmin', '-50.0'))
|
ModemParam.tuning_range_fmin = float(conf.get('TNC', 'fmin', '-50.0'))
|
||||||
static.TUNING_RANGE_FMAX = float(conf.get('TNC', 'fmax', '50.0'))
|
ModemParam.tuning_range_fmax = float(conf.get('TNC', 'fmax', '50.0'))
|
||||||
static.TX_AUDIO_LEVEL = int(conf.get('AUDIO', 'txaudiolevel', '100'))
|
AudioParam.tx_audio_level = int(conf.get('AUDIO', 'txaudiolevel', '100'))
|
||||||
static.RESPOND_TO_CQ = conf.get('TNC', 'qrv', 'True')
|
TNC.respond_to_cq = conf.get('TNC', 'qrv', 'True')
|
||||||
static.RX_BUFFER_SIZE = int(conf.get('TNC', 'rxbuffersize', '16'))
|
ARQ.rx_buffer_size = int(conf.get('TNC', 'rxbuffersize', '16'))
|
||||||
static.ENABLE_EXPLORER = conf.get('TNC', 'explorer', 'False')
|
TNC.enable_explorer = conf.get('TNC', 'explorer', 'False')
|
||||||
static.AUDIO_AUTO_TUNE = conf.get('AUDIO', 'auto_tune', 'False')
|
AudioParam.audio_auto_tune = conf.get('AUDIO', 'auto_tune', 'False')
|
||||||
static.ENABLE_STATS = conf.get('TNC', 'stats', 'False')
|
TNC.enable_stats = conf.get('TNC', 'stats', 'False')
|
||||||
static.AUDIO_ENABLE_TCI = conf.get('AUDIO', 'enable_tci', 'False')
|
AudioParam.audio_enable_tci = conf.get('AUDIO', 'enable_tci', 'False')
|
||||||
static.TCI_IP = str(conf.get('AUDIO', 'tci_ip', 'localhost'))
|
TCIParam.ip = str(conf.get('AUDIO', 'tci_ip', 'localhost'))
|
||||||
static.TCI_PORT = int(conf.get('AUDIO', 'tci_port', '50001'))
|
TCIParam.port = int(conf.get('AUDIO', 'tci_port', '50001'))
|
||||||
static.TX_DELAY = int(conf.get('TNC', 'tx_delay', '0'))
|
ModemParam.tx_delay = int(conf.get('TNC', 'tx_delay', '0'))
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
log.warning("[CFG] Error reading config file near", key=str(e))
|
log.warning("[CFG] Error reading config file near", key=str(e))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning("[CFG] Error", e=e)
|
log.warning("[CFG] Error", e=e)
|
||||||
|
|
||||||
# make sure the own ssid is always part of the ssid list
|
# make sure the own ssid is always part of the ssid list
|
||||||
my_ssid = int(static.MYCALLSIGN.split(b'-')[1])
|
my_ssid = int(Station.mycallsign.split(b'-')[1])
|
||||||
if my_ssid not in static.SSID_LIST:
|
if my_ssid not in Station.ssid_list:
|
||||||
static.SSID_LIST.append(my_ssid)
|
Station.ssid_list.append(my_ssid)
|
||||||
|
|
||||||
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
# we need to wait until we got all parameters from argparse first before we can load the other modules
|
||||||
import sock
|
import sock
|
||||||
|
@ -394,7 +395,7 @@ if __name__ == "__main__":
|
||||||
log.error("[DMN] logger init error", exception=err)
|
log.error("[DMN] logger init error", exception=err)
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"[TNC] Starting FreeDATA", author="DJ2LS", version=static.VERSION
|
"[TNC] Starting FreeDATA", author="DJ2LS", version=TNC.version
|
||||||
)
|
)
|
||||||
|
|
||||||
# start data handler
|
# start data handler
|
||||||
|
@ -404,17 +405,17 @@ if __name__ == "__main__":
|
||||||
modem = modem.RF()
|
modem = modem.RF()
|
||||||
|
|
||||||
# optionally start explorer module
|
# optionally start explorer module
|
||||||
if static.ENABLE_EXPLORER:
|
if TNC.enable_explorer:
|
||||||
log.info("[EXPLORER] Publishing to https://explorer.freedata.app", state=static.ENABLE_EXPLORER)
|
log.info("[EXPLORER] Publishing to https://explorer.freedata.app", state=TNC.enable_explorer)
|
||||||
explorer = explorer.explorer()
|
explorer = explorer.explorer()
|
||||||
|
|
||||||
# --------------------------------------------START CMD SERVER
|
# --------------------------------------------START CMD SERVER
|
||||||
try:
|
try:
|
||||||
log.info("[TNC] Starting TCP/IP socket", port=static.PORT)
|
log.info("[TNC] Starting TCP/IP socket", port=TNC.port)
|
||||||
# https://stackoverflow.com/a/16641793
|
# https://stackoverflow.com/a/16641793
|
||||||
socketserver.TCPServer.allow_reuse_address = True
|
socketserver.TCPServer.allow_reuse_address = True
|
||||||
cmdserver = sock.ThreadedTCPServer(
|
cmdserver = sock.ThreadedTCPServer(
|
||||||
(static.HOST, static.PORT), sock.ThreadedTCPRequestHandler
|
(TNC.host, TNC.port), sock.ThreadedTCPRequestHandler
|
||||||
)
|
)
|
||||||
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
server_thread = threading.Thread(target=cmdserver.serve_forever)
|
||||||
|
|
||||||
|
@ -422,7 +423,7 @@ if __name__ == "__main__":
|
||||||
server_thread.start()
|
server_thread.start()
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.error("[TNC] Starting TCP/IP socket failed", port=static.PORT, e=err)
|
log.error("[TNC] Starting TCP/IP socket failed", port=TNC.port, e=err)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
while True:
|
while True:
|
||||||
threading.Event().wait(1)
|
threading.Event().wait(1)
|
493
tnc/modem.py
493
tnc/modem.py
|
@ -23,6 +23,8 @@ import numpy as np
|
||||||
import sock
|
import sock
|
||||||
import sounddevice as sd
|
import sounddevice as sd
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
|
from static import FRAME_TYPE
|
||||||
import structlog
|
import structlog
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import tci
|
import tci
|
||||||
|
@ -33,19 +35,24 @@ TESTMODE = False
|
||||||
RXCHANNEL = ""
|
RXCHANNEL = ""
|
||||||
TXCHANNEL = ""
|
TXCHANNEL = ""
|
||||||
|
|
||||||
static.TRANSMITTING = False
|
TNC.transmitting = False
|
||||||
|
|
||||||
# Receive only specific modes to reduce CPU load
|
# Receive only specific modes to reduce CPU load
|
||||||
RECEIVE_SIG0 = True
|
RECEIVE_SIG0 = True
|
||||||
RECEIVE_SIG1 = False
|
RECEIVE_SIG1 = False
|
||||||
RECEIVE_DATAC1 = False
|
RECEIVE_DATAC1 = False
|
||||||
RECEIVE_DATAC3 = False
|
RECEIVE_DATAC3 = False
|
||||||
|
RECEIVE_DATAC4 = False
|
||||||
|
|
||||||
|
|
||||||
# state buffer
|
# state buffer
|
||||||
SIG0_DATAC0_STATE = []
|
|
||||||
SIG1_DATAC0_STATE = []
|
SIG0_DATAC13_STATE = []
|
||||||
|
SIG1_DATAC13_STATE = []
|
||||||
DAT0_DATAC1_STATE = []
|
DAT0_DATAC1_STATE = []
|
||||||
DAT0_DATAC3_STATE = []
|
DAT0_DATAC3_STATE = []
|
||||||
|
DAT0_DATAC4_STATE = []
|
||||||
|
|
||||||
FSK_LDPC0_STATE = []
|
FSK_LDPC0_STATE = []
|
||||||
FSK_LDPC1_STATE = []
|
FSK_LDPC1_STATE = []
|
||||||
|
|
||||||
|
@ -66,7 +73,7 @@ class RF:
|
||||||
|
|
||||||
self.AUDIO_FRAMES_PER_BUFFER_RX = 2400 * 2 # 8192
|
self.AUDIO_FRAMES_PER_BUFFER_RX = 2400 * 2 # 8192
|
||||||
# 8192 Let's do some tests with very small chunks for TX
|
# 8192 Let's do some tests with very small chunks for TX
|
||||||
self.AUDIO_FRAMES_PER_BUFFER_TX = 1200 if static.AUDIO_ENABLE_TCI else 2400 * 2
|
self.AUDIO_FRAMES_PER_BUFFER_TX = 1200 if AudioParam.audio_enable_tci else 2400 * 2
|
||||||
# 8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) == 48
|
# 8 * (self.AUDIO_SAMPLE_RATE_RX/self.MODEM_SAMPLE_RATE) == 48
|
||||||
self.AUDIO_CHANNELS = 1
|
self.AUDIO_CHANNELS = 1
|
||||||
self.MODE = 0
|
self.MODE = 0
|
||||||
|
@ -79,9 +86,7 @@ class RF:
|
||||||
# Make sure our resampler will work
|
# Make sure our resampler will work
|
||||||
assert (self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48 # type: ignore
|
assert (self.AUDIO_SAMPLE_RATE_RX / self.MODEM_SAMPLE_RATE) == codec2.api.FDMDV_OS_48 # type: ignore
|
||||||
|
|
||||||
# Small hack for initializing codec2 via codec2.py module
|
# init codec2 resampler
|
||||||
# TODO: Need to change the entire modem module to integrate codec2 module
|
|
||||||
self.c_lib = codec2.api
|
|
||||||
self.resampler = codec2.resampler()
|
self.resampler = codec2.resampler()
|
||||||
|
|
||||||
self.modem_transmit_queue = MODEM_TRANSMIT_QUEUE
|
self.modem_transmit_queue = MODEM_TRANSMIT_QUEUE
|
||||||
|
@ -98,23 +103,23 @@ class RF:
|
||||||
|
|
||||||
# Open codec2 instances
|
# Open codec2 instances
|
||||||
|
|
||||||
# DATAC0
|
# DATAC13
|
||||||
# SIGNALLING MODE 0 - Used for Connecting - Payload 14 Bytes
|
# SIGNALLING MODE 0 - Used for Connecting - Payload 14 Bytes
|
||||||
self.sig0_datac0_freedv, \
|
self.sig0_datac13_freedv, \
|
||||||
self.sig0_datac0_bytes_per_frame, \
|
self.sig0_datac13_bytes_per_frame, \
|
||||||
self.sig0_datac0_bytes_out, \
|
self.sig0_datac13_bytes_out, \
|
||||||
self.sig0_datac0_buffer, \
|
self.sig0_datac13_buffer, \
|
||||||
self.sig0_datac0_nin = \
|
self.sig0_datac13_nin = \
|
||||||
self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC0, None)
|
self.init_codec2_mode(codec2.FREEDV_MODE.datac13.value, None)
|
||||||
|
|
||||||
# DATAC0
|
# DATAC13
|
||||||
# SIGNALLING MODE 1 - Used for ACK/NACK - Payload 5 Bytes
|
# SIGNALLING MODE 1 - Used for ACK/NACK - Payload 5 Bytes
|
||||||
self.sig1_datac0_freedv, \
|
self.sig1_datac13_freedv, \
|
||||||
self.sig1_datac0_bytes_per_frame, \
|
self.sig1_datac13_bytes_per_frame, \
|
||||||
self.sig1_datac0_bytes_out, \
|
self.sig1_datac13_bytes_out, \
|
||||||
self.sig1_datac0_buffer, \
|
self.sig1_datac13_buffer, \
|
||||||
self.sig1_datac0_nin = \
|
self.sig1_datac13_nin = \
|
||||||
self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC0, None)
|
self.init_codec2_mode(codec2.FREEDV_MODE.datac13.value, None)
|
||||||
|
|
||||||
# DATAC1
|
# DATAC1
|
||||||
self.dat0_datac1_freedv, \
|
self.dat0_datac1_freedv, \
|
||||||
|
@ -122,7 +127,7 @@ class RF:
|
||||||
self.dat0_datac1_bytes_out, \
|
self.dat0_datac1_bytes_out, \
|
||||||
self.dat0_datac1_buffer, \
|
self.dat0_datac1_buffer, \
|
||||||
self.dat0_datac1_nin = \
|
self.dat0_datac1_nin = \
|
||||||
self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC1, None)
|
self.init_codec2_mode(codec2.FREEDV_MODE.datac1.value, None)
|
||||||
|
|
||||||
# DATAC3
|
# DATAC3
|
||||||
self.dat0_datac3_freedv, \
|
self.dat0_datac3_freedv, \
|
||||||
|
@ -130,7 +135,16 @@ class RF:
|
||||||
self.dat0_datac3_bytes_out, \
|
self.dat0_datac3_bytes_out, \
|
||||||
self.dat0_datac3_buffer, \
|
self.dat0_datac3_buffer, \
|
||||||
self.dat0_datac3_nin = \
|
self.dat0_datac3_nin = \
|
||||||
self.init_codec2_mode(codec2.api.FREEDV_MODE_DATAC3, None)
|
self.init_codec2_mode(codec2.FREEDV_MODE.datac3.value, None)
|
||||||
|
|
||||||
|
# DATAC4
|
||||||
|
self.dat0_datac4_freedv, \
|
||||||
|
self.dat0_datac4_bytes_per_frame, \
|
||||||
|
self.dat0_datac4_bytes_out, \
|
||||||
|
self.dat0_datac4_buffer, \
|
||||||
|
self.dat0_datac4_nin = \
|
||||||
|
self.init_codec2_mode(codec2.FREEDV_MODE.datac4.value, None)
|
||||||
|
|
||||||
|
|
||||||
# FSK LDPC - 0
|
# FSK LDPC - 0
|
||||||
self.fsk_ldpc_freedv_0, \
|
self.fsk_ldpc_freedv_0, \
|
||||||
|
@ -139,7 +153,7 @@ class RF:
|
||||||
self.fsk_ldpc_buffer_0, \
|
self.fsk_ldpc_buffer_0, \
|
||||||
self.fsk_ldpc_nin_0 = \
|
self.fsk_ldpc_nin_0 = \
|
||||||
self.init_codec2_mode(
|
self.init_codec2_mode(
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC,
|
codec2.FREEDV_MODE.fsk_ldpc.value,
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV
|
codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -150,24 +164,27 @@ class RF:
|
||||||
self.fsk_ldpc_buffer_1, \
|
self.fsk_ldpc_buffer_1, \
|
||||||
self.fsk_ldpc_nin_1 = \
|
self.fsk_ldpc_nin_1 = \
|
||||||
self.init_codec2_mode(
|
self.init_codec2_mode(
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC,
|
codec2.FREEDV_MODE.fsk_ldpc.value,
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV
|
codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV
|
||||||
)
|
)
|
||||||
|
|
||||||
# INIT TX MODES
|
# INIT TX MODES - here we need all modes.
|
||||||
self.freedv_datac0_tx = open_codec2_instance(14)
|
self.freedv_datac0_tx = open_codec2_instance(codec2.FREEDV_MODE.datac0.value)
|
||||||
self.freedv_datac1_tx = open_codec2_instance(10)
|
self.freedv_datac1_tx = open_codec2_instance(codec2.FREEDV_MODE.datac1.value)
|
||||||
self.freedv_datac3_tx = open_codec2_instance(12)
|
self.freedv_datac3_tx = open_codec2_instance(codec2.FREEDV_MODE.datac3.value)
|
||||||
self.freedv_ldpc0_tx = open_codec2_instance(200)
|
self.freedv_datac4_tx = open_codec2_instance(codec2.FREEDV_MODE.datac4.value)
|
||||||
self.freedv_ldpc1_tx = open_codec2_instance(201)
|
self.freedv_datac13_tx = open_codec2_instance(codec2.FREEDV_MODE.datac13.value)
|
||||||
# --------------------------------------------CREATE PYAUDIO INSTANCE
|
self.freedv_ldpc0_tx = open_codec2_instance(codec2.FREEDV_MODE.fsk_ldpc_0.value)
|
||||||
if not TESTMODE and not static.AUDIO_ENABLE_TCI:
|
self.freedv_ldpc1_tx = open_codec2_instance(codec2.FREEDV_MODE.fsk_ldpc_1.value)
|
||||||
|
|
||||||
|
# --------------------------------------------CREATE PORTAUDIO INSTANCE
|
||||||
|
if not TESTMODE and not AudioParam.audio_enable_tci:
|
||||||
try:
|
try:
|
||||||
self.stream = sd.RawStream(
|
self.stream = sd.RawStream(
|
||||||
channels=1,
|
channels=1,
|
||||||
dtype="int16",
|
dtype="int16",
|
||||||
callback=self.callback,
|
callback=self.callback,
|
||||||
device=(static.AUDIO_INPUT_DEVICE, static.AUDIO_OUTPUT_DEVICE),
|
device=(AudioParam.audio_input_device, AudioParam.audio_output_device),
|
||||||
samplerate=self.AUDIO_SAMPLE_RATE_RX,
|
samplerate=self.AUDIO_SAMPLE_RATE_RX,
|
||||||
blocksize=4800,
|
blocksize=4800,
|
||||||
)
|
)
|
||||||
|
@ -179,7 +196,7 @@ class RF:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.log.debug("[MDM] init: starting pyaudio callback")
|
self.log.debug("[MDM] init: starting pyaudio callback")
|
||||||
# self.audio_stream.start_stream()
|
# self.audio_stream.start_stream(
|
||||||
self.stream.start()
|
self.stream.start()
|
||||||
except Exception as err:
|
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)
|
||||||
|
@ -187,7 +204,7 @@ class RF:
|
||||||
elif not TESTMODE:
|
elif not TESTMODE:
|
||||||
# placeholder area for processing audio via TCI
|
# placeholder area for processing audio via TCI
|
||||||
# https://github.com/maksimus1210/TCI
|
# https://github.com/maksimus1210/TCI
|
||||||
self.log.warning("[MDM] [TCI] Not yet fully implemented", ip=static.TCI_IP, port=static.TCI_PORT)
|
self.log.warning("[MDM] [TCI] Not yet fully implemented", ip=TCIParam.tci_ip, port=TCIParam.tci_port)
|
||||||
|
|
||||||
# we are trying this by simulating an audio stream Object like with mkfifo
|
# we are trying this by simulating an audio stream Object like with mkfifo
|
||||||
class Object:
|
class Object:
|
||||||
|
@ -197,7 +214,7 @@ class RF:
|
||||||
self.stream = Object()
|
self.stream = Object()
|
||||||
|
|
||||||
# lets init TCI module
|
# lets init TCI module
|
||||||
self.tci_module = tci.TCI()
|
self.tci_module = tci.TCICtrl()
|
||||||
|
|
||||||
tci_rx_callback_thread = threading.Thread(
|
tci_rx_callback_thread = threading.Thread(
|
||||||
target=self.tci_rx_callback,
|
target=self.tci_rx_callback,
|
||||||
|
@ -247,35 +264,28 @@ class RF:
|
||||||
|
|
||||||
# --------------------------------------------INIT AND OPEN HAMLIB
|
# --------------------------------------------INIT AND OPEN HAMLIB
|
||||||
# Check how we want to control the radio
|
# Check how we want to control the radio
|
||||||
# TODO: deprecated feature - we can remove this possibly
|
if HamlibParam.hamlib_radiocontrol == "rigctld":
|
||||||
if static.HAMLIB_RADIOCONTROL == "direct":
|
|
||||||
print("direct hamlib support deprecated - not usable anymore")
|
|
||||||
sys.exit(1)
|
|
||||||
elif static.HAMLIB_RADIOCONTROL == "rigctl":
|
|
||||||
print("rigctl support deprecated - not usable anymore")
|
|
||||||
sys.exit(1)
|
|
||||||
elif static.HAMLIB_RADIOCONTROL == "rigctld":
|
|
||||||
import rigctld as rig
|
import rigctld as rig
|
||||||
elif static.AUDIO_ENABLE_TCI:
|
elif AudioParam.audio_enable_tci:
|
||||||
self.radio = self.tci_module
|
self.radio = self.tci_module
|
||||||
else:
|
else:
|
||||||
import rigdummy as rig
|
import rigdummy as rig
|
||||||
|
|
||||||
if not static.AUDIO_ENABLE_TCI:
|
if not AudioParam.audio_enable_tci:
|
||||||
self.radio = rig.radio()
|
self.radio = rig.radio()
|
||||||
self.radio.open_rig(
|
self.radio.open_rig(
|
||||||
rigctld_ip=static.HAMLIB_RIGCTLD_IP,
|
rigctld_ip=HamlibParam.hamlib_rigctld_ip,
|
||||||
rigctld_port=static.HAMLIB_RIGCTLD_PORT,
|
rigctld_port=HamlibParam.hamlib_rigctld_port,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --------------------------------------------START DECODER THREAD
|
# --------------------------------------------START DECODER THREAD
|
||||||
if static.ENABLE_FFT:
|
if AudioParam.enable_fft:
|
||||||
fft_thread = threading.Thread(
|
fft_thread = threading.Thread(
|
||||||
target=self.calculate_fft, name="FFT_THREAD", daemon=True
|
target=self.calculate_fft, name="FFT_THREAD", daemon=True
|
||||||
)
|
)
|
||||||
fft_thread.start()
|
fft_thread.start()
|
||||||
|
|
||||||
if static.ENABLE_FSK:
|
if TNC.enable_fsk:
|
||||||
audio_thread_fsk_ldpc0 = threading.Thread(
|
audio_thread_fsk_ldpc0 = threading.Thread(
|
||||||
target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0", daemon=True
|
target=self.audio_fsk_ldpc_0, name="AUDIO_THREAD FSK LDPC0", daemon=True
|
||||||
)
|
)
|
||||||
|
@ -287,15 +297,15 @@ class RF:
|
||||||
audio_thread_fsk_ldpc1.start()
|
audio_thread_fsk_ldpc1.start()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
audio_thread_sig0_datac0 = threading.Thread(
|
audio_thread_sig0_datac13 = threading.Thread(
|
||||||
target=self.audio_sig0_datac0, name="AUDIO_THREAD DATAC0 - 0", daemon=True
|
target=self.audio_sig0_datac13, name="AUDIO_THREAD DATAC13 - 0", daemon=True
|
||||||
)
|
)
|
||||||
audio_thread_sig0_datac0.start()
|
audio_thread_sig0_datac13.start()
|
||||||
|
|
||||||
audio_thread_sig1_datac0 = threading.Thread(
|
audio_thread_sig1_datac13 = threading.Thread(
|
||||||
target=self.audio_sig1_datac0, name="AUDIO_THREAD DATAC0 - 1", daemon=True
|
target=self.audio_sig1_datac13, name="AUDIO_THREAD DATAC13 - 1", daemon=True
|
||||||
)
|
)
|
||||||
audio_thread_sig1_datac0.start()
|
audio_thread_sig1_datac13.start()
|
||||||
|
|
||||||
audio_thread_dat0_datac1 = threading.Thread(
|
audio_thread_dat0_datac1 = threading.Thread(
|
||||||
target=self.audio_dat0_datac1, name="AUDIO_THREAD DATAC1", daemon=True
|
target=self.audio_dat0_datac1, name="AUDIO_THREAD DATAC1", daemon=True
|
||||||
|
@ -307,6 +317,11 @@ class RF:
|
||||||
)
|
)
|
||||||
audio_thread_dat0_datac3.start()
|
audio_thread_dat0_datac3.start()
|
||||||
|
|
||||||
|
audio_thread_dat0_datac4 = threading.Thread(
|
||||||
|
target=self.audio_dat0_datac4, name="AUDIO_THREAD DATAC4", daemon=True
|
||||||
|
)
|
||||||
|
audio_thread_dat0_datac4.start()
|
||||||
|
|
||||||
hamlib_thread = threading.Thread(
|
hamlib_thread = threading.Thread(
|
||||||
target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True
|
target=self.update_rig_data, name="HAMLIB_THREAD", daemon=True
|
||||||
)
|
)
|
||||||
|
@ -337,7 +352,7 @@ class RF:
|
||||||
threading.Event().wait(0.01)
|
threading.Event().wait(0.01)
|
||||||
|
|
||||||
if len(self.modoutqueue) > 0 and not self.mod_out_locked:
|
if len(self.modoutqueue) > 0 and not self.mod_out_locked:
|
||||||
static.PTT_STATE = self.radio.set_ptt(True)
|
HamlibParam.ptt_state = self.radio.set_ptt(True)
|
||||||
jsondata = {"ptt": "True"}
|
jsondata = {"ptt": "True"}
|
||||||
data_out = json.dumps(jsondata)
|
data_out = json.dumps(jsondata)
|
||||||
sock.SOCKET_QUEUE.put(data_out)
|
sock.SOCKET_QUEUE.put(data_out)
|
||||||
|
@ -364,12 +379,13 @@ class RF:
|
||||||
|
|
||||||
length_x = len(x)
|
length_x = len(x)
|
||||||
for data_buffer, receive in [
|
for data_buffer, receive in [
|
||||||
(self.sig0_datac0_buffer, RECEIVE_SIG0),
|
(self.sig0_datac13_buffer, RECEIVE_SIG0),
|
||||||
(self.sig1_datac0_buffer, RECEIVE_SIG1),
|
(self.sig1_datac13_buffer, RECEIVE_SIG1),
|
||||||
(self.dat0_datac1_buffer, RECEIVE_DATAC1),
|
(self.dat0_datac1_buffer, RECEIVE_DATAC1),
|
||||||
(self.dat0_datac3_buffer, RECEIVE_DATAC3),
|
(self.dat0_datac3_buffer, RECEIVE_DATAC3),
|
||||||
(self.fsk_ldpc_buffer_0, static.ENABLE_FSK),
|
(self.dat0_datac4_buffer, RECEIVE_DATAC4),
|
||||||
(self.fsk_ldpc_buffer_1, static.ENABLE_FSK),
|
(self.fsk_ldpc_buffer_0, TNC.enable_fsk),
|
||||||
|
(self.fsk_ldpc_buffer_1, TNC.enable_fsk),
|
||||||
]:
|
]:
|
||||||
if (
|
if (
|
||||||
not (data_buffer.nbuffer + length_x) > data_buffer.size
|
not (data_buffer.nbuffer + length_x) > data_buffer.size
|
||||||
|
@ -397,12 +413,13 @@ class RF:
|
||||||
|
|
||||||
length_x = len(x)
|
length_x = len(x)
|
||||||
for data_buffer, receive in [
|
for data_buffer, receive in [
|
||||||
(self.sig0_datac0_buffer, RECEIVE_SIG0),
|
(self.sig0_datac13_buffer, RECEIVE_SIG0),
|
||||||
(self.sig1_datac0_buffer, RECEIVE_SIG1),
|
(self.sig1_datac13_buffer, RECEIVE_SIG1),
|
||||||
(self.dat0_datac1_buffer, RECEIVE_DATAC1),
|
(self.dat0_datac1_buffer, RECEIVE_DATAC1),
|
||||||
(self.dat0_datac3_buffer, RECEIVE_DATAC3),
|
(self.dat0_datac3_buffer, RECEIVE_DATAC3),
|
||||||
(self.fsk_ldpc_buffer_0, static.ENABLE_FSK),
|
(self.dat0_datac4_buffer, RECEIVE_DATAC4),
|
||||||
(self.fsk_ldpc_buffer_1, static.ENABLE_FSK),
|
(self.fsk_ldpc_buffer_0, TNC.enable_fsk),
|
||||||
|
(self.fsk_ldpc_buffer_1, TNC.enable_fsk),
|
||||||
]:
|
]:
|
||||||
if (
|
if (
|
||||||
not (data_buffer.nbuffer + length_x) > data_buffer.size
|
not (data_buffer.nbuffer + length_x) > data_buffer.size
|
||||||
|
@ -443,38 +460,39 @@ class RF:
|
||||||
x = self.resampler.resample48_to_8(x)
|
x = self.resampler.resample48_to_8(x)
|
||||||
|
|
||||||
# audio recording for debugging purposes
|
# audio recording for debugging purposes
|
||||||
if static.AUDIO_RECORD:
|
if AudioParam.audio_record:
|
||||||
# static.AUDIO_RECORD_FILE.write(x)
|
# AudioParam.audio_record_file.write(x)
|
||||||
static.AUDIO_RECORD_FILE.writeframes(x)
|
AudioParam.audio_record_file.writeframes(x)
|
||||||
|
|
||||||
# Avoid decoding when transmitting to reduce CPU
|
# Avoid decoding when transmitting to reduce CPU
|
||||||
# TODO: Overriding this for testing purposes
|
# TODO: Overriding this for testing purposes
|
||||||
# if not static.TRANSMITTING:
|
# if not TNC.transmitting:
|
||||||
length_x = len(x)
|
length_x = len(x)
|
||||||
# Avoid buffer overflow by filling only if buffer for
|
# Avoid buffer overflow by filling only if buffer for
|
||||||
# selected datachannel mode is not full
|
# selected datachannel mode is not full
|
||||||
for audiobuffer, receive, index in [
|
for audiobuffer, receive, index in [
|
||||||
(self.sig0_datac0_buffer, RECEIVE_SIG0, 0),
|
(self.sig0_datac13_buffer, RECEIVE_SIG0, 0),
|
||||||
(self.sig1_datac0_buffer, RECEIVE_SIG1, 1),
|
(self.sig1_datac13_buffer, RECEIVE_SIG1, 1),
|
||||||
(self.dat0_datac1_buffer, RECEIVE_DATAC1, 2),
|
(self.dat0_datac1_buffer, RECEIVE_DATAC1, 2),
|
||||||
(self.dat0_datac3_buffer, RECEIVE_DATAC3, 3),
|
(self.dat0_datac3_buffer, RECEIVE_DATAC3, 3),
|
||||||
(self.fsk_ldpc_buffer_0, static.ENABLE_FSK, 4),
|
(self.dat0_datac4_buffer, RECEIVE_DATAC4, 4),
|
||||||
(self.fsk_ldpc_buffer_1, static.ENABLE_FSK, 5),
|
(self.fsk_ldpc_buffer_0, TNC.enable_fsk, 5),
|
||||||
|
(self.fsk_ldpc_buffer_1, TNC.enable_fsk, 6),
|
||||||
]:
|
]:
|
||||||
if (audiobuffer.nbuffer + length_x) > audiobuffer.size:
|
if (audiobuffer.nbuffer + length_x) > audiobuffer.size:
|
||||||
static.BUFFER_OVERFLOW_COUNTER[index] += 1
|
AudioParam.buffer_overflow_counter[index] += 1
|
||||||
elif receive:
|
elif receive:
|
||||||
audiobuffer.push(x)
|
audiobuffer.push(x)
|
||||||
# end of "not static.TRANSMITTING" if block
|
# end of "not TNC.transmitting" if block
|
||||||
|
|
||||||
if not self.modoutqueue or self.mod_out_locked:
|
if not self.modoutqueue or self.mod_out_locked:
|
||||||
data_out48k = np.zeros(frames, dtype=np.int16)
|
data_out48k = np.zeros(frames, dtype=np.int16)
|
||||||
self.fft_data = x
|
self.fft_data = x
|
||||||
else:
|
else:
|
||||||
if not static.PTT_STATE:
|
if not HamlibParam.ptt_state:
|
||||||
# TODO: Moved to this place for testing
|
# TODO: Moved to this place for testing
|
||||||
# Maybe we can avoid moments of silence before transmitting
|
# Maybe we can avoid moments of silence before transmitting
|
||||||
static.PTT_STATE = self.radio.set_ptt(True)
|
HamlibParam.ptt_state = self.radio.set_ptt(True)
|
||||||
jsondata = {"ptt": "True"}
|
jsondata = {"ptt": "True"}
|
||||||
data_out = json.dumps(jsondata)
|
data_out = json.dumps(jsondata)
|
||||||
sock.SOCKET_QUEUE.put(data_out)
|
sock.SOCKET_QUEUE.put(data_out)
|
||||||
|
@ -502,38 +520,33 @@ class RF:
|
||||||
frames:
|
frames:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
self.reset_data_sync()
|
||||||
|
|
||||||
"""
|
if mode == codec2.FREEDV_MODE.datac0.value:
|
||||||
sig0 = 14
|
|
||||||
sig1 = 14
|
|
||||||
datac0 = 14
|
|
||||||
datac1 = 10
|
|
||||||
datac3 = 12
|
|
||||||
fsk_ldpc = 9
|
|
||||||
fsk_ldpc_0 = 200
|
|
||||||
fsk_ldpc_1 = 201
|
|
||||||
"""
|
|
||||||
if mode == 14:
|
|
||||||
freedv = self.freedv_datac0_tx
|
freedv = self.freedv_datac0_tx
|
||||||
elif mode == 10:
|
elif mode == codec2.FREEDV_MODE.datac1.value:
|
||||||
freedv = self.freedv_datac1_tx
|
freedv = self.freedv_datac1_tx
|
||||||
elif mode == 12:
|
elif mode == codec2.FREEDV_MODE.datac3.value:
|
||||||
freedv = self.freedv_datac3_tx
|
freedv = self.freedv_datac3_tx
|
||||||
elif mode == 200:
|
elif mode == codec2.FREEDV_MODE.datac4.value:
|
||||||
|
freedv = self.freedv_datac4_tx
|
||||||
|
elif mode == codec2.FREEDV_MODE.datac13.value:
|
||||||
|
freedv = self.freedv_datac13_tx
|
||||||
|
elif mode == codec2.FREEDV_MODE.fsk_ldpc_0.value:
|
||||||
freedv = self.freedv_ldpc0_tx
|
freedv = self.freedv_ldpc0_tx
|
||||||
elif mode == 201:
|
elif mode == codec2.FREEDV_MODE.fsk_ldpc_1.value:
|
||||||
freedv = self.freedv_ldpc1_tx
|
freedv = self.freedv_ldpc1_tx
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
static.TRANSMITTING = True
|
TNC.transmitting = True
|
||||||
# if we're transmitting FreeDATA signals, reset channel busy state
|
# if we're transmitting FreeDATA signals, reset channel busy state
|
||||||
static.CHANNEL_BUSY = False
|
ModemParam.channel_busy = False
|
||||||
|
|
||||||
start_of_transmission = time.time()
|
start_of_transmission = time.time()
|
||||||
# TODO: Moved ptt toggle some steps before audio is ready for testing
|
# TODO: Moved ptt toggle some steps before audio is ready for testing
|
||||||
# Toggle ptt early to save some time and send ptt state via socket
|
# Toggle ptt early to save some time and send ptt state via socket
|
||||||
# static.PTT_STATE = self.radio.set_ptt(True)
|
# HamlibParam.ptt_state = self.radio.set_ptt(True)
|
||||||
# jsondata = {"ptt": "True"}
|
# jsondata = {"ptt": "True"}
|
||||||
# data_out = json.dumps(jsondata)
|
# data_out = json.dumps(jsondata)
|
||||||
# sock.SOCKET_QUEUE.put(data_out)
|
# sock.SOCKET_QUEUE.put(data_out)
|
||||||
|
@ -564,18 +577,22 @@ class RF:
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add empty data to handle ptt toggle time
|
# Add empty data to handle ptt toggle time
|
||||||
if static.TX_DELAY > 0:
|
if ModemParam.tx_delay > 0:
|
||||||
data_delay = int(self.MODEM_SAMPLE_RATE * (static.TX_DELAY / 1000)) # type: ignore
|
data_delay = int(self.MODEM_SAMPLE_RATE * (ModemParam.tx_delay / 1000)) # type: ignore
|
||||||
mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
|
mod_out_silence = ctypes.create_string_buffer(data_delay * 2)
|
||||||
txbuffer = bytes(mod_out_silence)
|
txbuffer = bytes(mod_out_silence)
|
||||||
else:
|
else:
|
||||||
txbuffer = bytes()
|
txbuffer = bytes()
|
||||||
|
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame, delay=static.TX_DELAY
|
"[MDM] TRANSMIT", mode=self.MODE, payload=payload_bytes_per_frame, delay=ModemParam.tx_delay
|
||||||
)
|
)
|
||||||
|
|
||||||
for _ in range(repeats):
|
for _ in range(repeats):
|
||||||
|
|
||||||
|
# Create modulation for all frames in the list
|
||||||
|
for frame in frames:
|
||||||
|
# Write preamble to txbuffer
|
||||||
# codec2 fsk preamble may be broken -
|
# codec2 fsk preamble may be broken -
|
||||||
# at least it sounds like that, so we are disabling it for testing
|
# at least it sounds like that, so we are disabling it for testing
|
||||||
if self.MODE not in [
|
if self.MODE not in [
|
||||||
|
@ -586,8 +603,6 @@ class RF:
|
||||||
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||||
txbuffer += bytes(mod_out_preamble)
|
txbuffer += bytes(mod_out_preamble)
|
||||||
|
|
||||||
# Create modulaton for all frames in the list
|
|
||||||
for frame in frames:
|
|
||||||
# Create buffer for data
|
# Create buffer for data
|
||||||
# Use this if CRC16 checksum is required (DATAc1-3)
|
# Use this if CRC16 checksum is required (DATAc1-3)
|
||||||
buffer = bytearray(payload_bytes_per_frame)
|
buffer = bytearray(payload_bytes_per_frame)
|
||||||
|
@ -631,35 +646,35 @@ class RF:
|
||||||
x = np.frombuffer(txbuffer, dtype=np.int16)
|
x = np.frombuffer(txbuffer, dtype=np.int16)
|
||||||
|
|
||||||
# enable / disable AUDIO TUNE Feature / ALC correction
|
# enable / disable AUDIO TUNE Feature / ALC correction
|
||||||
if static.AUDIO_AUTO_TUNE:
|
if AudioParam.audio_auto_tune:
|
||||||
if static.HAMLIB_ALC == 0.0:
|
if HamlibParam.alc == 0.0:
|
||||||
static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + 20
|
AudioParam.tx_audio_level = AudioParam.tx_audio_level + 20
|
||||||
elif 0.0 < static.HAMLIB_ALC <= 0.1:
|
elif 0.0 < HamlibParam.alc <= 0.1:
|
||||||
print("0.0 < static.HAMLIB_ALC <= 0.1")
|
print("0.0 < HamlibParam.alc <= 0.1")
|
||||||
static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL + 2
|
AudioParam.tx_audio_level = AudioParam.tx_audio_level + 2
|
||||||
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL),
|
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(AudioParam.tx_audio_level),
|
||||||
alc_level=str(static.HAMLIB_ALC))
|
alc_level=str(HamlibParam.alc))
|
||||||
elif 0.1 < static.HAMLIB_ALC < 0.2:
|
elif 0.1 < HamlibParam.alc < 0.2:
|
||||||
print("0.1 < static.HAMLIB_ALC < 0.2")
|
print("0.1 < HamlibParam.alc < 0.2")
|
||||||
static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL
|
AudioParam.tx_audio_level = AudioParam.tx_audio_level
|
||||||
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL),
|
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(AudioParam.tx_audio_level),
|
||||||
alc_level=str(static.HAMLIB_ALC))
|
alc_level=str(HamlibParam.alc))
|
||||||
elif 0.2 < static.HAMLIB_ALC < 0.99:
|
elif 0.2 < HamlibParam.alc < 0.99:
|
||||||
print("0.2 < static.HAMLIB_ALC < 0.99")
|
print("0.2 < HamlibParam.alc < 0.99")
|
||||||
static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 20
|
AudioParam.tx_audio_level = AudioParam.tx_audio_level - 20
|
||||||
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL),
|
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(AudioParam.tx_audio_level),
|
||||||
alc_level=str(static.HAMLIB_ALC))
|
alc_level=str(HamlibParam.alc))
|
||||||
elif 1.0 >= static.HAMLIB_ALC:
|
elif 1.0 >= HamlibParam.alc:
|
||||||
print("1.0 >= static.HAMLIB_ALC")
|
print("1.0 >= HamlibParam.alc")
|
||||||
static.TX_AUDIO_LEVEL = static.TX_AUDIO_LEVEL - 40
|
AudioParam.tx_audio_level = AudioParam.tx_audio_level - 40
|
||||||
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL),
|
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(AudioParam.tx_audio_level),
|
||||||
alc_level=str(static.HAMLIB_ALC))
|
alc_level=str(HamlibParam.alc))
|
||||||
else:
|
else:
|
||||||
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(static.TX_AUDIO_LEVEL),
|
self.log.debug("[MDM] AUDIO TUNE", audio_level=str(AudioParam.tx_audio_level),
|
||||||
alc_level=str(static.HAMLIB_ALC))
|
alc_level=str(HamlibParam.alc))
|
||||||
x = set_audio_volume(x, static.TX_AUDIO_LEVEL)
|
x = set_audio_volume(x, AudioParam.tx_audio_level)
|
||||||
|
|
||||||
if not static.AUDIO_ENABLE_TCI:
|
if not AudioParam.audio_enable_tci:
|
||||||
txbuffer_out = self.resampler.resample8_to_48(x)
|
txbuffer_out = self.resampler.resample8_to_48(x)
|
||||||
else:
|
else:
|
||||||
txbuffer_out = x
|
txbuffer_out = x
|
||||||
|
@ -689,7 +704,7 @@ class RF:
|
||||||
self.mod_out_locked = False
|
self.mod_out_locked = False
|
||||||
|
|
||||||
# we need to wait manually for tci processing
|
# we need to wait manually for tci processing
|
||||||
if static.AUDIO_ENABLE_TCI:
|
if AudioParam.audio_enable_tci:
|
||||||
duration = len(txbuffer_out) / 8000
|
duration = len(txbuffer_out) / 8000
|
||||||
timestamp_to_sleep = time.time() + duration
|
timestamp_to_sleep = time.time() + duration
|
||||||
self.log.debug("[MDM] TCI calculated duration", duration=duration)
|
self.log.debug("[MDM] TCI calculated duration", duration=duration)
|
||||||
|
@ -702,7 +717,7 @@ class RF:
|
||||||
tci_timeout_reached = True
|
tci_timeout_reached = True
|
||||||
|
|
||||||
while self.modoutqueue or not tci_timeout_reached:
|
while self.modoutqueue or not tci_timeout_reached:
|
||||||
if static.AUDIO_ENABLE_TCI:
|
if AudioParam.audio_enable_tci:
|
||||||
if time.time() < timestamp_to_sleep:
|
if time.time() < timestamp_to_sleep:
|
||||||
tci_timeout_reached = False
|
tci_timeout_reached = False
|
||||||
else:
|
else:
|
||||||
|
@ -710,9 +725,9 @@ class RF:
|
||||||
|
|
||||||
threading.Event().wait(0.01)
|
threading.Event().wait(0.01)
|
||||||
# if we're transmitting FreeDATA signals, reset channel busy state
|
# if we're transmitting FreeDATA signals, reset channel busy state
|
||||||
static.CHANNEL_BUSY = False
|
ModemParam.channel_busy = False
|
||||||
|
|
||||||
static.PTT_STATE = self.radio.set_ptt(False)
|
HamlibParam.ptt_state = self.radio.set_ptt(False)
|
||||||
|
|
||||||
# Push ptt state to socket stream
|
# Push ptt state to socket stream
|
||||||
jsondata = {"ptt": "False"}
|
jsondata = {"ptt": "False"}
|
||||||
|
@ -723,7 +738,7 @@ class RF:
|
||||||
self.mod_out_locked = True
|
self.mod_out_locked = True
|
||||||
|
|
||||||
self.modem_transmit_queue.task_done()
|
self.modem_transmit_queue.task_done()
|
||||||
static.TRANSMITTING = False
|
TNC.transmitting = False
|
||||||
threading.Event().set()
|
threading.Event().set()
|
||||||
|
|
||||||
end_of_transmission = time.time()
|
end_of_transmission = time.time()
|
||||||
|
@ -781,14 +796,14 @@ class RF:
|
||||||
if rx_status != 0:
|
if rx_status != 0:
|
||||||
# we need to disable this if in testmode as its causing problems with FIFO it seems
|
# we need to disable this if in testmode as its causing problems with FIFO it seems
|
||||||
if not TESTMODE:
|
if not TESTMODE:
|
||||||
static.IS_CODEC2_TRAFFIC = True
|
ModemParam.is_codec2_traffic = True
|
||||||
|
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"[MDM] [demod_audio] modem state", mode=mode_name, rx_status=rx_status,
|
"[MDM] [demod_audio] modem state", mode=mode_name, rx_status=rx_status,
|
||||||
sync_flag=codec2.api.rx_sync_flags_to_text[rx_status]
|
sync_flag=codec2.api.rx_sync_flags_to_text[rx_status]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
static.IS_CODEC2_TRAFFIC = False
|
ModemParam.is_codec2_traffic = False
|
||||||
|
|
||||||
if rx_status == 10:
|
if rx_status == 10:
|
||||||
state_buffer.append(rx_status)
|
state_buffer.append(rx_status)
|
||||||
|
@ -796,11 +811,27 @@ class RF:
|
||||||
audiobuffer.pop(nin)
|
audiobuffer.pop(nin)
|
||||||
nin = codec2.api.freedv_nin(freedv)
|
nin = codec2.api.freedv_nin(freedv)
|
||||||
if nbytes == bytes_per_frame:
|
if nbytes == bytes_per_frame:
|
||||||
# process commands only if static.LISTEN = True
|
|
||||||
if static.LISTEN:
|
# process commands only if TNC.listen = True
|
||||||
|
if TNC.listen:
|
||||||
|
|
||||||
|
|
||||||
|
# ignore data channel opener frames for avoiding toggle states
|
||||||
|
# use case: opener already received, but ack got lost and we are receiving
|
||||||
|
# an opener again
|
||||||
|
if mode_name in ["sig1-datac13"] and int.from_bytes(bytes(bytes_out[:1]), "big") in [
|
||||||
|
FRAME_TYPE.ARQ_SESSION_OPEN.value,
|
||||||
|
FRAME_TYPE.ARQ_DC_OPEN_W.value,
|
||||||
|
FRAME_TYPE.ARQ_DC_OPEN_ACK_W.value,
|
||||||
|
FRAME_TYPE.ARQ_DC_OPEN_N.value,
|
||||||
|
FRAME_TYPE.ARQ_DC_OPEN_ACK_N.value
|
||||||
|
]:
|
||||||
|
print("dropp")
|
||||||
|
else:
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"[MDM] [demod_audio] Pushing received data to received_queue", nbytes=nbytes
|
"[MDM] [demod_audio] Pushing received data to received_queue", nbytes=nbytes
|
||||||
)
|
)
|
||||||
|
|
||||||
self.modem_received_queue.put([bytes_out, freedv, bytes_per_frame])
|
self.modem_received_queue.put([bytes_out, freedv, bytes_per_frame])
|
||||||
self.get_scatter(freedv)
|
self.get_scatter(freedv)
|
||||||
self.calculate_snr(freedv)
|
self.calculate_snr(freedv)
|
||||||
|
@ -808,7 +839,7 @@ class RF:
|
||||||
else:
|
else:
|
||||||
self.log.warning(
|
self.log.warning(
|
||||||
"[MDM] [demod_audio] received frame but ignored processing",
|
"[MDM] [demod_audio] received frame but ignored processing",
|
||||||
listen=static.LISTEN
|
listen=TNC.listen
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning("[MDM] [demod_audio] Stream not active anymore", e=e)
|
self.log.warning("[MDM] [demod_audio] Stream not active anymore", e=e)
|
||||||
|
@ -830,7 +861,7 @@ class RF:
|
||||||
# FSK Long-distance Parity Code 1 - data frames
|
# FSK Long-distance Parity Code 1 - data frames
|
||||||
c2instance = ctypes.cast(
|
c2instance = ctypes.cast(
|
||||||
codec2.api.freedv_open_advanced(
|
codec2.api.freedv_open_advanced(
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC,
|
codec2.FREEDV_MODE.fsk_ldpc.value,
|
||||||
ctypes.byref(adv),
|
ctypes.byref(adv),
|
||||||
),
|
),
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
|
@ -843,10 +874,10 @@ class RF:
|
||||||
)
|
)
|
||||||
|
|
||||||
# set tuning range
|
# set tuning range
|
||||||
self.c_lib.freedv_set_tuning_range(
|
codec2.api.freedv_set_tuning_range(
|
||||||
c2instance,
|
c2instance,
|
||||||
ctypes.c_float(static.TUNING_RANGE_FMIN),
|
ctypes.c_float(ModemParam.tuning_range_fmin),
|
||||||
ctypes.c_float(static.TUNING_RANGE_FMAX),
|
ctypes.c_float(ModemParam.tuning_range_fmax),
|
||||||
)
|
)
|
||||||
|
|
||||||
# get bytes per frame
|
# get bytes per frame
|
||||||
|
@ -868,44 +899,56 @@ class RF:
|
||||||
|
|
||||||
# Additional Datac0-specific information - these are not referenced anywhere else.
|
# Additional Datac0-specific information - these are not referenced anywhere else.
|
||||||
# self.sig0_datac0_payload_per_frame = self.sig0_datac0_bytes_per_frame - 2
|
# self.sig0_datac0_payload_per_frame = self.sig0_datac0_bytes_per_frame - 2
|
||||||
# self.sig0_datac0_n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(
|
# self.sig0_datac0_n_nom_modem_samples = codec2.api.freedv_get_n_nom_modem_samples(
|
||||||
# self.sig0_datac0_freedv
|
# self.sig0_datac0_freedv
|
||||||
# )
|
# )
|
||||||
# self.sig0_datac0_n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(
|
# self.sig0_datac0_n_tx_modem_samples = codec2.api.freedv_get_n_tx_modem_samples(
|
||||||
# self.sig0_datac0_freedv
|
# self.sig0_datac0_freedv
|
||||||
# )
|
# )
|
||||||
# self.sig0_datac0_n_tx_preamble_modem_samples = (
|
# self.sig0_datac0_n_tx_preamble_modem_samples = (
|
||||||
# self.c_lib.freedv_get_n_tx_preamble_modem_samples(self.sig0_datac0_freedv)
|
# codec2.api.freedv_get_n_tx_preamble_modem_samples(self.sig0_datac0_freedv)
|
||||||
# )
|
# )
|
||||||
# self.sig0_datac0_n_tx_postamble_modem_samples = (
|
# self.sig0_datac0_n_tx_postamble_modem_samples = (
|
||||||
# self.c_lib.freedv_get_n_tx_postamble_modem_samples(self.sig0_datac0_freedv)
|
# codec2.api.freedv_get_n_tx_postamble_modem_samples(self.sig0_datac0_freedv)
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# return values
|
# return values
|
||||||
return c2instance, bytes_per_frame, bytes_out, audio_buffer, nin
|
return c2instance, bytes_per_frame, bytes_out, audio_buffer, nin
|
||||||
|
|
||||||
def audio_sig0_datac0(self) -> None:
|
def audio_sig0_datac13(self) -> None:
|
||||||
"""Receive data encoded with datac0 - 0"""
|
"""Receive data encoded with datac13 - 0"""
|
||||||
self.sig0_datac0_nin = self.demodulate_audio(
|
self.sig0_datac13_nin = self.demodulate_audio(
|
||||||
self.sig0_datac0_buffer,
|
self.sig0_datac13_buffer,
|
||||||
self.sig0_datac0_nin,
|
self.sig0_datac13_nin,
|
||||||
self.sig0_datac0_freedv,
|
self.sig0_datac13_freedv,
|
||||||
self.sig0_datac0_bytes_out,
|
self.sig0_datac13_bytes_out,
|
||||||
self.sig0_datac0_bytes_per_frame,
|
self.sig0_datac13_bytes_per_frame,
|
||||||
SIG0_DATAC0_STATE,
|
SIG0_DATAC13_STATE,
|
||||||
"sig0-datac0"
|
"sig0-datac13"
|
||||||
)
|
)
|
||||||
|
|
||||||
def audio_sig1_datac0(self) -> None:
|
def audio_sig1_datac13(self) -> None:
|
||||||
"""Receive data encoded with datac0 - 1"""
|
"""Receive data encoded with datac13 - 1"""
|
||||||
self.sig1_datac0_nin = self.demodulate_audio(
|
self.sig1_datac13_nin = self.demodulate_audio(
|
||||||
self.sig1_datac0_buffer,
|
self.sig1_datac13_buffer,
|
||||||
self.sig1_datac0_nin,
|
self.sig1_datac13_nin,
|
||||||
self.sig1_datac0_freedv,
|
self.sig1_datac13_freedv,
|
||||||
self.sig1_datac0_bytes_out,
|
self.sig1_datac13_bytes_out,
|
||||||
self.sig1_datac0_bytes_per_frame,
|
self.sig1_datac13_bytes_per_frame,
|
||||||
SIG1_DATAC0_STATE,
|
SIG1_DATAC13_STATE,
|
||||||
"sig1-datac0"
|
"sig1-datac13"
|
||||||
|
)
|
||||||
|
|
||||||
|
def audio_dat0_datac4(self) -> None:
|
||||||
|
"""Receive data encoded with datac4"""
|
||||||
|
self.dat0_datac4_nin = self.demodulate_audio(
|
||||||
|
self.dat0_datac4_buffer,
|
||||||
|
self.dat0_datac4_nin,
|
||||||
|
self.dat0_datac4_freedv,
|
||||||
|
self.dat0_datac4_bytes_out,
|
||||||
|
self.dat0_datac4_bytes_per_frame,
|
||||||
|
DAT0_DATAC4_STATE,
|
||||||
|
"dat0-datac4"
|
||||||
)
|
)
|
||||||
|
|
||||||
def audio_dat0_datac1(self) -> None:
|
def audio_dat0_datac1(self) -> None:
|
||||||
|
@ -986,7 +1029,7 @@ class RF:
|
||||||
def get_frequency_offset(self, freedv: ctypes.c_void_p) -> float:
|
def get_frequency_offset(self, freedv: ctypes.c_void_p) -> float:
|
||||||
"""
|
"""
|
||||||
Ask codec2 for the calculated (audio) frequency offset of the received signal.
|
Ask codec2 for the calculated (audio) frequency offset of the received signal.
|
||||||
Side-effect: sets static.FREQ_OFFSET
|
Side-effect: sets ModemParam.frequency_offset
|
||||||
|
|
||||||
:param freedv: codec2 instance to query
|
:param freedv: codec2 instance to query
|
||||||
:type freedv: ctypes.c_void_p
|
:type freedv: ctypes.c_void_p
|
||||||
|
@ -994,25 +1037,25 @@ class RF:
|
||||||
:rtype: float
|
:rtype: float
|
||||||
"""
|
"""
|
||||||
modemStats = codec2.MODEMSTATS()
|
modemStats = codec2.MODEMSTATS()
|
||||||
self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats))
|
codec2.api.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats))
|
||||||
offset = round(modemStats.foff) * (-1)
|
offset = round(modemStats.foff) * (-1)
|
||||||
static.FREQ_OFFSET = offset
|
ModemParam.frequency_offset = offset
|
||||||
return offset
|
return offset
|
||||||
|
|
||||||
def get_scatter(self, freedv: ctypes.c_void_p) -> None:
|
def get_scatter(self, freedv: ctypes.c_void_p) -> None:
|
||||||
"""
|
"""
|
||||||
Ask codec2 for data about the received signal and calculate the scatter plot.
|
Ask codec2 for data about the received signal and calculate the scatter plot.
|
||||||
Side-effect: sets static.SCATTER
|
Side-effect: sets ModemParam.scatter
|
||||||
|
|
||||||
:param freedv: codec2 instance to query
|
:param freedv: codec2 instance to query
|
||||||
:type freedv: ctypes.c_void_p
|
:type freedv: ctypes.c_void_p
|
||||||
"""
|
"""
|
||||||
if not static.ENABLE_SCATTER:
|
if not ModemParam.enable_scatter:
|
||||||
return
|
return
|
||||||
|
|
||||||
modemStats = codec2.MODEMSTATS()
|
modemStats = codec2.MODEMSTATS()
|
||||||
ctypes.cast(
|
ctypes.cast(
|
||||||
self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)),
|
codec2.api.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)),
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1035,16 +1078,16 @@ class RF:
|
||||||
|
|
||||||
# Send all the data if we have too-few samples, otherwise send a sampling
|
# Send all the data if we have too-few samples, otherwise send a sampling
|
||||||
if 150 > len(scatterdata) > 0:
|
if 150 > len(scatterdata) > 0:
|
||||||
static.SCATTER = scatterdata
|
ModemParam.scatter = scatterdata
|
||||||
else:
|
else:
|
||||||
# only take every tenth data point
|
# only take every tenth data point
|
||||||
static.SCATTER = scatterdata[::10]
|
ModemParam.scatter = scatterdata[::10]
|
||||||
|
|
||||||
def calculate_snr(self, freedv: ctypes.c_void_p) -> float:
|
def calculate_snr(self, freedv: ctypes.c_void_p) -> float:
|
||||||
"""
|
"""
|
||||||
Ask codec2 for data about the received signal and calculate
|
Ask codec2 for data about the received signal and calculate
|
||||||
the signal-to-noise ratio.
|
the signal-to-noise ratio.
|
||||||
Side-effect: sets static.SNR
|
Side-effect: sets ModemParam.snr
|
||||||
|
|
||||||
:param freedv: codec2 instance to query
|
:param freedv: codec2 instance to query
|
||||||
:type freedv: ctypes.c_void_p
|
:type freedv: ctypes.c_void_p
|
||||||
|
@ -1055,7 +1098,7 @@ class RF:
|
||||||
modem_stats_snr = ctypes.c_float()
|
modem_stats_snr = ctypes.c_float()
|
||||||
modem_stats_sync = ctypes.c_int()
|
modem_stats_sync = ctypes.c_int()
|
||||||
|
|
||||||
self.c_lib.freedv_get_modem_stats(
|
codec2.api.freedv_get_modem_stats(
|
||||||
freedv, ctypes.byref(modem_stats_sync), ctypes.byref(modem_stats_snr)
|
freedv, ctypes.byref(modem_stats_sync), ctypes.byref(modem_stats_snr)
|
||||||
)
|
)
|
||||||
modem_stats_snr = modem_stats_snr.value
|
modem_stats_snr = modem_stats_snr.value
|
||||||
|
@ -1063,15 +1106,15 @@ class RF:
|
||||||
|
|
||||||
snr = round(modem_stats_snr, 1)
|
snr = round(modem_stats_snr, 1)
|
||||||
self.log.info("[MDM] calculate_snr: ", snr=snr)
|
self.log.info("[MDM] calculate_snr: ", snr=snr)
|
||||||
static.SNR = snr
|
ModemParam.snr = snr
|
||||||
# static.SNR = np.clip(
|
# ModemParam.snr = np.clip(
|
||||||
# snr, -127, 127
|
# snr, -127, 127
|
||||||
# ) # limit to max value of -128/128 as a possible fix of #188
|
# ) # limit to max value of -128/128 as a possible fix of #188
|
||||||
return static.SNR
|
return ModemParam.snr
|
||||||
except Exception as err:
|
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
|
ModemParam.snr = 0
|
||||||
return static.SNR
|
return ModemParam.snr
|
||||||
|
|
||||||
def set_rig_data(self) -> None:
|
def set_rig_data(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1091,29 +1134,29 @@ class RF:
|
||||||
"""
|
"""
|
||||||
Request information about the current state of the radio via hamlib
|
Request information about the current state of the radio via hamlib
|
||||||
Side-effect: sets
|
Side-effect: sets
|
||||||
- static.HAMLIB_FREQUENCY
|
- HamlibParam.hamlib_frequency
|
||||||
- static.HAMLIB_MODE
|
- HamlibParam.hamlib_mode
|
||||||
- static.HAMLIB_BANDWIDTH
|
- HamlibParam.hamlib_bandwidth
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
# this looks weird, but is necessary for avoiding rigctld packet colission sock
|
# this looks weird, but is necessary for avoiding rigctld packet colission sock
|
||||||
threading.Event().wait(0.25)
|
threading.Event().wait(0.25)
|
||||||
static.HAMLIB_FREQUENCY = self.radio.get_frequency()
|
HamlibParam.hamlib_frequency = self.radio.get_frequency()
|
||||||
threading.Event().wait(0.1)
|
threading.Event().wait(0.1)
|
||||||
static.HAMLIB_MODE = self.radio.get_mode()
|
HamlibParam.hamlib_mode = self.radio.get_mode()
|
||||||
threading.Event().wait(0.1)
|
threading.Event().wait(0.1)
|
||||||
static.HAMLIB_BANDWIDTH = self.radio.get_bandwidth()
|
HamlibParam.hamlib_bandwidth = self.radio.get_bandwidth()
|
||||||
threading.Event().wait(0.1)
|
threading.Event().wait(0.1)
|
||||||
static.HAMLIB_STATUS = self.radio.get_status()
|
HamlibParam.hamlib_status = self.radio.get_status()
|
||||||
threading.Event().wait(0.1)
|
threading.Event().wait(0.1)
|
||||||
if static.TRANSMITTING:
|
if TNC.transmitting:
|
||||||
static.HAMLIB_ALC = self.radio.get_alc()
|
HamlibParam.alc = self.radio.get_alc()
|
||||||
threading.Event().wait(0.1)
|
threading.Event().wait(0.1)
|
||||||
# static.HAMLIB_RF = self.radio.get_level()
|
# HamlibParam.hamlib_rf = self.radio.get_level()
|
||||||
# threading.Event().wait(0.1)
|
# threading.Event().wait(0.1)
|
||||||
static.HAMLIB_STRENGTH = self.radio.get_strength()
|
HamlibParam.hamlib_strength = self.radio.get_strength()
|
||||||
|
|
||||||
# print(f"ALC: {static.HAMLIB_ALC}, RF: {static.HAMLIB_RF}, STRENGTH: {static.HAMLIB_STRENGTH}")
|
# print(f"ALC: {HamlibParam.alc}, RF: {HamlibParam.hamlib_rf}, STRENGTH: {HamlibParam.hamlib_strength}")
|
||||||
|
|
||||||
def calculate_fft(self) -> None:
|
def calculate_fft(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1152,7 +1195,7 @@ class RF:
|
||||||
# Therefore we are setting it to 100 so it will be highlighted
|
# Therefore we are setting it to 100 so it will be highlighted
|
||||||
# Have to do this when we are not transmitting so our
|
# Have to do this when we are not transmitting so our
|
||||||
# own sending data will not affect this too much
|
# own sending data will not affect this too much
|
||||||
if not static.TRANSMITTING:
|
if not TNC.transmitting:
|
||||||
dfft[dfft > avg + 15] = 100
|
dfft[dfft > avg + 15] = 100
|
||||||
|
|
||||||
# Calculate audio dbfs
|
# Calculate audio dbfs
|
||||||
|
@ -1162,27 +1205,26 @@ class RF:
|
||||||
if rms_counter > 50:
|
if rms_counter > 50:
|
||||||
d = np.frombuffer(self.fft_data, np.int16).astype(np.float32)
|
d = np.frombuffer(self.fft_data, np.int16).astype(np.float32)
|
||||||
# calculate RMS and then dBFS
|
# calculate RMS and then dBFS
|
||||||
# TODO: Need to change static.AUDIO_RMS to AUDIO_DBFS somewhen
|
|
||||||
# https://dsp.stackexchange.com/questions/8785/how-to-compute-dbfs
|
# https://dsp.stackexchange.com/questions/8785/how-to-compute-dbfs
|
||||||
# try except for avoiding runtime errors by division/0
|
# try except for avoiding runtime errors by division/0
|
||||||
try:
|
try:
|
||||||
rms = int(np.sqrt(np.max(d ** 2)))
|
rms = int(np.sqrt(np.max(d ** 2)))
|
||||||
if rms == 0:
|
if rms == 0:
|
||||||
raise ZeroDivisionError
|
raise ZeroDivisionError
|
||||||
static.AUDIO_DBFS = 20 * np.log10(rms / 32768)
|
AudioParam.audio_dbfs = 20 * np.log10(rms / 32768)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(
|
self.log.warning(
|
||||||
"[MDM] fft calculation error - please check your audio setup",
|
"[MDM] fft calculation error - please check your audio setup",
|
||||||
e=e,
|
e=e,
|
||||||
)
|
)
|
||||||
static.AUDIO_DBFS = -100
|
AudioParam.audio_dbfs = -100
|
||||||
|
|
||||||
rms_counter = 0
|
rms_counter = 0
|
||||||
|
|
||||||
# Convert data to int to decrease size
|
# Convert data to int to decrease size
|
||||||
dfft = dfft.astype(int)
|
dfft = dfft.astype(int)
|
||||||
|
|
||||||
# Create list of dfft for later pushing to static.FFT
|
# Create list of dfft for later pushing to AudioParam.fft
|
||||||
dfftlist = dfft.tolist()
|
dfftlist = dfft.tolist()
|
||||||
|
|
||||||
# Reduce area where the busy detection is enabled
|
# Reduce area where the busy detection is enabled
|
||||||
|
@ -1196,14 +1238,26 @@ class RF:
|
||||||
# 2700Hz = 266
|
# 2700Hz = 266
|
||||||
# 3200Hz = 315
|
# 3200Hz = 315
|
||||||
|
|
||||||
# define the area, we are detecting busy state
|
# slot
|
||||||
dfft = dfft[120:176] if static.LOW_BANDWIDTH_MODE else dfft[65:231]
|
slot = 0
|
||||||
|
slot1 = [0, 65]
|
||||||
|
slot2 = [65,120]
|
||||||
|
slot3 = [120, 176]
|
||||||
|
slot4 = [176, 231]
|
||||||
|
slot5 = [231, len(dfftlist)]
|
||||||
|
for range in [slot1, slot2, slot3, slot4, slot5]:
|
||||||
|
|
||||||
|
range_start = range[0]
|
||||||
|
range_end = range[1]
|
||||||
|
# define the area, we are detecting busy state
|
||||||
|
#dfft = dfft[120:176] if TNC.low_bandwidth_mode else dfft[65:231]
|
||||||
|
dfft = dfft[range_start:range_end]
|
||||||
# Check for signals higher than average by checking for "100"
|
# Check for signals higher than average by checking for "100"
|
||||||
# If we have a signal, increment our channel_busy delay counter
|
# If we have a signal, increment our channel_busy delay counter
|
||||||
# so we have a smoother state toggle
|
# so we have a smoother state toggle
|
||||||
if np.sum(dfft[dfft > avg + 15]) >= 400 and not static.TRANSMITTING:
|
if np.sum(dfft[dfft > avg + 15]) >= 400 and not TNC.transmitting:
|
||||||
static.CHANNEL_BUSY = True
|
ModemParam.channel_busy = True
|
||||||
|
ModemParam.channel_busy_slot[slot] = True
|
||||||
# Limit delay counter to a maximum of 200. The higher this value,
|
# Limit delay counter to a maximum of 200. The higher this value,
|
||||||
# the longer we will wait until releasing state
|
# the longer we will wait until releasing state
|
||||||
channel_busy_delay = min(channel_busy_delay + 10, 200)
|
channel_busy_delay = min(channel_busy_delay + 10, 200)
|
||||||
|
@ -1212,14 +1266,18 @@ class RF:
|
||||||
channel_busy_delay = max(channel_busy_delay - 1, 0)
|
channel_busy_delay = max(channel_busy_delay - 1, 0)
|
||||||
# When our channel busy counter reaches 0, toggle state to False
|
# When our channel busy counter reaches 0, toggle state to False
|
||||||
if channel_busy_delay == 0:
|
if channel_busy_delay == 0:
|
||||||
static.CHANNEL_BUSY = False
|
ModemParam.channel_busy = False
|
||||||
|
ModemParam.channel_busy_slot[slot] = False
|
||||||
|
|
||||||
static.FFT = dfftlist[:315] # 315 --> bandwidth 3200
|
# increment slot
|
||||||
|
slot += 1
|
||||||
|
|
||||||
|
AudioParam.fft = dfftlist[:315] # 315 --> bandwidth 3200
|
||||||
except Exception as err:
|
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")
|
self.log.debug("[MDM] Setting fft=0")
|
||||||
# else 0
|
# else 0
|
||||||
static.FFT = [0]
|
AudioParam.fft = [0]
|
||||||
|
|
||||||
def set_frames_per_burst(self, frames_per_burst: int) -> None:
|
def set_frames_per_burst(self, frames_per_burst: int) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1232,10 +1290,26 @@ class RF:
|
||||||
frames_per_burst = min(frames_per_burst, 1)
|
frames_per_burst = min(frames_per_burst, 1)
|
||||||
frames_per_burst = max(frames_per_burst, 5)
|
frames_per_burst = max(frames_per_burst, 5)
|
||||||
|
|
||||||
|
frames_per_burst = 1
|
||||||
|
|
||||||
codec2.api.freedv_set_frames_per_burst(self.dat0_datac1_freedv, frames_per_burst)
|
codec2.api.freedv_set_frames_per_burst(self.dat0_datac1_freedv, frames_per_burst)
|
||||||
codec2.api.freedv_set_frames_per_burst(self.dat0_datac3_freedv, frames_per_burst)
|
codec2.api.freedv_set_frames_per_burst(self.dat0_datac3_freedv, frames_per_burst)
|
||||||
|
codec2.api.freedv_set_frames_per_burst(self.dat0_datac4_freedv, frames_per_burst)
|
||||||
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, frames_per_burst)
|
codec2.api.freedv_set_frames_per_burst(self.fsk_ldpc_freedv_0, frames_per_burst)
|
||||||
|
|
||||||
|
def reset_data_sync(self) -> None:
|
||||||
|
"""
|
||||||
|
reset sync state for data modes
|
||||||
|
|
||||||
|
:param frames_per_burst: Number of frames per burst requested
|
||||||
|
:type frames_per_burst: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
codec2.api.freedv_set_sync(self.dat0_datac1_freedv, 0)
|
||||||
|
codec2.api.freedv_set_sync(self.dat0_datac3_freedv, 0)
|
||||||
|
codec2.api.freedv_set_sync(self.dat0_datac4_freedv, 0)
|
||||||
|
codec2.api.freedv_set_sync(self.fsk_ldpc_freedv_0, 0)
|
||||||
|
|
||||||
|
|
||||||
def open_codec2_instance(mode: int) -> ctypes.c_void_p:
|
def open_codec2_instance(mode: int) -> ctypes.c_void_p:
|
||||||
"""
|
"""
|
||||||
|
@ -1249,7 +1323,7 @@ def open_codec2_instance(mode: int) -> ctypes.c_void_p:
|
||||||
if mode in [codec2.FREEDV_MODE.fsk_ldpc_0.value]:
|
if mode in [codec2.FREEDV_MODE.fsk_ldpc_0.value]:
|
||||||
return ctypes.cast(
|
return ctypes.cast(
|
||||||
codec2.api.freedv_open_advanced(
|
codec2.api.freedv_open_advanced(
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC,
|
codec2.FREEDV_MODE.fsk_ldpc.value,
|
||||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV),
|
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_0_ADV),
|
||||||
),
|
),
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
|
@ -1258,7 +1332,7 @@ def open_codec2_instance(mode: int) -> ctypes.c_void_p:
|
||||||
if mode in [codec2.FREEDV_MODE.fsk_ldpc_1.value]:
|
if mode in [codec2.FREEDV_MODE.fsk_ldpc_1.value]:
|
||||||
return ctypes.cast(
|
return ctypes.cast(
|
||||||
codec2.api.freedv_open_advanced(
|
codec2.api.freedv_open_advanced(
|
||||||
codec2.api.FREEDV_MODE_FSK_LDPC,
|
codec2.FREEDV_MODE.fsk_ldpc.value,
|
||||||
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV),
|
ctypes.byref(codec2.api.FREEDV_MODE_FSK_LDPC_1_ADV),
|
||||||
),
|
),
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
|
@ -1277,7 +1351,7 @@ def get_bytes_per_frame(mode: int) -> int:
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
freedv = open_codec2_instance(mode)
|
freedv = open_codec2_instance(mode)
|
||||||
|
# TODO: add close session
|
||||||
# get number of bytes per frame for mode
|
# get number of bytes per frame for mode
|
||||||
return int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
|
return int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||||
|
|
||||||
|
@ -1320,5 +1394,8 @@ def get_modem_error_state():
|
||||||
if RECEIVE_DATAC3 and 10 in DAT0_DATAC3_STATE:
|
if RECEIVE_DATAC3 and 10 in DAT0_DATAC3_STATE:
|
||||||
DAT0_DATAC3_STATE.clear()
|
DAT0_DATAC3_STATE.clear()
|
||||||
return True
|
return True
|
||||||
|
if RECEIVE_DATAC4 and 10 in DAT0_DATAC4_STATE:
|
||||||
|
DAT0_DATAC4_STATE.clear()
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
|
@ -3,6 +3,7 @@ Hold queues used by more than one module to eliminate cyclic imports.
|
||||||
"""
|
"""
|
||||||
import queue
|
import queue
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, TCIParam, TNC
|
||||||
|
|
||||||
DATA_QUEUE_TRANSMIT = queue.Queue()
|
DATA_QUEUE_TRANSMIT = queue.Queue()
|
||||||
DATA_QUEUE_RECEIVED = queue.Queue()
|
DATA_QUEUE_RECEIVED = queue.Queue()
|
||||||
|
@ -16,7 +17,7 @@ AUDIO_RECEIVED_QUEUE = queue.Queue()
|
||||||
AUDIO_TRANSMIT_QUEUE = queue.Queue()
|
AUDIO_TRANSMIT_QUEUE = queue.Queue()
|
||||||
|
|
||||||
# Initialize FIFO queue to finally store received data
|
# Initialize FIFO queue to finally store received data
|
||||||
RX_BUFFER = queue.Queue(maxsize=static.RX_BUFFER_SIZE)
|
RX_BUFFER = queue.Queue(maxsize=ARQ.rx_buffer_size)
|
||||||
|
|
||||||
# Commands we want to send to rigctld
|
# Commands we want to send to rigctld
|
||||||
RIGCTLD_COMMAND_QUEUE = queue.Queue()
|
RIGCTLD_COMMAND_QUEUE = queue.Queue()
|
|
@ -10,9 +10,7 @@ import time
|
||||||
import structlog
|
import structlog
|
||||||
import threading
|
import threading
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, TCIParam
|
||||||
# set global hamlib version
|
|
||||||
hamlib_version = 0
|
|
||||||
|
|
||||||
|
|
||||||
class radio:
|
class radio:
|
||||||
|
@ -243,7 +241,7 @@ class radio:
|
||||||
if 'RPRT' not in alc:
|
if 'RPRT' not in alc:
|
||||||
try:
|
try:
|
||||||
alc = float(alc)
|
alc = float(alc)
|
||||||
self.alc = alc if alc != 0.0 else static.HAMLIB_ALC
|
self.alc = alc if alc != 0.0 else HamlibParam.alc
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.alc = 0.0
|
self.alc = 0.0
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ simple TNC self tests
|
||||||
# pylint: disable=import-outside-toplevel, attribute-defined-outside-init
|
# pylint: disable=import-outside-toplevel, attribute-defined-outside-init
|
||||||
import sys
|
import sys
|
||||||
import structlog
|
import structlog
|
||||||
|
from static import ARQ, Audio, Beacon, Channel, Daemon, Hamlib, Modem, Station, TCI, TNC
|
||||||
|
|
||||||
log = structlog.get_logger("selftest")
|
log = structlog.get_logger("selftest")
|
||||||
|
|
||||||
|
|
||||||
|
|
197
tnc/sock.py
197
tnc/sock.py
|
@ -27,6 +27,7 @@ import time
|
||||||
import wave
|
import wave
|
||||||
import helpers
|
import helpers
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC
|
||||||
import structlog
|
import structlog
|
||||||
from random import randrange
|
from random import randrange
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
@ -67,7 +68,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
while self.connection_alive and not CLOSE_SIGNAL:
|
while self.connection_alive and not CLOSE_SIGNAL:
|
||||||
# send tnc state as network stream
|
# send tnc state as network stream
|
||||||
# check server port against daemon port and send corresponding data
|
# check server port against daemon port and send corresponding data
|
||||||
if self.server.server_address[1] == static.PORT and not static.TNCSTARTED:
|
if self.server.server_address[1] == TNC.port and not Daemon.tncstarted:
|
||||||
data = send_tnc_state()
|
data = send_tnc_state()
|
||||||
if data != tempdata:
|
if data != tempdata:
|
||||||
tempdata = data
|
tempdata = data
|
||||||
|
@ -98,9 +99,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
self.log.debug("[SCK] catch harmless RuntimeError: Set changed size during iteration", e=err)
|
self.log.debug("[SCK] catch harmless RuntimeError: Set changed size during iteration", e=err)
|
||||||
|
|
||||||
# we want to transmit scatter data only once to reduce network traffic
|
# we want to transmit scatter data only once to reduce network traffic
|
||||||
static.SCATTER = []
|
ModemParam.scatter = []
|
||||||
# we want to display INFO messages only once
|
|
||||||
static.INFO = []
|
|
||||||
# self.request.sendall(sock_data)
|
# self.request.sendall(sock_data)
|
||||||
threading.Event().wait(0.15)
|
threading.Event().wait(0.15)
|
||||||
|
|
||||||
|
@ -127,7 +126,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
# iterate thorugh data list
|
# iterate thorugh data list
|
||||||
for commands in data:
|
for commands in data:
|
||||||
if self.server.server_address[1] == static.PORT:
|
if self.server.server_address[1] == TNC.port:
|
||||||
self.process_tnc_commands(commands)
|
self.process_tnc_commands(commands)
|
||||||
else:
|
else:
|
||||||
self.process_daemon_commands(commands)
|
self.process_daemon_commands(commands)
|
||||||
|
@ -354,14 +353,14 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_set_listen(self, received_json):
|
def tnc_set_listen(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.LISTEN = received_json["state"] in ['true', 'True', True, "ON", "on"]
|
TNC.listen = received_json["state"] in ['true', 'True', True, "ON", "on"]
|
||||||
command_response("listen", True)
|
command_response("listen", True)
|
||||||
|
|
||||||
# if tnc is connected, force disconnect when static.LISTEN == False
|
# if tnc is connected, force disconnect when TNC.listen == False
|
||||||
if not static.LISTEN and static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]:
|
if not TNC.listen and ARQ.arq_session_state not in ["disconnecting", "disconnected", "failed"]:
|
||||||
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
||||||
# set early disconnecting state so we can interrupt connection attempts
|
# set early disconnecting state so we can interrupt connection attempts
|
||||||
static.ARQ_SESSION_STATE = "disconnecting"
|
ARQ.arq_session_state = "disconnecting"
|
||||||
command_response("disconnect", True)
|
command_response("disconnect", True)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -372,15 +371,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_set_record_audio(self, received_json):
|
def tnc_set_record_audio(self, received_json):
|
||||||
try:
|
try:
|
||||||
if not static.AUDIO_RECORD:
|
if not AudioParam.audio_record:
|
||||||
static.AUDIO_RECORD_FILE = wave.open(f"{int(time.time())}_audio_recording.wav", 'w')
|
AudioParam.audio_record_FILE = wave.open(f"{int(time.time())}_audio_recording.wav", 'w')
|
||||||
static.AUDIO_RECORD_FILE.setnchannels(1)
|
AudioParam.audio_record_FILE.setnchannels(1)
|
||||||
static.AUDIO_RECORD_FILE.setsampwidth(2)
|
AudioParam.audio_record_FILE.setsampwidth(2)
|
||||||
static.AUDIO_RECORD_FILE.setframerate(8000)
|
AudioParam.audio_record_FILE.setframerate(8000)
|
||||||
static.AUDIO_RECORD = True
|
AudioParam.audio_record = True
|
||||||
else:
|
else:
|
||||||
static.AUDIO_RECORD = False
|
AudioParam.audio_record = False
|
||||||
static.AUDIO_RECORD_FILE.close()
|
AudioParam.audio_record_FILE.close()
|
||||||
|
|
||||||
command_response("respond_to_call", True)
|
command_response("respond_to_call", True)
|
||||||
|
|
||||||
|
@ -392,7 +391,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_set_respond_to_call(self, received_json):
|
def tnc_set_respond_to_call(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.RESPOND_TO_CALL = received_json["state"] in ['true', 'True', True]
|
TNC.respond_to_call = received_json["state"] in ['true', 'True', True]
|
||||||
command_response("respond_to_call", True)
|
command_response("respond_to_call", True)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -403,7 +402,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_set_respond_to_cq(self, received_json):
|
def tnc_set_respond_to_cq(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.RESPOND_TO_CQ = received_json["state"] in ['true', 'True', True]
|
TNC.respond_to_cq = received_json["state"] in ['true', 'True', True]
|
||||||
command_response("respond_to_cq", True)
|
command_response("respond_to_cq", True)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -414,7 +413,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_set_tx_audio_level(self, received_json):
|
def tnc_set_tx_audio_level(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.TX_AUDIO_LEVEL = int(received_json["value"])
|
AudioParam.tx_audio_level = int(received_json["value"])
|
||||||
command_response("tx_audio_level", True)
|
command_response("tx_audio_level", True)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -481,7 +480,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_start_beacon(self, received_json):
|
def tnc_start_beacon(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.BEACON_STATE = True
|
Beacon.beacon_state = True
|
||||||
interval = int(received_json["parameter"])
|
interval = int(received_json["parameter"])
|
||||||
DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
||||||
command_response("start_beacon", True)
|
command_response("start_beacon", True)
|
||||||
|
@ -496,7 +495,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
def tnc_stop_beacon(self, received_json):
|
def tnc_stop_beacon(self, received_json):
|
||||||
try:
|
try:
|
||||||
log.warning("[SCK] Stopping beacon!")
|
log.warning("[SCK] Stopping beacon!")
|
||||||
static.BEACON_STATE = False
|
Beacon.beacon_state = False
|
||||||
DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
||||||
command_response("stop_beacon", True)
|
command_response("stop_beacon", True)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -527,7 +526,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
mycallsign = static.MYCALLSIGN
|
mycallsign = Station.mycallsign
|
||||||
|
|
||||||
DATA_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign])
|
DATA_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign])
|
||||||
command_response("ping", True)
|
command_response("ping", True)
|
||||||
|
@ -543,7 +542,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
def tnc_arq_connect(self, received_json):
|
def tnc_arq_connect(self, received_json):
|
||||||
|
|
||||||
# pause our beacon first
|
# pause our beacon first
|
||||||
static.BEACON_PAUSE = True
|
Beacon.beacon_pause = True
|
||||||
|
|
||||||
# check for connection attempts key
|
# check for connection attempts key
|
||||||
try:
|
try:
|
||||||
|
@ -561,7 +560,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
mycallsign = static.MYCALLSIGN
|
mycallsign = Station.mycallsign
|
||||||
|
|
||||||
# additional step for being sure our callsign is correctly
|
# additional step for being sure our callsign is correctly
|
||||||
# in case we are not getting a station ssid
|
# in case we are not getting a station ssid
|
||||||
|
@ -569,11 +568,11 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
|
|
||||||
if static.ARQ_SESSION_STATE not in ["disconnected", "failed"]:
|
if ARQ.arq_session_state not in ["disconnected", "failed"]:
|
||||||
command_response("connect", False)
|
command_response("connect", False)
|
||||||
log.warning(
|
log.warning(
|
||||||
"[SCK] Connect command execution error",
|
"[SCK] Connect command execution error",
|
||||||
e=f"already connected to station:{static.DXCALLSIGN}",
|
e=f"already connected to station:{Station.dxcallsign}",
|
||||||
command=received_json,
|
command=received_json,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -593,24 +592,24 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
command=received_json,
|
command=received_json,
|
||||||
)
|
)
|
||||||
# allow beacon transmission again
|
# allow beacon transmission again
|
||||||
static.BEACON_PAUSE = False
|
Beacon.beacon_pause = False
|
||||||
|
|
||||||
# allow beacon transmission again
|
# allow beacon transmission again
|
||||||
static.BEACON_PAUSE = False
|
Beacon.beacon_pause = False
|
||||||
|
|
||||||
def tnc_arq_disconnect(self, received_json):
|
def tnc_arq_disconnect(self, received_json):
|
||||||
try:
|
try:
|
||||||
if static.ARQ_SESSION_STATE not in ["disconnecting", "disconnected", "failed"]:
|
if ARQ.arq_session_state not in ["disconnecting", "disconnected", "failed"]:
|
||||||
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
||||||
|
|
||||||
# set early disconnecting state so we can interrupt connection attempts
|
# set early disconnecting state so we can interrupt connection attempts
|
||||||
static.ARQ_SESSION_STATE = "disconnecting"
|
ARQ.arq_session_state = "disconnecting"
|
||||||
command_response("disconnect", True)
|
command_response("disconnect", True)
|
||||||
else:
|
else:
|
||||||
command_response("disconnect", False)
|
command_response("disconnect", False)
|
||||||
log.warning(
|
log.warning(
|
||||||
"[SCK] Disconnect command not possible",
|
"[SCK] Disconnect command not possible",
|
||||||
state=static.ARQ_SESSION_STATE,
|
state=ARQ.arq_session_state,
|
||||||
command=received_json,
|
command=received_json,
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -622,13 +621,13 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
def tnc_arq_send_raw(self, received_json):
|
def tnc_arq_send_raw(self, received_json):
|
||||||
static.BEACON_PAUSE = True
|
Beacon.beacon_pause = True
|
||||||
|
|
||||||
# wait some random time
|
# wait some random time
|
||||||
helpers.wait(randrange(5, 25, 5) / 10.0)
|
helpers.wait(randrange(5, 25, 5) / 10.0)
|
||||||
|
|
||||||
# we need to warn if already in arq state
|
# we need to warn if already in arq state
|
||||||
if static.ARQ_STATE:
|
if ARQ.arq_state:
|
||||||
command_response("send_raw", False)
|
command_response("send_raw", False)
|
||||||
log.warning(
|
log.warning(
|
||||||
"[SCK] Send raw command execution warning",
|
"[SCK] Send raw command execution warning",
|
||||||
|
@ -638,19 +637,19 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not static.ARQ_SESSION:
|
if not ARQ.arq_session:
|
||||||
dxcallsign = received_json["parameter"][0]["dxcallsign"]
|
dxcallsign = received_json["parameter"][0]["dxcallsign"]
|
||||||
# additional step for being sure our callsign is correctly
|
# additional step for being sure our callsign is correctly
|
||||||
# in case we are not getting a station ssid
|
# in case we are not getting a station ssid
|
||||||
# then we are forcing a station ssid = 0
|
# then we are forcing a station ssid = 0
|
||||||
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
|
||||||
static.DXCALLSIGN = dxcallsign
|
Station.dxcallsign = dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
||||||
command_response("send_raw", True)
|
command_response("send_raw", True)
|
||||||
else:
|
else:
|
||||||
dxcallsign = static.DXCALLSIGN
|
dxcallsign = Station.dxcallsign
|
||||||
static.DXCALLSIGN_CRC = helpers.get_crc_24(static.DXCALLSIGN)
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
||||||
|
|
||||||
mode = int(received_json["parameter"][0]["mode"])
|
mode = int(received_json["parameter"][0]["mode"])
|
||||||
n_frames = int(received_json["parameter"][0]["n_frames"])
|
n_frames = int(received_json["parameter"][0]["n_frames"])
|
||||||
|
@ -663,7 +662,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
mycallsign = static.MYCALLSIGN
|
mycallsign = Station.mycallsign
|
||||||
|
|
||||||
# check for connection attempts key
|
# check for connection attempts key
|
||||||
try:
|
try:
|
||||||
|
@ -697,11 +696,11 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def tnc_arq_stop_transmission(self, received_json):
|
def tnc_arq_stop_transmission(self, received_json):
|
||||||
try:
|
try:
|
||||||
if static.TNC_STATE == "BUSY" or static.ARQ_STATE:
|
if TNC.tnc_state == "BUSY" or ARQ.arq_state:
|
||||||
DATA_QUEUE_TRANSMIT.put(["STOP"])
|
DATA_QUEUE_TRANSMIT.put(["STOP"])
|
||||||
log.warning("[SCK] Stopping transmission!")
|
log.warning("[SCK] Stopping transmission!")
|
||||||
static.TNC_STATE = "IDLE"
|
TNC.tnc_state = "IDLE"
|
||||||
static.ARQ_STATE = False
|
ARQ.arq_state = False
|
||||||
command_response("stop_transmission", True)
|
command_response("stop_transmission", True)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
command_response("stop_transmission", False)
|
command_response("stop_transmission", False)
|
||||||
|
@ -803,7 +802,7 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
if (
|
if (
|
||||||
received_json["type"] == "set"
|
received_json["type"] == "set"
|
||||||
and received_json["command"] == "start_tnc"
|
and received_json["command"] == "start_tnc"
|
||||||
and not static.TNCSTARTED
|
and not Daemon.tncstarted
|
||||||
):
|
):
|
||||||
self.daemon_start_tnc(received_json)
|
self.daemon_start_tnc(received_json)
|
||||||
|
|
||||||
|
@ -821,18 +820,18 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
self.request.sendall(b"INVALID CALLSIGN")
|
self.request.sendall(b"INVALID CALLSIGN")
|
||||||
log.warning(
|
log.warning(
|
||||||
"[SCK] SET MYCALL FAILED",
|
"[SCK] SET MYCALL FAILED",
|
||||||
call=static.MYCALLSIGN,
|
call=Station.mycallsign,
|
||||||
crc=static.MYCALLSIGN_CRC.hex(),
|
crc=Station.mycallsign_crc.hex(),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
static.MYCALLSIGN = bytes(callsign, "utf-8")
|
Station.mycallsign = bytes(callsign, "utf-8")
|
||||||
static.MYCALLSIGN_CRC = helpers.get_crc_24(static.MYCALLSIGN)
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
||||||
|
|
||||||
command_response("mycallsign", True)
|
command_response("mycallsign", True)
|
||||||
log.info(
|
log.info(
|
||||||
"[SCK] SET MYCALL",
|
"[SCK] SET MYCALL",
|
||||||
call=static.MYCALLSIGN,
|
call=Station.mycallsign,
|
||||||
crc=static.MYCALLSIGN_CRC.hex(),
|
crc=Station.mycallsign_crc.hex(),
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
command_response("mycallsign", False)
|
command_response("mycallsign", False)
|
||||||
|
@ -846,8 +845,8 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
self.request.sendall(b"INVALID GRID")
|
self.request.sendall(b"INVALID GRID")
|
||||||
command_response("mygrid", False)
|
command_response("mygrid", False)
|
||||||
else:
|
else:
|
||||||
static.MYGRID = bytes(mygrid, "utf-8")
|
Station.mygrid = bytes(mygrid, "utf-8")
|
||||||
log.info("[SCK] SET MYGRID", grid=static.MYGRID)
|
log.info("[SCK] SET MYGRID", grid=Station.mygrid)
|
||||||
command_response("mygrid", True)
|
command_response("mygrid", True)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
command_response("mygrid", False)
|
command_response("mygrid", False)
|
||||||
|
@ -928,12 +927,12 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
def daemon_stop_tnc(self, received_json):
|
def daemon_stop_tnc(self, received_json):
|
||||||
try:
|
try:
|
||||||
static.TNCPROCESS.kill()
|
Daemon.tncprocess.kill()
|
||||||
# unregister process from atexit to avoid process zombies
|
# unregister process from atexit to avoid process zombies
|
||||||
atexit.unregister(static.TNCPROCESS.kill)
|
atexit.unregister(Daemon.tncprocess.kill)
|
||||||
|
|
||||||
log.warning("[SCK] Stopping TNC")
|
log.warning("[SCK] Stopping TNC")
|
||||||
static.TNCSTARTED = False
|
Daemon.tncstarted = False
|
||||||
command_response("stop_tnc", True)
|
command_response("stop_tnc", True)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
command_response("stop_tnc", False)
|
command_response("stop_tnc", False)
|
||||||
|
@ -972,15 +971,15 @@ def send_daemon_state():
|
||||||
"command": "daemon_state",
|
"command": "daemon_state",
|
||||||
"daemon_state": [],
|
"daemon_state": [],
|
||||||
"python_version": str(python_version),
|
"python_version": str(python_version),
|
||||||
"input_devices": static.AUDIO_INPUT_DEVICES,
|
"input_devices": AudioParam.audio_input_devices,
|
||||||
"output_devices": static.AUDIO_OUTPUT_DEVICES,
|
"output_devices": AudioParam.audio_output_devices,
|
||||||
"serial_devices": static.SERIAL_DEVICES,
|
"serial_devices": Daemon.serial_devices,
|
||||||
# 'cpu': str(psutil.cpu_percent()),
|
# 'cpu': str(psutil.cpu_percent()),
|
||||||
# 'ram': str(psutil.virtual_memory().percent),
|
# 'ram': str(psutil.virtual_memory().percent),
|
||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
}
|
}
|
||||||
|
|
||||||
if static.TNCSTARTED:
|
if Daemon.tncstarted:
|
||||||
output["daemon_state"].append({"status": "running"})
|
output["daemon_state"].append({"status": "running"})
|
||||||
else:
|
else:
|
||||||
output["daemon_state"].append({"status": "stopped"})
|
output["daemon_state"].append({"status": "stopped"})
|
||||||
|
@ -996,55 +995,55 @@ def send_tnc_state():
|
||||||
send the tnc state to network
|
send the tnc state to network
|
||||||
"""
|
"""
|
||||||
encoding = "utf-8"
|
encoding = "utf-8"
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"command": "tnc_state",
|
"command": "tnc_state",
|
||||||
"ptt_state": str(static.PTT_STATE),
|
"ptt_state": str(HamlibParam.ptt_state),
|
||||||
"tnc_state": str(static.TNC_STATE),
|
"tnc_state": str(TNC.tnc_state),
|
||||||
"arq_state": str(static.ARQ_STATE),
|
"arq_state": str(ARQ.arq_state),
|
||||||
"arq_session": str(static.ARQ_SESSION),
|
"arq_session": str(ARQ.arq_session),
|
||||||
"arq_session_state": str(static.ARQ_SESSION_STATE),
|
"arq_session_state": str(ARQ.arq_session_state),
|
||||||
"audio_dbfs": str(static.AUDIO_DBFS),
|
"audio_dbfs": str(AudioParam.audio_dbfs),
|
||||||
"snr": str(static.SNR),
|
"snr": str(ModemParam.snr),
|
||||||
"frequency": str(static.HAMLIB_FREQUENCY),
|
"frequency": str(HamlibParam.hamlib_frequency),
|
||||||
"rf_level": str(static.HAMLIB_RF),
|
"rf_level": str(HamlibParam.hamlib_rf),
|
||||||
"strength": str(static.HAMLIB_STRENGTH),
|
"strength": str(HamlibParam.hamlib_strength),
|
||||||
"alc": str(static.HAMLIB_ALC),
|
"alc": str(HamlibParam.alc),
|
||||||
"audio_level": str(static.TX_AUDIO_LEVEL),
|
"audio_level": str(AudioParam.tx_audio_level),
|
||||||
"audio_auto_tune": str(static.AUDIO_AUTO_TUNE),
|
"audio_auto_tune": str(AudioParam.audio_auto_tune),
|
||||||
"speed_level": str(static.ARQ_SPEED_LEVEL),
|
"speed_level": str(ARQ.arq_speed_level),
|
||||||
"mode": str(static.HAMLIB_MODE),
|
"mode": str(HamlibParam.hamlib_mode),
|
||||||
"bandwidth": str(static.HAMLIB_BANDWIDTH),
|
"bandwidth": str(HamlibParam.hamlib_bandwidth),
|
||||||
"fft": str(static.FFT),
|
"fft": str(AudioParam.fft),
|
||||||
"channel_busy": str(static.CHANNEL_BUSY),
|
"channel_busy": str(ModemParam.channel_busy),
|
||||||
"is_codec2_traffic": str(static.IS_CODEC2_TRAFFIC),
|
"channel_busy_slot": str(ModemParam.channel_busy_slot),
|
||||||
"scatter": static.SCATTER,
|
"is_codec2_traffic": str(ModemParam.is_codec2_traffic),
|
||||||
|
"scatter": ModemParam.scatter,
|
||||||
"rx_buffer_length": str(RX_BUFFER.qsize()),
|
"rx_buffer_length": str(RX_BUFFER.qsize()),
|
||||||
"rx_msg_buffer_length": str(len(static.RX_MSG_BUFFER)),
|
"rx_msg_buffer_length": str(len(ARQ.rx_msg_buffer)),
|
||||||
"arq_bytes_per_minute": str(static.ARQ_BYTES_PER_MINUTE),
|
"arq_bytes_per_minute": str(ARQ.bytes_per_minute),
|
||||||
"arq_bytes_per_minute_burst": str(static.ARQ_BYTES_PER_MINUTE_BURST),
|
"arq_bytes_per_minute_burst": str(ARQ.bytes_per_minute_burst),
|
||||||
"arq_seconds_until_finish": str(static.ARQ_SECONDS_UNTIL_FINISH),
|
"arq_seconds_until_finish": str(ARQ.arq_seconds_until_finish),
|
||||||
"arq_compression_factor": str(static.ARQ_COMPRESSION_FACTOR),
|
"arq_compression_factor": str(ARQ.arq_compression_factor),
|
||||||
"arq_transmission_percent": str(static.ARQ_TRANSMISSION_PERCENT),
|
"arq_transmission_percent": str(ARQ.arq_transmission_percent),
|
||||||
"speed_list": static.SPEED_LIST,
|
"speed_list": ARQ.speed_list,
|
||||||
"total_bytes": str(static.TOTAL_BYTES),
|
"total_bytes": str(ARQ.total_bytes),
|
||||||
"beacon_state": str(static.BEACON_STATE),
|
"beacon_state": str(Beacon.beacon_state),
|
||||||
"stations": [],
|
"stations": [],
|
||||||
"mycallsign": str(static.MYCALLSIGN, encoding),
|
"mycallsign": str(Station.mycallsign, encoding),
|
||||||
"mygrid": str(static.MYGRID, encoding),
|
"mygrid": str(Station.mygrid, encoding),
|
||||||
"dxcallsign": str(static.DXCALLSIGN, encoding),
|
"dxcallsign": str(Station.dxcallsign, encoding),
|
||||||
"dxgrid": str(static.DXGRID, encoding),
|
"dxgrid": str(Station.dxgrid, encoding),
|
||||||
"hamlib_status": static.HAMLIB_STATUS,
|
"hamlib_status": HamlibParam.hamlib_status,
|
||||||
"listen": str(static.LISTEN),
|
"listen": str(TNC.listen),
|
||||||
"audio_recording": str(static.AUDIO_RECORD),
|
"audio_recording": str(AudioParam.audio_record),
|
||||||
}
|
}
|
||||||
|
|
||||||
# add heard stations to heard stations object
|
# add heard stations to heard stations object
|
||||||
for heard in static.HEARD_STATIONS:
|
for heard in TNC.heard_stations:
|
||||||
output["stations"].append(
|
output["stations"].append(
|
||||||
{
|
{
|
||||||
"dxcallsign": str(heard[0], "utf-8"),
|
"dxcallsign": str(heard[0], encoding),
|
||||||
"dxgrid": str(heard[1], "utf-8"),
|
"dxgrid": str(heard[1], encoding),
|
||||||
"timestamp": heard[2],
|
"timestamp": heard[2],
|
||||||
"datatype": heard[3],
|
"datatype": heard[3],
|
||||||
"snr": heard[4],
|
"snr": heard[4],
|
||||||
|
|
214
tnc/static.py
214
tnc/static.py
|
@ -5,13 +5,188 @@ Created on Wed Dec 23 11:13:57 2020
|
||||||
|
|
||||||
@author: DJ2LS
|
@author: DJ2LS
|
||||||
Here we are saving application wide variables and stats, which have to be accessed everywhere.
|
Here we are saving application wide variables and stats, which have to be accessed everywhere.
|
||||||
Not nice, suggestions are appreciated :-)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import List
|
||||||
import subprocess
|
import subprocess
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
VERSION = "0.8.1-alpha"
|
|
||||||
|
# CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||||
|
# disconnected, connecting, connected, disconnecting, failed
|
||||||
|
# ------- RX BUFFER
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ARQ:
|
||||||
|
bytes_per_minute: int = 0
|
||||||
|
arq_transmission_percent: int = 0
|
||||||
|
arq_compression_factor: int = 0
|
||||||
|
arq_speed_level: int = 0
|
||||||
|
arq_bits_per_second_burst: int = 0
|
||||||
|
arq_bits_per_second: int = 0
|
||||||
|
arq_seconds_until_finish: int = 0
|
||||||
|
rx_buffer_size: int = 16
|
||||||
|
rx_frame_buffer: bytes = b""
|
||||||
|
rx_burst_buffer =[]
|
||||||
|
arq_session_state: str = "disconnected"
|
||||||
|
arq_session: bool = False
|
||||||
|
arq_state: bool = False
|
||||||
|
# ARQ PROTOCOL VERSION
|
||||||
|
# v.5 - signalling frame uses datac0
|
||||||
|
# v.6 - signalling frame uses datac13
|
||||||
|
arq_protocol_version: int = 6
|
||||||
|
total_bytes: int = 0
|
||||||
|
speed_list = []
|
||||||
|
# set save to folder state for allowing downloading files to local file system
|
||||||
|
arq_save_to_folder: bool = False
|
||||||
|
bytes_per_minute_burst: int = 0
|
||||||
|
rx_msg_buffer = []
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AudioParam:
|
||||||
|
tx_audio_level: int = 50
|
||||||
|
audio_input_devices = []
|
||||||
|
audio_output_devices = []
|
||||||
|
audio_input_device: int = -2
|
||||||
|
audio_output_device: int = -2
|
||||||
|
audio_record: bool = False
|
||||||
|
audio_record_file = ''
|
||||||
|
buffer_overflow_counter = []
|
||||||
|
audio_auto_tune: bool = False
|
||||||
|
# Audio TCI Support
|
||||||
|
audio_enable_tci: bool = False
|
||||||
|
audio_dbfs: int = 0
|
||||||
|
fft = []
|
||||||
|
enable_fft: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Beacon:
|
||||||
|
beacon_state: bool = False
|
||||||
|
beacon_pause: bool = False
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Channel:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Daemon:
|
||||||
|
tncprocess: subprocess.Popen
|
||||||
|
tncstarted: bool = False
|
||||||
|
port: int = 3001
|
||||||
|
serial_devices = []
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HamlibParam:
|
||||||
|
alc: int = 0
|
||||||
|
hamlib_frequency: int = 0
|
||||||
|
hamlib_strength: int = 0
|
||||||
|
hamlib_radiocontrol: str = "disabled"
|
||||||
|
hamlib_rigctld_ip: str = "127.0.0.1"
|
||||||
|
hamlib_rigctld_port: str = "4532"
|
||||||
|
ptt_state: bool = False
|
||||||
|
hamlib_bandwidth: int = 0
|
||||||
|
hamlib_status: str = "unknown/disconnected"
|
||||||
|
hamlib_mode: str = ""
|
||||||
|
hamlib_rf: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ModemParam:
|
||||||
|
tuning_range_fmin: float = -50.0
|
||||||
|
tuning_range_fmax: float = 50.0
|
||||||
|
channel_busy: bool = False
|
||||||
|
channel_busy_slot = [False] * 5
|
||||||
|
snr: float = 0
|
||||||
|
is_codec2_traffic: bool = False # true if we have codec2 signalling mode traffic on channel
|
||||||
|
frequency_offset: float = 0
|
||||||
|
tx_delay: int = 0 # delay in ms before sending modulation for triggering VOX for example or slow PTT radios
|
||||||
|
enable_scatter: bool = False
|
||||||
|
scatter = []
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Station:
|
||||||
|
mycallsign: bytes = b"AA0AA"
|
||||||
|
mycallsign_crc: bytes = b"A"
|
||||||
|
dxcallsign: bytes = b"ZZ9YY"
|
||||||
|
dxcallsign_crc: bytes = b"A"
|
||||||
|
mygrid: bytes = b""
|
||||||
|
dxgrid: bytes = b""
|
||||||
|
ssid_list = [] # ssid list we are responding to
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Statistics:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TCIParam:
|
||||||
|
ip: str = '127.0.0.1'
|
||||||
|
port: int = '9000'
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TNC:
|
||||||
|
version = "0.9.0-alpha-exp.6"
|
||||||
|
host: str = "0.0.0.0"
|
||||||
|
port: int = 3000
|
||||||
|
SOCKET_TIMEOUT: int = 1 # seconds
|
||||||
|
tnc_state: str = "IDLE"
|
||||||
|
enable_explorer = False
|
||||||
|
enable_stats = False
|
||||||
|
transmitting: bool = False
|
||||||
|
low_bandwidth_mode: bool = False
|
||||||
|
enable_fsk: bool = False
|
||||||
|
respond_to_cq: bool = True
|
||||||
|
respond_to_call: bool = True # respond to cq, ping, connection request, file request if not in session
|
||||||
|
heard_stations = []
|
||||||
|
listen: bool = True
|
||||||
|
|
||||||
|
# ------------
|
||||||
|
|
||||||
|
|
||||||
|
class FRAME_TYPE(Enum):
|
||||||
|
"""Lookup for frame types"""
|
||||||
|
|
||||||
|
BURST_01 = 10
|
||||||
|
BURST_02 = 11
|
||||||
|
BURST_03 = 12
|
||||||
|
BURST_04 = 13
|
||||||
|
# ...
|
||||||
|
BURST_51 = 50
|
||||||
|
BURST_ACK = 60
|
||||||
|
FR_ACK = 61
|
||||||
|
FR_REPEAT = 62
|
||||||
|
FR_NACK = 63
|
||||||
|
BURST_NACK = 64
|
||||||
|
CQ = 200
|
||||||
|
QRV = 201
|
||||||
|
PING = 210
|
||||||
|
PING_ACK = 211
|
||||||
|
IS_WRITING = 215
|
||||||
|
ARQ_SESSION_OPEN = 221
|
||||||
|
ARQ_SESSION_HB = 222
|
||||||
|
ARQ_SESSION_CLOSE = 223
|
||||||
|
ARQ_DC_OPEN_W = 225
|
||||||
|
ARQ_DC_OPEN_ACK_W = 226
|
||||||
|
ARQ_DC_OPEN_N = 227
|
||||||
|
ARQ_DC_OPEN_ACK_N = 228
|
||||||
|
ARQ_STOP = 249
|
||||||
|
BEACON = 250
|
||||||
|
FEC = 251
|
||||||
|
IDENT = 254
|
||||||
|
TEST_FRAME = 255
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# DON'T USE THESE SETTINGS ANYMORE
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# Fixme: REMOVE THESE OLD SETTINGS!
|
||||||
|
# REASON: For some reason ctests are failing when using dataclasses.
|
||||||
|
# We need to figure out whats happening and why the tests are failing.
|
||||||
|
|
||||||
|
|
||||||
|
CHANNEL_BUSY_SLOT = [False] * 5
|
||||||
|
|
||||||
|
|
||||||
ENABLE_EXPLORER = False
|
ENABLE_EXPLORER = False
|
||||||
ENABLE_STATS = False
|
ENABLE_STATS = False
|
||||||
|
@ -87,15 +262,15 @@ AUDIO_ENABLE_TCI: bool = False
|
||||||
TCI_IP: str = '127.0.0.1'
|
TCI_IP: str = '127.0.0.1'
|
||||||
TCI_PORT: int = '9000'
|
TCI_PORT: int = '9000'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AUDIO_DBFS: int = 0
|
AUDIO_DBFS: int = 0
|
||||||
FFT: list = [0]
|
FFT: list = [0]
|
||||||
ENABLE_FFT: bool = True
|
ENABLE_FFT: bool = True
|
||||||
CHANNEL_BUSY: bool = False
|
CHANNEL_BUSY: bool = False
|
||||||
|
|
||||||
# ARQ PROTOCOL VERSION
|
# ARQ PROTOCOL VERSION
|
||||||
ARQ_PROTOCOL_VERSION: int = 5
|
# v.5 - signalling frame uses datac0
|
||||||
|
# v.6 - signalling frame uses datac13
|
||||||
|
ARQ_PROTOCOL_VERSION: int = 6
|
||||||
|
|
||||||
# ARQ statistics
|
# ARQ statistics
|
||||||
SPEED_LIST: list = []
|
SPEED_LIST: list = []
|
||||||
|
@ -139,32 +314,3 @@ INFO: list = []
|
||||||
TUNING_RANGE_FMIN: float = -50.0
|
TUNING_RANGE_FMIN: float = -50.0
|
||||||
TUNING_RANGE_FMAX: float = 50.0
|
TUNING_RANGE_FMAX: float = 50.0
|
||||||
IS_CODEC2_TRAFFIC: bool = False # true if we have codec2 signalling mode traffic on channel
|
IS_CODEC2_TRAFFIC: bool = False # true if we have codec2 signalling mode traffic on channel
|
||||||
|
|
||||||
class FRAME_TYPE(Enum):
|
|
||||||
"""Lookup for frame types"""
|
|
||||||
|
|
||||||
BURST_01 = 10
|
|
||||||
# ...
|
|
||||||
BURST_51 = 50
|
|
||||||
BURST_ACK = 60
|
|
||||||
FR_ACK = 61
|
|
||||||
FR_REPEAT = 62
|
|
||||||
FR_NACK = 63
|
|
||||||
BURST_NACK = 64
|
|
||||||
CQ = 200
|
|
||||||
QRV = 201
|
|
||||||
PING = 210
|
|
||||||
PING_ACK = 211
|
|
||||||
IS_WRITING = 215
|
|
||||||
ARQ_SESSION_OPEN = 221
|
|
||||||
ARQ_SESSION_HB = 222
|
|
||||||
ARQ_SESSION_CLOSE = 223
|
|
||||||
ARQ_DC_OPEN_W = 225
|
|
||||||
ARQ_DC_OPEN_ACK_W = 226
|
|
||||||
ARQ_DC_OPEN_N = 227
|
|
||||||
ARQ_DC_OPEN_ACK_N = 228
|
|
||||||
ARQ_STOP = 249
|
|
||||||
BEACON = 250
|
|
||||||
FEC = 251
|
|
||||||
IDENT = 254
|
|
||||||
TEST_FRAME = 255
|
|
||||||
|
|
23
tnc/stats.py
23
tnc/stats.py
|
@ -13,6 +13,7 @@ import time
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import structlog
|
import structlog
|
||||||
import static
|
import static
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, TCIParam, TNC
|
||||||
|
|
||||||
log = structlog.get_logger("stats")
|
log = structlog.get_logger("stats")
|
||||||
|
|
||||||
|
@ -25,29 +26,29 @@ class stats():
|
||||||
crcerror = status in ["crc_error", "wrong_crc"]
|
crcerror = status in ["crc_error", "wrong_crc"]
|
||||||
# get avg snr
|
# get avg snr
|
||||||
try:
|
try:
|
||||||
snr_raw = [item["snr"] for item in static.SPEED_LIST]
|
snr_raw = [item["snr"] for item in ARQ.speed_list]
|
||||||
avg_snr = round(sum(snr_raw) / len(snr_raw), 2 )
|
avg_snr = round(sum(snr_raw) / len(snr_raw), 2 )
|
||||||
except Exception:
|
except Exception:
|
||||||
avg_snr = 0
|
avg_snr = 0
|
||||||
|
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
station_data = {
|
station_data = {
|
||||||
'callsign': str(static.MYCALLSIGN, "utf-8"),
|
'callsign': str(Station.mycallsign, "utf-8"),
|
||||||
'dxcallsign': str(static.DXCALLSIGN, "utf-8"),
|
'dxcallsign': str(Station.dxcallsign, "utf-8"),
|
||||||
'gridsquare': str(static.MYGRID, "utf-8"),
|
'gridsquare': str(Station.mygrid, "utf-8"),
|
||||||
'dxgridsquare': str(static.DXGRID, "utf-8"),
|
'dxgridsquare': str(Station.dxgrid, "utf-8"),
|
||||||
'frequency': 0 if static.HAMLIB_FREQUENCY is None else static.HAMLIB_FREQUENCY,
|
'frequency': 0 if HamlibParam.hamlib_frequency is None else HamlibParam.hamlib_frequency,
|
||||||
'avgstrength': 0,
|
'avgstrength': 0,
|
||||||
'avgsnr': avg_snr,
|
'avgsnr': avg_snr,
|
||||||
'bytesperminute': static.ARQ_BYTES_PER_MINUTE,
|
'bytesperminute': ARQ.bytes_per_minute,
|
||||||
'filesize': static.TOTAL_BYTES,
|
'filesize': ARQ.total_bytes,
|
||||||
'compressionfactor': static.ARQ_COMPRESSION_FACTOR,
|
'compressionfactor': ARQ.arq_compression_factor,
|
||||||
'nacks': frame_nack_counter,
|
'nacks': frame_nack_counter,
|
||||||
'crcerror': crcerror,
|
'crcerror': crcerror,
|
||||||
'duration': duration,
|
'duration': duration,
|
||||||
'percentage': static.ARQ_TRANSMISSION_PERCENT,
|
'percentage': ARQ.arq_transmission_percent,
|
||||||
'status': status,
|
'status': status,
|
||||||
'version': static.VERSION
|
'version': TNC.version
|
||||||
}
|
}
|
||||||
|
|
||||||
station_data = json.dumps(station_data)
|
station_data = json.dumps(station_data)
|
||||||
|
|
|
@ -7,8 +7,9 @@ import websocket
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import time
|
import time
|
||||||
from queues import AUDIO_TRANSMIT_QUEUE, AUDIO_RECEIVED_QUEUE
|
from queues import AUDIO_TRANSMIT_QUEUE, AUDIO_RECEIVED_QUEUE
|
||||||
|
from static import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, TCIParam, TNC
|
||||||
|
|
||||||
class TCI:
|
class TCICtrl:
|
||||||
def __init__(self, hostname='127.0.0.1', port=50001):
|
def __init__(self, hostname='127.0.0.1', port=50001):
|
||||||
# websocket.enableTrace(True)
|
# websocket.enableTrace(True)
|
||||||
self.log = structlog.get_logger("TCI")
|
self.log = structlog.get_logger("TCI")
|
||||||
|
|
Loading…
Reference in a new issue