This directory holds the pure-Python tooling that talks to the KV4P-HT radio firmware. It contains a reusable library that implements the serial protocol as well as a Tk-based GUI that demonstrates the end-to-end audio path.
kv4p_python/– production library with theRadioControllerclass and protocol helpers.radio_gui/– desktop GUI that exercises the controller, audio capture/playback, and PTT workflow.kiss_tnc/– headless KISS TCP TNC built on top of the KV4P radio controller.tests/–unittest-based regression checks for the protocol layer.requirements.txt– Python dependencies, including OPUS bindings (opuslib) used for 48 kHz audio.
-
Python 3.11+ (CPython recommended).
-
Host computer with a working serial connection to the KV4P hardware.
-
libopus installed on the system. macOS example:
brew install opus
If the dynamic library is not discovered automatically, export the path (macOS example):
export DYLD_LIBRARY_PATH="$(brew --prefix opus)/lib:${DYLD_LIBRARY_PATH}"
From the repository root:
python -m venv .venv
source .venv/bin/activate
python -m pip install -r python/requirements.txtThe requirements list includes pyserial, sounddevice, numpy, and opuslib. The controller will fall back gracefully if OPUS cannot be initialised, but audio TX/RX will not function without it.
-
Connect the KV4P radio via USB and note the serial port.
-
Export the port if you want to avoid typing it (optional):
export KV4P_PORT=/dev/tty.usbserial-xxxx -
Launch the GUI:
python -m radio_gui.app --debug
Select the port, open the connection, and use the “Set PTT Key” button to bind a keyboard shortcut. Hold the key to transmit; release to return to RX.
Launch the TCP KISS server (defaults to 127.0.0.1:8001):
python -m kiss_tnc --port /dev/tty.usbserial-xxxx --tx 144.390 --squelch 0 --log-level DEBUGAttach a KISS-aware client (e.g., direwolf -lp 8001 or any APRS application). The modem implements 1200 baud AFSK with simple demodulation suited for strong signals.
from kv4p_python import RadioController
with RadioController("COM3") as radio:
radio.initialize()
radio.tune_to_frequency("146.520", "146.520", tone=0, squelch_level=1)
radio.start_rx_mode()
# Listen for radio.add_audio_listener(...) callbacksThe controller sends frames using the KV4P-HT binary protocol (0xDEADBEEF delimiter, 48 kHz OPUS audio). Window updates from the firmware regulate the serial throughput automatically.
PYTHONPATH=python python -m unittest python.tests.test_radio_controllerThe suite validates frame construction, window accounting, and startup fallbacks without needing actual hardware.
- Audio runs at 48 kHz / 40 ms frames. The GUI’s audio engine produces 16-bit PCM data that the controller encodes into OPUS before transmission.
- The controller automatically falls back to RX if the firmware banner is not received but still respects window updates once they arrive.
- Keyboard PTT in the GUI incorporates a 150 ms debounce so OS-level key repeat does not toggle the transmitter.
- No audio TX/RX – verify
opuslibis installed, the system can locatelibopus, and the log shows “Firmware v…” followed by window updates. - Permission errors – ensure the user account can access the serial device (
/dev/tty.*on macOS,COMxon Windows,/dev/ttyUSB*on Linux). - Audio device discovery – the GUI uses
sounddevicewhich depends on PortAudio; install the package for your OS if devices are missing.
For protocol reference and firmware updates, see the microcontroller sources under ../kv4p-ht/microcontroller-src/.