mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge remote-tracking branch 'origin/main' into issue_205_ping_no_call
This commit is contained in:
commit
9cb2cebddd
23 changed files with 303 additions and 226 deletions
2
.github/workflows/ctest.yml
vendored
2
.github/workflows/ctest.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install octave octave-common octave-signal sox python3 python3-pip portaudio19-dev python3-pyaudio
|
sudo apt-get install octave octave-common octave-signal sox python3 python3-pip portaudio19-dev python3-pyaudio
|
||||||
pip3 install psutil crcengine ujson pyserial numpy structlog miniaudio sounddevice
|
pip3 install psutil crcengine ujson pyserial numpy structlog sounddevice
|
||||||
pip3 install pytest pytest-rerunfailures
|
pip3 install pytest pytest-rerunfailures
|
||||||
|
|
||||||
- name: Build codec2
|
- name: Build codec2
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Test small (single-frame) and large (multi-frame) messages over a high quality
|
||||||
|
simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving data through the TNC and modem
|
||||||
|
and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC. Tests both low- and
|
||||||
|
high-bandwidth data frames (datac3 and datac1 respectively) from Codec2.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_chat_test_[12].py in separate processes to perform the data transfer.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
@ -33,7 +43,27 @@ bytes_out = b'{"dt":"f","fn":"zeit.txt","ft":"text\\/plain","d":"data:text\\/pla
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
"This is a test chat...",
|
"This is a test chat...",
|
||||||
"This is a much longer message, hopefully longer than each of the datac1 and datac3 frames available to use in this modem. This should be long enought, but to err on the side of completeness this will string on for many more words before coming to the long awaited conclusion. We are not at the concluding point just yet because there is still more space to be taken up in the datac3 frame. Perhaps now would be a good place to terminate this test message, but perhaps not because we need a few more bytes. Here then we stop. This compresses so well that I need more data, even more stuff than is already here and included in the unreadable diatribe below, or is it a soliloquy? MyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5CgMyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5Cg=MyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5CgMyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5CgMyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5Cg=",
|
"This is a much longer message, hopefully longer than each of the datac1 and "
|
||||||
|
"datac3 frames available to use in this modem. This should be long enough, "
|
||||||
|
"but to err on the side of completeness this will string on for many more "
|
||||||
|
"words before coming to the long awaited conclusion. We are not at the "
|
||||||
|
"concluding point just yet because there is still more space to be taken up "
|
||||||
|
"in the datac3 frame. Perhaps now would be a good place to terminate this test "
|
||||||
|
"message, but perhaps not because we need a few more bytes. Here then we stop. "
|
||||||
|
"This compresses so well that I need more data, even more stuff than is already "
|
||||||
|
"here and included in the unreadable diatribe below, or is it a soliloquy? "
|
||||||
|
"MyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obm"
|
||||||
|
"UgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5"
|
||||||
|
"NjY5NzY1NTU4Nzc4MjA5CgMyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0"
|
||||||
|
"MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG"
|
||||||
|
"9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5Cg=MyBtb2Rlcywgb2huZSBjbGFzcwowL"
|
||||||
|
"jAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODk"
|
||||||
|
"xMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5CgMyBtb2R"
|
||||||
|
"lcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjIgbW9kZXMsIG9obmUgY2xhc"
|
||||||
|
"3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY2xhc3MKMC4wMDA5NjY5NzY"
|
||||||
|
"1NTU4Nzc4MjA5CgMyBtb2Rlcywgb2huZSBjbGFzcwowLjAwMDk2OTQ4MTE4MDk5MTg0MTcKCjI"
|
||||||
|
"gbW9kZXMsIG9obmUgY2xhc3MKMC4wMDA5NjY1NDUxODkxMjI1Mzk0CgoxIG1vZGUsIG9obmUgY"
|
||||||
|
"2xhc3MKMC4wMDA5NjY5NzY1NTU4Nzc4MjA5Cg=",
|
||||||
]
|
]
|
||||||
PIPE_THREAD_RUNNING = True
|
PIPE_THREAD_RUNNING = True
|
||||||
|
|
||||||
|
@ -145,7 +175,7 @@ def test_chat_text(
|
||||||
STATIONS[0],
|
STATIONS[0],
|
||||||
STATIONS[1],
|
STATIONS[1],
|
||||||
messages[message_no],
|
messages[message_no],
|
||||||
True, # low bandwidth mode
|
freedv_mode == "datac3", # low bandwidth mode
|
||||||
tmp_path,
|
tmp_path,
|
||||||
),
|
),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
|
@ -159,7 +189,7 @@ def test_chat_text(
|
||||||
STATIONS[1],
|
STATIONS[1],
|
||||||
STATIONS[0],
|
STATIONS[0],
|
||||||
messages[message_no],
|
messages[message_no],
|
||||||
True, # low bandwidth mode
|
freedv_mode == "datac3", # low bandwidth mode
|
||||||
tmp_path,
|
tmp_path,
|
||||||
),
|
),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Test control frame commands over a high quality simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving select control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_datac0.py in separate process to perform the data transfer.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
@ -173,7 +181,6 @@ def analyze_results(station1: list, station2: list, call_list: list):
|
||||||
# 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.mark.flaky(reruns=2)
|
|
||||||
def test_datac0(frame_type: str, tmp_path):
|
def test_datac0(frame_type: str, tmp_path):
|
||||||
log_handler.setup_logging(filename=tmp_path / "test_datac0", level="DEBUG")
|
log_handler.setup_logging(filename=tmp_path / "test_datac0", level="DEBUG")
|
||||||
log = structlog.get_logger("test_datac0")
|
log = structlog.get_logger("test_datac0")
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests for the FreeDATA TNC state machine.
|
Unit test common helper routines used throughout the TNC.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses no other files.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests a high signal-to-noise ratio path with codec2 data formats using codec2 to transmit.
|
Test small multiple-burst messages over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving frames through the codec2 modem
|
||||||
|
and back through on the other station. Data injection initiates directly into
|
||||||
|
codec2 API. Tests all three codec2 data frames.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_rx.py, sox and freedv_data_raw_tx in separate processeses to perform
|
||||||
|
the audio tests.
|
||||||
|
|
||||||
|
@author: DJ2LS, N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=global-statement, invalid-name, unused-import
|
# pylint: disable=global-statement, invalid-name, unused-import
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests a high signal-to-noise ratio path with codec2 data formats using codec2 to receive.
|
Test small multiple-burst messages over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving frames through the codec2 modem
|
||||||
|
and back through on the other station. Data injection initiates directly into
|
||||||
|
codec2 API. Tests all three codec2 data frames.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_tx.py, sox, freedv_data_raw_rx and hexdump in separate processeses to
|
||||||
|
perform the audio tests.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=global-statement, invalid-name, unused-import
|
# pylint: disable=global-statement, invalid-name, unused-import
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests a high signal-to-noise ratio path with codec2 data formats.
|
Test small multiple-burst messages over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving frames through the codec2 modem
|
||||||
|
and back through on the other station. Data injection initiates directly into
|
||||||
|
codec2 API. Tests all three codec2 data frames.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_rx.py and util_tx.py in separate processeses to perform
|
||||||
|
the audio tests.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=global-statement, invalid-name, unused-import
|
# pylint: disable=global-statement, invalid-name, unused-import
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests a high signal-to-noise ratio path with multiple codec2 data formats.
|
Test small multiple-burst messages over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving frames through the codec2 modem
|
||||||
|
and back through on the other station. Data injection initiates directly into
|
||||||
|
codec2 API. Tests all three codec2 data frames simultaneously.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_multimode_tx.py and util_multimode_tx in separate processeses to perform
|
||||||
|
the audio tests.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=global-statement, invalid-name, unused-import
|
# pylint: disable=global-statement, invalid-name, unused-import
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
"""
|
|
||||||
Tests for the FreeDATA modem.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import multiprocessing
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
|
||||||
sys.path.insert(0, "..")
|
|
||||||
sys.path.insert(0, "../tnc")
|
|
||||||
import helpers
|
|
||||||
import modem
|
|
||||||
import static
|
|
||||||
|
|
||||||
|
|
||||||
def print_frame(data: bytearray):
|
|
||||||
"""
|
|
||||||
Pretty-print the provided frame.
|
|
||||||
|
|
||||||
:param data: Frame to be output
|
|
||||||
:type data: bytearray
|
|
||||||
"""
|
|
||||||
print(f"Type : {int(data[0])}")
|
|
||||||
print(f"DXCRC : {bytes(data[1:4])}")
|
|
||||||
print(f"CallCRC: {bytes(data[4:7])}")
|
|
||||||
print(f"Call : {helpers.bytes_to_callsign(data[7:13])}")
|
|
||||||
|
|
||||||
|
|
||||||
def t_create_frame(frame_type: int, mycall: str, dxcall: str) -> bytearray:
|
|
||||||
"""
|
|
||||||
Generate the requested frame.
|
|
||||||
|
|
||||||
:param frame_type: The numerical type of the desired frame.
|
|
||||||
:type frame_type: int
|
|
||||||
:param mycall: Callsign of the near station
|
|
||||||
:type mycall: str
|
|
||||||
:param dxcall: Callsign of the far station
|
|
||||||
:type dxcall: str
|
|
||||||
:return: Bytearray of the requested frame
|
|
||||||
:rtype: bytearray
|
|
||||||
"""
|
|
||||||
mycallsign_bytes = helpers.callsign_to_bytes(mycall)
|
|
||||||
mycallsign = helpers.bytes_to_callsign(mycallsign_bytes)
|
|
||||||
mycallsign_crc = helpers.get_crc_24(mycallsign)
|
|
||||||
|
|
||||||
dxcallsign_bytes = helpers.callsign_to_bytes(dxcall)
|
|
||||||
dxcallsign = helpers.bytes_to_callsign(dxcallsign_bytes)
|
|
||||||
dxcallsign_crc = helpers.get_crc_24(dxcallsign)
|
|
||||||
|
|
||||||
frame = bytearray(14)
|
|
||||||
frame[:1] = bytes([frame_type])
|
|
||||||
frame[1:4] = dxcallsign_crc
|
|
||||||
frame[4:7] = mycallsign_crc
|
|
||||||
frame[7:13] = mycallsign_bytes
|
|
||||||
|
|
||||||
return frame
|
|
||||||
|
|
||||||
|
|
||||||
def t_create_session_close(mycall: str, dxcall: str) -> bytearray:
|
|
||||||
"""
|
|
||||||
Generate the session_close frame.
|
|
||||||
|
|
||||||
:param mycall: Callsign of the near station
|
|
||||||
:type mycall: str
|
|
||||||
:param dxcall: Callsign of the far station
|
|
||||||
:type dxcall: str
|
|
||||||
:return: Bytearray of the requested frame
|
|
||||||
:rtype: bytearray
|
|
||||||
"""
|
|
||||||
return t_create_frame(223, mycall, dxcall)
|
|
||||||
|
|
||||||
|
|
||||||
def t_create_start_session(mycall: str, dxcall: str) -> bytearray:
|
|
||||||
"""
|
|
||||||
Generate the create_session frame.
|
|
||||||
|
|
||||||
:param mycall: Callsign of the near station
|
|
||||||
:type mycall: str
|
|
||||||
:param dxcall: Callsign of the far station
|
|
||||||
:type dxcall: str
|
|
||||||
:return: Bytearray of the requested frame
|
|
||||||
:rtype: bytearray
|
|
||||||
"""
|
|
||||||
return t_create_frame(221, mycall, dxcall)
|
|
||||||
|
|
||||||
|
|
||||||
def t_modem():
|
|
||||||
"""
|
|
||||||
Execute test to validate that receiving a session open frame sets the correct machine
|
|
||||||
state.
|
|
||||||
"""
|
|
||||||
t_mode = t_repeats = t_repeat_delay = 0
|
|
||||||
t_frames = []
|
|
||||||
|
|
||||||
def t_tx_dummy(mode, repeats, repeat_delay, frames):
|
|
||||||
"""Replacement function for transmit"""
|
|
||||||
print(f"t_tx_dummy: In transmit({mode}, {repeats}, {repeat_delay}, {frames})")
|
|
||||||
nonlocal t_mode, t_repeats, t_repeat_delay, t_frames
|
|
||||||
t_mode = mode
|
|
||||||
t_repeats = repeats
|
|
||||||
t_repeat_delay = repeat_delay
|
|
||||||
t_frames = frames[:]
|
|
||||||
static.TRANSMITTING = False
|
|
||||||
|
|
||||||
# enable testmode
|
|
||||||
modem.TESTMODE = True
|
|
||||||
modem.RXCHANNEL = "/tmp/hfchannel1"
|
|
||||||
modem.TXCHANNEL = "/tmp/hfchannel2"
|
|
||||||
static.HAMLIB_RADIOCONTROL = "disabled"
|
|
||||||
|
|
||||||
# Create the modem
|
|
||||||
local_modem = modem.RF()
|
|
||||||
|
|
||||||
# Replace transmit routine with our own, an effective No-Op.
|
|
||||||
local_modem.transmit = t_tx_dummy
|
|
||||||
|
|
||||||
txbuffer = t_create_start_session("AA9AA", "DC2EJ")
|
|
||||||
|
|
||||||
# Start the transmission
|
|
||||||
static.TRANSMITTING = True
|
|
||||||
modem.MODEM_TRANSMIT_QUEUE.put([14, 5, 250, txbuffer])
|
|
||||||
while static.TRANSMITTING:
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
# Check that the contents were transferred correctly.
|
|
||||||
assert t_mode == 14
|
|
||||||
assert t_repeats == 5
|
|
||||||
assert t_repeat_delay == 250
|
|
||||||
assert t_frames == txbuffer
|
|
||||||
|
|
||||||
|
|
||||||
def test_modem_queue():
|
|
||||||
proc = multiprocessing.Process(target=t_modem, args=())
|
|
||||||
# print("Starting threads.")
|
|
||||||
proc.start()
|
|
||||||
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
# print("Terminating threads.")
|
|
||||||
proc.terminate()
|
|
||||||
proc.join()
|
|
||||||
|
|
||||||
# print(f"\n{proc.exitcode=}")
|
|
||||||
assert proc.exitcode == 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Run pytest with the current script as the filename.
|
|
||||||
ecode = pytest.main(["-v", "-s", sys.argv[0]])
|
|
||||||
if ecode == 0:
|
|
||||||
print("errors: 0")
|
|
||||||
else:
|
|
||||||
print(ecode)
|
|
|
@ -1,5 +1,18 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Test connect frame commands over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Near end-to-end test for sending / receiving connection control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_tnc_I[RS]S.py in separate process to perform the data transfer.
|
||||||
|
|
||||||
|
@author: DJ2LS, N2KIQ
|
||||||
|
"""
|
||||||
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tests for the FreeDATA TNC state machine.
|
Test control frame messages over a high quality simulated audio channel.
|
||||||
|
|
||||||
|
Near end-to-end test for sending / receiving select control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Can be invoked from CMake, pytest, coverage or directly.
|
||||||
|
|
||||||
|
Uses util_datac0.py in separate process to perform the data transfer.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Send-side station emulator for connect frame tests over a high quality simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving connection control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Invoked from test_chat_text.py.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Receive-side station emulator for connect frame tests over a high quality simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving connection control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Invoked from test_chat_text.py.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Send- and receive-side station emulator for control frame tests over a high quality
|
||||||
|
simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
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
|
||||||
|
by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Invoked from test_datac0.py.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Receive-side station emulator for test frame tests over a high quality audio channel
|
||||||
|
using a physical sound card or STDIO.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving connection test frames through the codec2 and
|
||||||
|
back through on the other station. Data injection initiates directly through
|
||||||
|
the codec2 API. Tests all three codec2 data frames simultaneously.
|
||||||
|
|
||||||
|
Invoked from CMake, test_highsnr_stdio_P_P_multi.py, and many test_virtual[1-3]*.sh.
|
||||||
|
|
||||||
|
@author: DJ2LS
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Send-side station emulator for test frame tests over a high quality audio channel
|
||||||
|
using a physical sound card or STDIO.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving connection test frames through the codec2 and
|
||||||
|
back through on the other station. Data injection initiates directly through
|
||||||
|
the codec2 API. Tests all three codec2 data frames simultaneously.
|
||||||
|
|
||||||
|
Invoked from CMake, test_highsnr_stdio_P_P_multi.py, and many test_virtual[1-3]*.sh.
|
||||||
|
|
||||||
|
@author: DJ2LS
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Receive-side station emulator for test frame tests over a high quality audio channel
|
||||||
|
using a physical sound card or STDIO.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving connection test frames through the codec2 and
|
||||||
|
back through on the other station. Data injection initiates directly through
|
||||||
|
the codec2 API.
|
||||||
|
|
||||||
|
Invoked from CMake, test_highsnr_stdio_{P_C, P_P}_datacx.py, and many test_virtual[1-3]*.sh.
|
||||||
|
|
||||||
@author: DJ2LS
|
@author: DJ2LS
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Receive-side station emulator for connect frame tests over a high quality simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving connection control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Invoked from test_tnc.py.
|
||||||
|
|
||||||
|
@author: N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Wed Dec 23 07:04:24 2020
|
Send-side station emulator for connect frame tests over a high quality simulated audio channel.
|
||||||
|
|
||||||
@author: DJ2LS
|
Near end-to-end test for sending / receiving connection control frames through the
|
||||||
|
TNC and modem and back through on the other station. Data injection initiates from the
|
||||||
|
queue used by the daemon process into and out of the TNC.
|
||||||
|
|
||||||
|
Invoked from test_tnc.py.
|
||||||
|
|
||||||
|
@author: DJ2LS, N2KIQ
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Send-side station emulator for test frame tests over a high quality audio channel
|
||||||
|
using a physical sound card or STDIO.
|
||||||
|
|
||||||
|
Legacy test for sending / receiving connection test frames through the codec2 and
|
||||||
|
back through on the other station. Data injection initiates directly through
|
||||||
|
the codec2 API.
|
||||||
|
|
||||||
|
Invoked from CMake, test_highsnr_stdio_{P_C, P_P}_datacx.py, and many test_virtual[1-3]*.sh.
|
||||||
|
|
||||||
|
@author: DJ2LS
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
|
@ -2278,11 +2278,11 @@ class DATA:
|
||||||
"""
|
"""
|
||||||
# reset ARQ statistics
|
# reset ARQ statistics
|
||||||
static.ARQ_BYTES_PER_MINUTE_BURST = 0
|
static.ARQ_BYTES_PER_MINUTE_BURST = 0
|
||||||
static.ARQ_BYTES_PER_MINUTE = 0
|
static.ARQ_BYTES_PER_MINUTE = 0
|
||||||
static.ARQ_BITS_PER_SECOND_BURST = 0
|
static.ARQ_BITS_PER_SECOND_BURST = 0
|
||||||
static.ARQ_BITS_PER_SECOND = 0
|
static.ARQ_BITS_PER_SECOND = 0
|
||||||
static.ARQ_TRANSMISSION_PERCENT = 0
|
static.ARQ_TRANSMISSION_PERCENT = 0
|
||||||
static.TOTAL_BYTES = 0
|
static.TOTAL_BYTES = 0
|
||||||
|
|
||||||
def calculate_transfer_rate_tx(
|
def calculate_transfer_rate_tx(
|
||||||
self, tx_start_of_transmission: float, sentbytes: int, tx_buffer_length: int
|
self, tx_start_of_transmission: float, sentbytes: int, tx_buffer_length: int
|
||||||
|
|
|
@ -22,44 +22,47 @@ def setup_logging(filename: str = "", level: str = "DEBUG"):
|
||||||
timestamper,
|
timestamper,
|
||||||
]
|
]
|
||||||
|
|
||||||
logging.config.dictConfig(
|
config_dict = {
|
||||||
{
|
"version": 1,
|
||||||
"version": 1,
|
"disable_existing_loggers": False,
|
||||||
"disable_existing_loggers": False,
|
"formatters": {
|
||||||
"formatters": {
|
"plain": {
|
||||||
"plain": {
|
"()": structlog.stdlib.ProcessorFormatter,
|
||||||
"()": structlog.stdlib.ProcessorFormatter,
|
"processor": structlog.dev.ConsoleRenderer(colors=False),
|
||||||
"processor": structlog.dev.ConsoleRenderer(colors=False),
|
"foreign_pre_chain": pre_chain,
|
||||||
"foreign_pre_chain": pre_chain,
|
|
||||||
},
|
|
||||||
"colored": {
|
|
||||||
"()": structlog.stdlib.ProcessorFormatter,
|
|
||||||
"processor": structlog.dev.ConsoleRenderer(colors=True),
|
|
||||||
"foreign_pre_chain": pre_chain,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"handlers": {
|
"colored": {
|
||||||
"default": {
|
"()": structlog.stdlib.ProcessorFormatter,
|
||||||
"level": level,
|
"processor": structlog.dev.ConsoleRenderer(colors=True),
|
||||||
"class": "logging.StreamHandler",
|
"foreign_pre_chain": pre_chain,
|
||||||
"formatter": "colored",
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"level": level,
|
|
||||||
"class": "logging.handlers.WatchedFileHandler",
|
|
||||||
"filename": f"{filename}.log",
|
|
||||||
"formatter": "plain",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"loggers": {
|
},
|
||||||
"": {
|
"handlers": {
|
||||||
"handlers": ["default", "file"] if filename else ["default"],
|
"default": {
|
||||||
"level": level,
|
"level": level,
|
||||||
"propagate": True,
|
"class": "logging.StreamHandler",
|
||||||
},
|
"formatter": "colored",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
"loggers": {
|
||||||
|
"": {
|
||||||
|
"handlers": ["default"],
|
||||||
|
"level": level,
|
||||||
|
"propagate": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename:
|
||||||
|
config_dict["handlers"]["file"] = {
|
||||||
|
"level": level,
|
||||||
|
"class": "logging.handlers.WatchedFileHandler",
|
||||||
|
"filename": f"{filename}.log",
|
||||||
|
"formatter": "plain",
|
||||||
}
|
}
|
||||||
)
|
config_dict["loggers"][""]["handlers"].append("file")
|
||||||
|
|
||||||
|
logging.config.dictConfig(config_dict)
|
||||||
structlog.configure(
|
structlog.configure(
|
||||||
processors=[
|
processors=[
|
||||||
structlog.stdlib.add_log_level,
|
structlog.stdlib.add_log_level,
|
||||||
|
|
|
@ -9,6 +9,7 @@ Not nice, suggestions are appreciated :-)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
VERSION = "0.4.2-alpha"
|
VERSION = "0.4.2-alpha"
|
||||||
|
|
||||||
|
@ -123,3 +124,43 @@ INFO: list = []
|
||||||
# ------- CODEC2 SETTINGS
|
# ------- CODEC2 SETTINGS
|
||||||
TUNING_RANGE_FMIN: float = -50.0
|
TUNING_RANGE_FMIN: float = -50.0
|
||||||
TUNING_RANGE_FMAX: float = 50.0
|
TUNING_RANGE_FMAX: float = 50.0
|
||||||
|
|
||||||
|
|
||||||
|
class FRAME_TYPE(Enum):
|
||||||
|
"""Lookup for frame types"""
|
||||||
|
|
||||||
|
BURST_01 = 10
|
||||||
|
BURST_02 = 11
|
||||||
|
BURST_03 = 12
|
||||||
|
BURST_04 = 13
|
||||||
|
BURST_05 = 14
|
||||||
|
BURST_06 = 15
|
||||||
|
BURST_07 = 16
|
||||||
|
BURST_08 = 17
|
||||||
|
BURST_09 = 18
|
||||||
|
BURST_10 = 19
|
||||||
|
BURST_11 = 20
|
||||||
|
BURST_12 = 21
|
||||||
|
BURST_13 = 22
|
||||||
|
BURST_14 = 23
|
||||||
|
BURST_15 = 24
|
||||||
|
BURST_16 = 25
|
||||||
|
ACK = 60
|
||||||
|
FR_ACK = 61
|
||||||
|
FR_REPEAT = 62
|
||||||
|
FR_NACK = 63
|
||||||
|
BURST_NACK = 64
|
||||||
|
CQ = 200
|
||||||
|
QRV = 201
|
||||||
|
PING = 210
|
||||||
|
PING_ACK = 211
|
||||||
|
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
|
||||||
|
TEST_FRAME = 255
|
Loading…
Reference in a new issue