ka9q-python 3.9.0__tar.gz → 3.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/CHANGELOG.md +77 -0
- {ka9q_python-3.9.0/ka9q_python.egg-info → ka9q_python-3.12.0}/PKG-INFO +38 -61
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/README.md +37 -60
- ka9q_python-3.12.0/docs/API_REFERENCE.md +936 -0
- ka9q_python-3.12.0/docs/ARCHITECTURE.md +376 -0
- ka9q_python-3.12.0/docs/CLI_GUIDE.md +288 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/docs/GETTING_STARTED.md +20 -6
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/docs/INSTALLATION.md +34 -14
- ka9q_python-3.12.0/docs/MULTI_STREAM.md +280 -0
- ka9q_python-3.12.0/docs/RECIPES.md +695 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/docs/RTP_TIMING_SUPPORT.md +31 -59
- ka9q_python-3.12.0/docs/SECURITY.md +54 -0
- ka9q_python-3.12.0/docs/TESTING_GUIDE.md +199 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/docs/TUI_GUIDE.md +28 -7
- ka9q_python-3.12.0/examples/spectrum_example.py +109 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/__init__.py +5 -1
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/cli.py +4 -2
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/compat.py +1 -1
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/control.py +166 -12
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/multi_stream.py +10 -0
- ka9q_python-3.12.0/ka9q/spectrum_stream.py +317 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/status.py +51 -3
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/tui.py +256 -14
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/types.py +2 -1
- {ka9q_python-3.9.0 → ka9q_python-3.12.0/ka9q_python.egg-info}/PKG-INFO +38 -61
- ka9q_python-3.12.0/ka9q_python.egg-info/SOURCES.txt +101 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q_radio_compat +1 -1
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/pyproject.toml +1 -1
- ka9q_python-3.12.0/scripts/check_upstream_drift.py +490 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/setup.py +1 -1
- ka9q_python-3.12.0/tests/conftest.py +29 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_channel_verification.py +1 -5
- ka9q_python-3.12.0/tests/test_decode_description.py +46 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_encode_socket.py +41 -51
- ka9q_python-3.12.0/tests/test_filter_edges.py +256 -0
- ka9q_python-3.12.0/tests/test_lifetime.py +175 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_native_discovery.py +4 -1
- ka9q_python-3.12.0/tests/test_spectrum.py +271 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_tune_debug.py +3 -2
- ka9q_python-3.12.0/tests/test_upstream_drift.py +176 -0
- ka9q_python-3.9.0/RELEASE_NOTES_v3.5.0.md +0 -75
- ka9q_python-3.9.0/docs/API_REFERENCE.md +0 -1438
- ka9q_python-3.9.0/docs/ARCHITECTURE.md +0 -534
- ka9q_python-3.9.0/docs/CHANGELOG.md +0 -378
- ka9q_python-3.9.0/docs/CROSS_PLATFORM_SUPPORT.md +0 -251
- ka9q_python-3.9.0/docs/DISTRIBUTION_RECOMMENDATION.md +0 -343
- ka9q_python-3.9.0/docs/MULTI_HOMED_QUICK_REF.md +0 -305
- ka9q_python-3.9.0/docs/NATIVE_DISCOVERY.md +0 -276
- ka9q_python-3.9.0/docs/PYPI_PUBLICATION_GUIDE.md +0 -404
- ka9q_python-3.9.0/docs/QUICK_REFERENCE.md +0 -233
- ka9q_python-3.9.0/docs/RTP_RECORDER_PASS_ALL_PACKETS.md +0 -512
- ka9q_python-3.9.0/docs/RTP_TIMING_IMPLEMENTATION.md +0 -439
- ka9q_python-3.9.0/docs/SECURITY.md +0 -876
- ka9q_python-3.9.0/docs/SSRC_COLLISION_PREVENTION.md +0 -1000
- ka9q_python-3.9.0/docs/TESTING_GUIDE.md +0 -347
- ka9q_python-3.9.0/docs/TESTING_SUMMARY.md +0 -133
- ka9q_python-3.9.0/docs/TEST_RESULTS.md +0 -262
- ka9q_python-3.9.0/docs/WEB_UI_ENHANCEMENT_GUIDE.md +0 -412
- ka9q_python-3.9.0/docs/WEB_UI_ENHANCEMENT_IMPLEMENTED.md +0 -184
- ka9q_python-3.9.0/docs/WEB_UI_ESCAPE_SEQUENCE_FIX.md +0 -78
- ka9q_python-3.9.0/docs/WEB_UI_FUNCTIONALITY_REVIEW.md +0 -355
- ka9q_python-3.9.0/docs/WEB_UI_IMPLEMENTATION_STATUS.md +0 -356
- ka9q_python-3.9.0/docs/WEB_UI_INTERACTIVE_COMPLETE.md +0 -333
- ka9q_python-3.9.0/docs/development/CHANGES_SUMMARY.md +0 -304
- ka9q_python-3.9.0/docs/development/CHANNEL_CLEANUP_ADDITION.md +0 -136
- ka9q_python-3.9.0/docs/development/CHANNEL_CLEANUP_COMPLETE.md +0 -224
- ka9q_python-3.9.0/docs/development/CHANNEL_TUNING_DIAGNOSTICS.md +0 -495
- ka9q_python-3.9.0/docs/development/CODE_REVIEW_RECOMMENDATIONS.md +0 -456
- ka9q_python-3.9.0/docs/development/CODE_REVIEW_SUMMARY.md +0 -318
- ka9q_python-3.9.0/docs/development/COMMIT_SUMMARY.md +0 -212
- ka9q_python-3.9.0/docs/development/CRITICAL_FIXES_CHECKLIST.md +0 -295
- ka9q_python-3.9.0/docs/development/FINAL_SUMMARY.md +0 -469
- ka9q_python-3.9.0/docs/development/FIXES_SUMMARY.md +0 -89
- ka9q_python-3.9.0/docs/development/GIT_STATUS_SUMMARY.md +0 -109
- ka9q_python-3.9.0/docs/development/IMPLEMENTATION_COMPLETE.md +0 -441
- ka9q_python-3.9.0/docs/development/IMPLEMENTATION_STATUS.md +0 -444
- ka9q_python-3.9.0/docs/development/IMPLEMENTATION_SUMMARY.md +0 -70
- ka9q_python-3.9.0/docs/development/IMPLEMENTATION_SUMMARY_v2.2.0.md +0 -348
- ka9q_python-3.9.0/docs/development/IMPROVEMENTS_IMPLEMENTED.md +0 -454
- ka9q_python-3.9.0/docs/development/MULTI_HOMED_ACTION_PLAN.md +0 -304
- ka9q_python-3.9.0/docs/development/MULTI_HOMED_IMPLEMENTATION_COMPLETE.md +0 -330
- ka9q_python-3.9.0/docs/development/MULTI_HOMED_SUPPORT_REVIEW.md +0 -471
- ka9q_python-3.9.0/docs/development/PACKAGE_STATUS.md +0 -257
- ka9q_python-3.9.0/docs/development/PACKAGE_VERIFICATION.md +0 -238
- ka9q_python-3.9.0/docs/development/PERFORMANCE_FIXES_APPLIED.md +0 -428
- ka9q_python-3.9.0/docs/development/PERFORMANCE_REVIEW.md +0 -762
- ka9q_python-3.9.0/docs/development/PERFORMANCE_REVIEW_V2.md +0 -776
- ka9q_python-3.9.0/docs/development/PERFORMANCE_SUMMARY.md +0 -203
- ka9q_python-3.9.0/docs/development/QUICK_ACTION_ITEMS.md +0 -370
- ka9q_python-3.9.0/docs/development/QUICK_START_DIAGNOSIS.md +0 -319
- ka9q_python-3.9.0/docs/development/RELEASE_CHECKLIST_v3.0.0.md +0 -133
- ka9q_python-3.9.0/docs/development/SUMMARY.md +0 -291
- ka9q_python-3.9.0/docs/development/SUMMARY_WEB_UI_FIXES.md +0 -153
- ka9q_python-3.9.0/docs/development/TUNE_IMPLEMENTATION.md +0 -291
- ka9q_python-3.9.0/docs/development/WEBUI_SUMMARY.md +0 -411
- ka9q_python-3.9.0/docs/development/WEB_UI_ENHANCEMENTS_COMPLETE.md +0 -198
- ka9q_python-3.9.0/docs/features/CONTROL_COMPARISON.md +0 -201
- ka9q_python-3.9.0/docs/features/DESTINATION_AWARE_CHANNELS.md +0 -73
- ka9q_python-3.9.0/docs/features/NEW_FEATURES.md +0 -239
- ka9q_python-3.9.0/docs/features/RADIOD_FEATURES_SUMMARY.md +0 -261
- ka9q_python-3.9.0/docs/features/RTP_DESTINATION_FEATURE.md +0 -237
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_INSTRUCTIONS.md +0 -196
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v2.2.0.md +0 -275
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v2.4.0.md +0 -269
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v2.5.0.md +0 -241
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v3.0.0.md +0 -148
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v3.1.0.md +0 -139
- ka9q_python-3.9.0/docs/releases/GITHUB_RELEASE_v3.2.0.md +0 -116
- ka9q_python-3.9.0/docs/releases/RELEASE_NOTES.md +0 -244
- ka9q_python-3.9.0/docs/releases/RELEASE_NOTES_v2.1.0.md +0 -291
- ka9q_python-3.9.0/docs/releases/RELEASE_NOTES_v2.2.0.md +0 -554
- ka9q_python-3.9.0/docs/releases/RELEASE_NOTES_v2.3.0.md +0 -297
- ka9q_python-3.9.0/docs/releases/RELEASE_NOTES_v2.4.0.md +0 -545
- ka9q_python-3.9.0/docs/releases/RTP_TIMING_RELEASE_NOTES.md +0 -281
- ka9q_python-3.9.0/ka9q_python.egg-info/SOURCES.txt +0 -160
- ka9q_python-3.9.0/tests/conftest.py +0 -14
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/LICENSE +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/MANIFEST.in +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/advanced_features_demo.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/channel_cleanup_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/codar_oceanography.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/diagnostics/diagnose_packets.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/diagnostics/repro_utc_bug.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/discover_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/grape_integration_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/hf_band_scanner.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/multi_stream_smoke.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/rtp_recorder_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/simple_am_radio.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/stream_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/superdarn_recorder.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/test_channel_operations.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/test_improvements.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/test_timing_fields.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/tune.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/examples/tune_example.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/addressing.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/discovery.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/exceptions.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/managed_stream.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/monitor.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/pps_calibrator.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/resequencer.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/rtp_recorder.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/stream.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/stream_quality.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q/utils.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q_python.egg-info/dependency_links.txt +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q_python.egg-info/entry_points.txt +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q_python.egg-info/requires.txt +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/ka9q_python.egg-info/top_level.txt +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/scripts/sync_types.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/setup.cfg +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/__init__.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_addressing.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_create_split_encoding.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_decode_functions.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_encode_functions.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_ensure_channel_encoding.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_integration.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_iq_20khz_f32.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_listen_multicast.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_managed_stream_recovery.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_monitor.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_multihomed.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_performance_fixes.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_protocol_compat.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_remove_channel.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_rtp_recorder.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_security_features.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_ssrc_dest_unit.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_ssrc_encoding_unit.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_ssrc_radiod_host_unit.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_status_decoder.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_ttl_warning.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_tune.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_tune_cli.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_tune_live.py +0 -0
- {ka9q_python-3.9.0 → ka9q_python-3.12.0}/tests/test_tune_method.py +0 -0
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.12.0] - 2026-05-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Spectrum bin vector decoding**: `decode_status_packet()` now decodes `BIN_DATA` (float32, `SPECT_DEMOD`) and `BIN_BYTE_DATA` (uint8, `SPECT2_DEMOD`) TLV vectors from radiod status packets. New fields on `SpectrumStatus`:
|
|
8
|
+
- `bin_data: Optional[np.ndarray]` — float32 power values per FFT bin.
|
|
9
|
+
- `bin_byte_data: Optional[np.ndarray]` — uint8 quantised log-power values.
|
|
10
|
+
- `bin_power_db` property — returns dB values regardless of source format (10*log10 for float data, `base + byte * step` for byte data).
|
|
11
|
+
|
|
12
|
+
- **`SpectrumStream`**: new class for receiving real-time FFT spectrum data from radiod. Spectrum data flows over the status multicast channel (port 5006) as TLV vectors, not over RTP. `SpectrumStream` handles channel creation, periodic polling, SSRC filtering, and delivers decoded `ChannelStatus` objects (with populated `spectrum.bin_power_db`) to an `on_spectrum` callback. Supports retuning via `set_frequency()` and context manager usage.
|
|
13
|
+
|
|
14
|
+
### Documentation
|
|
15
|
+
|
|
16
|
+
- API_REFERENCE.md: SpectrumStream section, SpectrumStatus bin vector fields, quickstart table updated.
|
|
17
|
+
- ARCHITECTURE.md: module listing, abstraction layer description, threading model updated.
|
|
18
|
+
- RECIPES.md: Recipe 5 covering spectrum display, spectrogram accumulation, frequency axis reconstruction, FFT parameter tuning, and combined audio+spectrum patterns.
|
|
19
|
+
- New `examples/spectrum_example.py`: runnable CLI example for real-time spectrum reception.
|
|
20
|
+
|
|
21
|
+
### Tests
|
|
22
|
+
|
|
23
|
+
- 13 new unit tests in `tests/test_spectrum.py` covering float32 and uint8 bin decoding, multi-byte TLV lengths, `bin_power_db` property, combined metadata+bins, edge cases, and import verification.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [3.11.0] - 2026-05-06
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **Channel filter overrides on create / ensure / add_channel**: optional `low_edge`, `high_edge`, and `kaiser_beta` kwargs on `RadiodControl.create_channel()`, `RadiodControl.ensure_channel()`, and `MultiStream.add_channel()` — when specified, the requested filter passband is applied inline with the channel-create command (no transient at preset BW), and on the reuse path of `ensure_channel`, `set_filter` is called so the requested edges are authoritative regardless of the channel's prior state. Previously, callers were stuck with the preset's `low`/`high` values and had to either author a custom radiod preset or call `set_filter` manually after channel creation. Filter edges are not part of the SSRC hash — multiple callers requesting the same channel with different filters reconfigure last-writer-wins, matching the existing model for `gain` / `agc_enable`.
|
|
33
|
+
- Motivating clients: hf-timestd's BPSK PPS calibrator needs ~±500 Hz to match the TS1 injector's effectively-CW spectrum (the iq preset's ±5 kHz is wrong by an order of magnitude); planned SuperDARN and CODAR-sounder receivers need wider passbands than any single preset provides.
|
|
34
|
+
|
|
35
|
+
### Backward Compatibility
|
|
36
|
+
|
|
37
|
+
- Default behavior unchanged: omitting all three kwargs produces a wire packet with no LOW_EDGE / HIGH_EDGE / KAISER_BETA tags, so radiod uses the preset's defaults exactly as before. Reuse path also skips `set_filter` when no filter args are supplied.
|
|
38
|
+
|
|
39
|
+
### Tests
|
|
40
|
+
|
|
41
|
+
- 8 new unit tests in `tests/test_filter_edges.py` cover encode-presence on each entry point, encode-absence when omitted, ensure_channel forwarding on the create path, and ensure_channel reuse-path calling set_filter (only when filter args are supplied).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## [3.10.0] - 2026-04-30
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- **Channel-lifetime keep-alive** (radiod 0f8b622+): support for ka9q-radio's new self-destruct timer, which lets a channel declare a lifetime in radiod main-loop frames (~50 Hz at the default 20 ms blocktime); 0 means infinite, >0 decrements every frame and destroys the channel at zero. This gives crash-resilient cleanup — if a client dies, its channels expire on their own instead of lingering on radiod.
|
|
50
|
+
- `RadiodControl.set_channel_lifetime(ssrc, lifetime)` — explicit poll that sends the LIFETIME tag, suitable as a periodic keep-alive.
|
|
51
|
+
- `RadiodControl.create_channel(..., lifetime=None)` — optional kwarg; sends LIFETIME on the creation packet when provided.
|
|
52
|
+
- `RadiodControl.ensure_channel(..., lifetime=None)` — passes through to `create_channel`; on the reuse path, calls `set_channel_lifetime` so the value is enforced regardless of the channel's prior state.
|
|
53
|
+
- `RadiodControl.tune(..., lifetime=None)` — optional kwarg; LIFETIME is included in the multi-parameter command buffer.
|
|
54
|
+
- `_decode_status_response()` exposes received LIFETIME as `status['lifetime']`; `ChannelStatus.lifetime` field.
|
|
55
|
+
- **`StatusType.LIFETIME = 117`** in `ka9q/types.py` (synced from ka9q-radio commit `5498aef`).
|
|
56
|
+
- **`StatusType.DESCRIPTION` decode** in `_decode_status_response()`: incoming front-end / channel description strings are now surfaced as `status['description']` (the encode side already existed via `set_description`).
|
|
57
|
+
|
|
58
|
+
### Backward Compatibility
|
|
59
|
+
|
|
60
|
+
- Default behavior unchanged: omitting `lifetime` produces a wire packet with no LIFETIME tag, so pre-`0f8b622` radiod stays compatible and existing clients see no change. Channels created without LIFETIME inherit radiod's template default (0 = infinite) and live until destroyed.
|
|
61
|
+
|
|
62
|
+
### Tests
|
|
63
|
+
|
|
64
|
+
- 10 new unit tests in `tests/test_lifetime.py` cover encode-presence on each entry point, encode-absence when omitted, and validation of negative / non-int inputs.
|
|
65
|
+
- Refreshed stale `tests/test_encode_socket.py` to match the current 6-byte wire format that radiod's `decode_socket()` actually expects.
|
|
66
|
+
- Hardened `tests/test_native_discovery.py::test_native_discovery_with_valid_packet` to mock `RadiodControl._connect`, removing the DNS dependency on `test.local`.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [3.9.0] - 2026-04-15
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- **`ka9q` CLI** (`ka9q/cli.py`): new console entry point `ka9q` (declared via `[project.scripts]`), exposing channel discovery, tune, create, destroy, and status commands against a running radiod.
|
|
75
|
+
- **Textual TUI** (`ka9q/tui.py`): an interactive Textual app for browsing channels and tuning interactively, with radiod and SSRC pickers. Optional install via `pip install ka9q-python[tui]`.
|
|
76
|
+
- **Typed `ChannelStatus` decoder** (`ka9q/status.py`): a typed dataclass view over the dict returned by `_decode_status_response`, so callers can use attribute access and IDE-completable fields instead of dict keys.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
3
80
|
## [3.8.0] - 2026-04-12
|
|
4
81
|
|
|
5
82
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ka9q-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.12.0
|
|
4
4
|
Summary: Python interface for ka9q-radio control and monitoring
|
|
5
5
|
Home-page: https://github.com/mijahauan/ka9q-python
|
|
6
6
|
Author: Michael Hauan AC0G
|
|
@@ -60,15 +60,15 @@ Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, S
|
|
|
60
60
|
|
|
61
61
|
## Features
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
- **Complete radiod API** — all 110+ TLV status/command parameters exposed, generated from ka9q-radio's C headers
|
|
64
|
+
- **Four stream abstractions** — `RTPRecorder` (raw packets), `RadiodStream` (samples + gap handling), `ManagedStream` (self-healing single channel), `MultiStream` (shared socket, many SSRCs)
|
|
65
|
+
- **Typed status decoder** — `ChannelStatus`, `FrontendStatus`, `PllStatus`, etc. with dotted-path field access
|
|
66
|
+
- **Precise RTP timing** — GPS_TIME / RTP_TIMESNAP for sample-accurate wallclock timestamps
|
|
67
|
+
- **LAN discovery** — enumerate radiod instances and their active channels via mDNS
|
|
68
|
+
- **CLI + TUI** — `ka9q list / query / set / tui` for interactive and scripted control
|
|
69
|
+
- **Multi-homed** — explicit interface selection for hosts with multiple NICs
|
|
70
|
+
- **Protocol drift detection** — pinned to a specific ka9q-radio commit, with a sync script
|
|
71
|
+
- **Pure Python** — NumPy is the only runtime dependency
|
|
72
72
|
|
|
73
73
|
## Installation
|
|
74
74
|
|
|
@@ -215,6 +215,7 @@ monitor.monitor_channel(
|
|
|
215
215
|
preset="usb",
|
|
216
216
|
sample_rate=12000
|
|
217
217
|
)
|
|
218
|
+
```
|
|
218
219
|
|
|
219
220
|
### Channel Cleanup (frequency = 0)
|
|
220
221
|
|
|
@@ -293,63 +294,39 @@ It auto-skips if `../ka9q-radio` is not present, so CI environments without the
|
|
|
293
294
|
|
|
294
295
|
## Documentation
|
|
295
296
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
- **[API Reference](docs/API_REFERENCE.md)
|
|
299
|
-
- **[
|
|
300
|
-
- **[
|
|
301
|
-
- **[
|
|
302
|
-
- **[
|
|
303
|
-
- **[
|
|
304
|
-
- **[
|
|
305
|
-
- **[Changelog](
|
|
306
|
-
- **[Release Notes](docs/releases/)**: Release-specific notes and instructions.
|
|
297
|
+
- **[Getting Started](docs/GETTING_STARTED.md)** — first-run walkthrough
|
|
298
|
+
- **[Recipes](docs/RECIPES.md)** — task-oriented cookbook: LAN probing, fixed-channel pipelines (WSPR/PSK/FT8/timing), nimble SWL-style retuning, and using ka9q-python across different SDRs
|
|
299
|
+
- **[API Reference](docs/API_REFERENCE.md)** — every public class, method, and function
|
|
300
|
+
- **[Architecture](docs/ARCHITECTURE.md)** — module layout, threading, protocol
|
|
301
|
+
- **[CLI Guide](docs/CLI_GUIDE.md)** — `ka9q list / query / set / tui` command reference
|
|
302
|
+
- **[TUI Guide](docs/TUI_GUIDE.md)** — the Textual terminal UI
|
|
303
|
+
- **[MultiStream Guide](docs/MULTI_STREAM.md)** — shared-socket multi-channel receiver
|
|
304
|
+
- **[RTP Timing](docs/RTP_TIMING_SUPPORT.md)** — GPS_TIME / RTP_TIMESNAP for sample-accurate timestamps
|
|
305
|
+
- **[Installation](docs/INSTALLATION.md)** · **[Testing](docs/TESTING_GUIDE.md)** · **[Security](docs/SECURITY.md)**
|
|
306
|
+
- **[Changelog](CHANGELOG.md)**
|
|
307
307
|
|
|
308
308
|
## Examples
|
|
309
309
|
|
|
310
|
-
See
|
|
311
|
-
|
|
312
|
-
-
|
|
313
|
-
-
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
- **`superdarn_recorder.py`** - Ionospheric radar monitoring
|
|
322
|
-
- **`codar_oceanography.py`** - Ocean current radar
|
|
323
|
-
- **`hf_band_scanner.py`** - Dynamic frequency scanner
|
|
324
|
-
- **`wspr_monitor.py`** - Weak signal propagation reporter
|
|
310
|
+
See [`examples/`](examples/) for runnable scripts:
|
|
311
|
+
|
|
312
|
+
- [`simple_am_radio.py`](examples/simple_am_radio.py) — minimal AM listener
|
|
313
|
+
- [`discover_example.py`](examples/discover_example.py) — channel discovery on the LAN
|
|
314
|
+
- [`stream_example.py`](examples/stream_example.py) — `RadiodStream` sample callback
|
|
315
|
+
- [`rtp_recorder_example.py`](examples/rtp_recorder_example.py) — precise-timing RTP recorder
|
|
316
|
+
- [`multi_stream_smoke.py`](examples/multi_stream_smoke.py) — `MultiStream` multi-SSRC receiver
|
|
317
|
+
- [`hf_band_scanner.py`](examples/hf_band_scanner.py) — dynamic band scanner
|
|
318
|
+
- [`channel_cleanup_example.py`](examples/channel_cleanup_example.py) — teardown via frequency=0
|
|
319
|
+
- [`tune.py`](examples/tune.py) — interactive tuning utility
|
|
320
|
+
- [`superdarn_recorder.py`](examples/superdarn_recorder.py), [`codar_oceanography.py`](examples/codar_oceanography.py), [`grape_integration_example.py`](examples/grape_integration_example.py) — domain-specific recorders
|
|
325
321
|
|
|
326
322
|
## Use Cases
|
|
327
323
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
-
|
|
331
|
-
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
- WSPR propagation studies
|
|
335
|
-
- SuperDARN ionospheric radar
|
|
336
|
-
- CODAR ocean current mapping
|
|
337
|
-
- Meteor scatter
|
|
338
|
-
- EME (moonbounce)
|
|
339
|
-
|
|
340
|
-
### Digital Modes
|
|
341
|
-
- FT8/FT4 monitoring
|
|
342
|
-
- RTTY/PSK decoding
|
|
343
|
-
- DRM digital radio
|
|
344
|
-
- HF fax reception
|
|
345
|
-
|
|
346
|
-
### Satellite Operations
|
|
347
|
-
- Downlink reception
|
|
348
|
-
- Doppler tracking
|
|
349
|
-
- Multi-frequency monitoring
|
|
350
|
-
|
|
351
|
-
### Custom Applications
|
|
352
|
-
**No assumptions!** Use for anything SDR-related.
|
|
324
|
+
See [docs/RECIPES.md](docs/RECIPES.md) for worked examples of:
|
|
325
|
+
|
|
326
|
+
- **LAN probing** — enumerate radiod instances and their active channels
|
|
327
|
+
- **Fixed-channel pipelines** — WSPR, PSK/FT8, HF timing (bundled band plans, `MultiStream`); see companion projects `wspr-recorder`, `psk-recorder`, `hf-timestd`
|
|
328
|
+
- **Nimble channel switching** — single-channel SWL-style retuning driven from the CLI or an app
|
|
329
|
+
- **SDR portability** — ka9q-python talks to `radiod`, which talks to the SDR; reporting frontend capabilities via `FrontendStatus`. Primary tested frontend is the RX888; AirspyR2 and Airspy HF+ support is in development.
|
|
353
330
|
|
|
354
331
|
## License
|
|
355
332
|
|
|
@@ -23,15 +23,15 @@ Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, S
|
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
- **Complete radiod API** — all 110+ TLV status/command parameters exposed, generated from ka9q-radio's C headers
|
|
27
|
+
- **Four stream abstractions** — `RTPRecorder` (raw packets), `RadiodStream` (samples + gap handling), `ManagedStream` (self-healing single channel), `MultiStream` (shared socket, many SSRCs)
|
|
28
|
+
- **Typed status decoder** — `ChannelStatus`, `FrontendStatus`, `PllStatus`, etc. with dotted-path field access
|
|
29
|
+
- **Precise RTP timing** — GPS_TIME / RTP_TIMESNAP for sample-accurate wallclock timestamps
|
|
30
|
+
- **LAN discovery** — enumerate radiod instances and their active channels via mDNS
|
|
31
|
+
- **CLI + TUI** — `ka9q list / query / set / tui` for interactive and scripted control
|
|
32
|
+
- **Multi-homed** — explicit interface selection for hosts with multiple NICs
|
|
33
|
+
- **Protocol drift detection** — pinned to a specific ka9q-radio commit, with a sync script
|
|
34
|
+
- **Pure Python** — NumPy is the only runtime dependency
|
|
35
35
|
|
|
36
36
|
## Installation
|
|
37
37
|
|
|
@@ -178,6 +178,7 @@ monitor.monitor_channel(
|
|
|
178
178
|
preset="usb",
|
|
179
179
|
sample_rate=12000
|
|
180
180
|
)
|
|
181
|
+
```
|
|
181
182
|
|
|
182
183
|
### Channel Cleanup (frequency = 0)
|
|
183
184
|
|
|
@@ -256,63 +257,39 @@ It auto-skips if `../ka9q-radio` is not present, so CI environments without the
|
|
|
256
257
|
|
|
257
258
|
## Documentation
|
|
258
259
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
- **[API Reference](docs/API_REFERENCE.md)
|
|
262
|
-
- **[
|
|
263
|
-
- **[
|
|
264
|
-
- **[
|
|
265
|
-
- **[
|
|
266
|
-
- **[
|
|
267
|
-
- **[
|
|
268
|
-
- **[Changelog](
|
|
269
|
-
- **[Release Notes](docs/releases/)**: Release-specific notes and instructions.
|
|
260
|
+
- **[Getting Started](docs/GETTING_STARTED.md)** — first-run walkthrough
|
|
261
|
+
- **[Recipes](docs/RECIPES.md)** — task-oriented cookbook: LAN probing, fixed-channel pipelines (WSPR/PSK/FT8/timing), nimble SWL-style retuning, and using ka9q-python across different SDRs
|
|
262
|
+
- **[API Reference](docs/API_REFERENCE.md)** — every public class, method, and function
|
|
263
|
+
- **[Architecture](docs/ARCHITECTURE.md)** — module layout, threading, protocol
|
|
264
|
+
- **[CLI Guide](docs/CLI_GUIDE.md)** — `ka9q list / query / set / tui` command reference
|
|
265
|
+
- **[TUI Guide](docs/TUI_GUIDE.md)** — the Textual terminal UI
|
|
266
|
+
- **[MultiStream Guide](docs/MULTI_STREAM.md)** — shared-socket multi-channel receiver
|
|
267
|
+
- **[RTP Timing](docs/RTP_TIMING_SUPPORT.md)** — GPS_TIME / RTP_TIMESNAP for sample-accurate timestamps
|
|
268
|
+
- **[Installation](docs/INSTALLATION.md)** · **[Testing](docs/TESTING_GUIDE.md)** · **[Security](docs/SECURITY.md)**
|
|
269
|
+
- **[Changelog](CHANGELOG.md)**
|
|
270
270
|
|
|
271
271
|
## Examples
|
|
272
272
|
|
|
273
|
-
See
|
|
274
|
-
|
|
275
|
-
-
|
|
276
|
-
-
|
|
277
|
-
-
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
- **`superdarn_recorder.py`** - Ionospheric radar monitoring
|
|
285
|
-
- **`codar_oceanography.py`** - Ocean current radar
|
|
286
|
-
- **`hf_band_scanner.py`** - Dynamic frequency scanner
|
|
287
|
-
- **`wspr_monitor.py`** - Weak signal propagation reporter
|
|
273
|
+
See [`examples/`](examples/) for runnable scripts:
|
|
274
|
+
|
|
275
|
+
- [`simple_am_radio.py`](examples/simple_am_radio.py) — minimal AM listener
|
|
276
|
+
- [`discover_example.py`](examples/discover_example.py) — channel discovery on the LAN
|
|
277
|
+
- [`stream_example.py`](examples/stream_example.py) — `RadiodStream` sample callback
|
|
278
|
+
- [`rtp_recorder_example.py`](examples/rtp_recorder_example.py) — precise-timing RTP recorder
|
|
279
|
+
- [`multi_stream_smoke.py`](examples/multi_stream_smoke.py) — `MultiStream` multi-SSRC receiver
|
|
280
|
+
- [`hf_band_scanner.py`](examples/hf_band_scanner.py) — dynamic band scanner
|
|
281
|
+
- [`channel_cleanup_example.py`](examples/channel_cleanup_example.py) — teardown via frequency=0
|
|
282
|
+
- [`tune.py`](examples/tune.py) — interactive tuning utility
|
|
283
|
+
- [`superdarn_recorder.py`](examples/superdarn_recorder.py), [`codar_oceanography.py`](examples/codar_oceanography.py), [`grape_integration_example.py`](examples/grape_integration_example.py) — domain-specific recorders
|
|
288
284
|
|
|
289
285
|
## Use Cases
|
|
290
286
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
- WSPR propagation studies
|
|
298
|
-
- SuperDARN ionospheric radar
|
|
299
|
-
- CODAR ocean current mapping
|
|
300
|
-
- Meteor scatter
|
|
301
|
-
- EME (moonbounce)
|
|
302
|
-
|
|
303
|
-
### Digital Modes
|
|
304
|
-
- FT8/FT4 monitoring
|
|
305
|
-
- RTTY/PSK decoding
|
|
306
|
-
- DRM digital radio
|
|
307
|
-
- HF fax reception
|
|
308
|
-
|
|
309
|
-
### Satellite Operations
|
|
310
|
-
- Downlink reception
|
|
311
|
-
- Doppler tracking
|
|
312
|
-
- Multi-frequency monitoring
|
|
313
|
-
|
|
314
|
-
### Custom Applications
|
|
315
|
-
**No assumptions!** Use for anything SDR-related.
|
|
287
|
+
See [docs/RECIPES.md](docs/RECIPES.md) for worked examples of:
|
|
288
|
+
|
|
289
|
+
- **LAN probing** — enumerate radiod instances and their active channels
|
|
290
|
+
- **Fixed-channel pipelines** — WSPR, PSK/FT8, HF timing (bundled band plans, `MultiStream`); see companion projects `wspr-recorder`, `psk-recorder`, `hf-timestd`
|
|
291
|
+
- **Nimble channel switching** — single-channel SWL-style retuning driven from the CLI or an app
|
|
292
|
+
- **SDR portability** — ka9q-python talks to `radiod`, which talks to the SDR; reporting frontend capabilities via `FrontendStatus`. Primary tested frontend is the RX888; AirspyR2 and Airspy HF+ support is in development.
|
|
316
293
|
|
|
317
294
|
## License
|
|
318
295
|
|