ka9q-python 3.4.2__tar.gz → 3.7.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.7.0/CHANGELOG.md +628 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/MANIFEST.in +11 -6
- {ka9q_python-3.4.2/ka9q_python.egg-info → ka9q_python-3.7.0}/PKG-INFO +59 -2
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/README.md +58 -1
- ka9q_python-3.7.0/RELEASE_NOTES_v3.5.0.md +75 -0
- ka9q_python-3.7.0/docs/API_REFERENCE.md +1438 -0
- ka9q_python-3.7.0/docs/ARCHITECTURE.md +534 -0
- ka9q_python-3.7.0/docs/CHANGELOG.md +354 -0
- ka9q_python-3.7.0/docs/CROSS_PLATFORM_SUPPORT.md +251 -0
- ka9q_python-3.7.0/docs/DISTRIBUTION_RECOMMENDATION.md +343 -0
- ka9q_python-3.7.0/docs/GETTING_STARTED.md +249 -0
- ka9q_python-3.7.0/docs/INSTALLATION.md +254 -0
- ka9q_python-3.7.0/docs/MULTI_HOMED_QUICK_REF.md +305 -0
- ka9q_python-3.7.0/docs/NATIVE_DISCOVERY.md +276 -0
- ka9q_python-3.7.0/docs/PYPI_PUBLICATION_GUIDE.md +404 -0
- ka9q_python-3.7.0/docs/QUICK_REFERENCE.md +233 -0
- ka9q_python-3.7.0/docs/RTP_RECORDER_PASS_ALL_PACKETS.md +512 -0
- ka9q_python-3.7.0/docs/RTP_TIMING_IMPLEMENTATION.md +439 -0
- ka9q_python-3.7.0/docs/RTP_TIMING_SUPPORT.md +173 -0
- ka9q_python-3.7.0/docs/SECURITY.md +876 -0
- ka9q_python-3.7.0/docs/SSRC_COLLISION_PREVENTION.md +1000 -0
- ka9q_python-3.7.0/docs/TESTING_GUIDE.md +347 -0
- ka9q_python-3.7.0/docs/TESTING_SUMMARY.md +133 -0
- ka9q_python-3.7.0/docs/TEST_RESULTS.md +262 -0
- ka9q_python-3.7.0/docs/WEB_UI_ENHANCEMENT_GUIDE.md +412 -0
- ka9q_python-3.7.0/docs/WEB_UI_ENHANCEMENT_IMPLEMENTED.md +184 -0
- ka9q_python-3.7.0/docs/WEB_UI_ESCAPE_SEQUENCE_FIX.md +78 -0
- ka9q_python-3.7.0/docs/WEB_UI_FUNCTIONALITY_REVIEW.md +355 -0
- ka9q_python-3.7.0/docs/WEB_UI_IMPLEMENTATION_STATUS.md +356 -0
- ka9q_python-3.7.0/docs/WEB_UI_INTERACTIVE_COMPLETE.md +333 -0
- ka9q_python-3.7.0/docs/development/CHANGES_SUMMARY.md +304 -0
- ka9q_python-3.7.0/docs/development/CHANNEL_CLEANUP_ADDITION.md +136 -0
- ka9q_python-3.7.0/docs/development/CHANNEL_CLEANUP_COMPLETE.md +224 -0
- ka9q_python-3.7.0/docs/development/CHANNEL_TUNING_DIAGNOSTICS.md +495 -0
- ka9q_python-3.7.0/docs/development/CODE_REVIEW_RECOMMENDATIONS.md +456 -0
- ka9q_python-3.7.0/docs/development/CODE_REVIEW_SUMMARY.md +318 -0
- ka9q_python-3.7.0/docs/development/COMMIT_SUMMARY.md +212 -0
- ka9q_python-3.7.0/docs/development/CRITICAL_FIXES_CHECKLIST.md +295 -0
- ka9q_python-3.7.0/docs/development/FINAL_SUMMARY.md +469 -0
- ka9q_python-3.7.0/docs/development/FIXES_SUMMARY.md +89 -0
- ka9q_python-3.7.0/docs/development/GIT_STATUS_SUMMARY.md +109 -0
- ka9q_python-3.7.0/docs/development/IMPLEMENTATION_COMPLETE.md +441 -0
- ka9q_python-3.7.0/docs/development/IMPLEMENTATION_STATUS.md +444 -0
- ka9q_python-3.7.0/docs/development/IMPLEMENTATION_SUMMARY.md +70 -0
- ka9q_python-3.7.0/docs/development/IMPLEMENTATION_SUMMARY_v2.2.0.md +348 -0
- ka9q_python-3.7.0/docs/development/IMPROVEMENTS_IMPLEMENTED.md +454 -0
- ka9q_python-3.7.0/docs/development/MULTI_HOMED_ACTION_PLAN.md +304 -0
- ka9q_python-3.7.0/docs/development/MULTI_HOMED_IMPLEMENTATION_COMPLETE.md +330 -0
- ka9q_python-3.7.0/docs/development/MULTI_HOMED_SUPPORT_REVIEW.md +471 -0
- ka9q_python-3.7.0/docs/development/PACKAGE_STATUS.md +257 -0
- ka9q_python-3.7.0/docs/development/PACKAGE_VERIFICATION.md +238 -0
- ka9q_python-3.7.0/docs/development/PERFORMANCE_FIXES_APPLIED.md +428 -0
- ka9q_python-3.7.0/docs/development/PERFORMANCE_REVIEW.md +762 -0
- ka9q_python-3.7.0/docs/development/PERFORMANCE_REVIEW_V2.md +776 -0
- ka9q_python-3.7.0/docs/development/PERFORMANCE_SUMMARY.md +203 -0
- ka9q_python-3.7.0/docs/development/QUICK_ACTION_ITEMS.md +370 -0
- ka9q_python-3.7.0/docs/development/QUICK_START_DIAGNOSIS.md +319 -0
- ka9q_python-3.7.0/docs/development/RELEASE_CHECKLIST_v3.0.0.md +133 -0
- ka9q_python-3.7.0/docs/development/SUMMARY.md +291 -0
- ka9q_python-3.7.0/docs/development/SUMMARY_WEB_UI_FIXES.md +153 -0
- ka9q_python-3.7.0/docs/development/TUNE_IMPLEMENTATION.md +291 -0
- ka9q_python-3.7.0/docs/development/WEBUI_SUMMARY.md +411 -0
- ka9q_python-3.7.0/docs/development/WEB_UI_ENHANCEMENTS_COMPLETE.md +198 -0
- ka9q_python-3.7.0/docs/features/CONTROL_COMPARISON.md +201 -0
- ka9q_python-3.7.0/docs/features/DESTINATION_AWARE_CHANNELS.md +73 -0
- ka9q_python-3.7.0/docs/features/NEW_FEATURES.md +239 -0
- ka9q_python-3.7.0/docs/features/RADIOD_FEATURES_SUMMARY.md +261 -0
- ka9q_python-3.7.0/docs/features/RTP_DESTINATION_FEATURE.md +237 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_INSTRUCTIONS.md +196 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v2.2.0.md +275 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v2.4.0.md +269 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v2.5.0.md +241 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v3.0.0.md +148 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v3.1.0.md +139 -0
- ka9q_python-3.7.0/docs/releases/GITHUB_RELEASE_v3.2.0.md +116 -0
- ka9q_python-3.7.0/docs/releases/RELEASE_NOTES.md +244 -0
- ka9q_python-3.7.0/docs/releases/RELEASE_NOTES_v2.1.0.md +291 -0
- ka9q_python-3.7.0/docs/releases/RELEASE_NOTES_v2.2.0.md +554 -0
- ka9q_python-3.7.0/docs/releases/RELEASE_NOTES_v2.3.0.md +297 -0
- ka9q_python-3.7.0/docs/releases/RELEASE_NOTES_v2.4.0.md +545 -0
- ka9q_python-3.7.0/docs/releases/RTP_TIMING_RELEASE_NOTES.md +281 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/__init__.py +11 -2
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/addressing.py +32 -10
- ka9q_python-3.7.0/ka9q/compat.py +15 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/control.py +42 -30
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/discovery.py +2 -3
- ka9q_python-3.7.0/ka9q/pps_calibrator.py +314 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/rtp_recorder.py +7 -1
- ka9q_python-3.7.0/ka9q/types.py +186 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0/ka9q_python.egg-info}/PKG-INFO +59 -2
- ka9q_python-3.7.0/ka9q_python.egg-info/SOURCES.txt +152 -0
- ka9q_python-3.7.0/ka9q_radio_compat +3 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/pyproject.toml +1 -1
- ka9q_python-3.7.0/scripts/sync_types.py +440 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/setup.py +1 -1
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_addressing.py +18 -0
- ka9q_python-3.7.0/tests/test_protocol_compat.py +82 -0
- ka9q_python-3.7.0/tests/test_ssrc_radiod_host_unit.py +61 -0
- ka9q_python-3.4.2/ka9q/types.py +0 -175
- ka9q_python-3.4.2/ka9q_python.egg-info/SOURCES.txt +0 -69
- ka9q_python-3.4.2/tests/test_decode_description.py +0 -46
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/LICENSE +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/advanced_features_demo.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/channel_cleanup_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/codar_oceanography.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/diagnostics/diagnose_packets.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/diagnostics/repro_utc_bug.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/discover_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/grape_integration_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/hf_band_scanner.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/rtp_recorder_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/simple_am_radio.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/stream_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/superdarn_recorder.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/test_channel_operations.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/test_improvements.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/test_timing_fields.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/tune.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/examples/tune_example.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/exceptions.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/managed_stream.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/monitor.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/resequencer.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/stream.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/stream_quality.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q/utils.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q_python.egg-info/dependency_links.txt +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q_python.egg-info/requires.txt +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/ka9q_python.egg-info/top_level.txt +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/setup.cfg +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/__init__.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/conftest.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_channel_verification.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_create_split_encoding.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_decode_functions.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_encode_functions.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_encode_socket.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_ensure_channel_encoding.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_integration.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_iq_20khz_f32.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_listen_multicast.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_managed_stream_recovery.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_monitor.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_multihomed.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_native_discovery.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_performance_fixes.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_remove_channel.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_rtp_recorder.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_security_features.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_ssrc_dest_unit.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_ssrc_encoding_unit.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_ttl_warning.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_tune.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_tune_cli.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_tune_debug.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_tune_live.py +0 -0
- {ka9q_python-3.4.2 → ka9q_python-3.7.0}/tests/test_tune_method.py +0 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [3.7.0] - 2026-04-12
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Radiod-aware multicast addressing**: `generate_multicast_ip()` now accepts a `radiod_host` keyword argument. When provided, the hash is computed over both the client identifier and the radiod host, producing a distinct multicast IP for each (client, radiod) pair. This prevents address collisions when the same client application (e.g., `hf-timestd`) connects to multiple radiod instances simultaneously.
|
|
8
|
+
- **Radiod-aware SSRC allocation**: `allocate_ssrc()` now accepts a `radiod_host` parameter, included in the deterministic hash. The same channel parameters on different radiod instances produce distinct SSRCs.
|
|
9
|
+
- **Automatic radiod identity propagation**: `RadiodControl.create_channel()` and `RadiodControl.ensure_channel()` automatically pass `self.status_address` as `radiod_host` when computing SSRCs. No API changes needed for callers using the `RadiodControl` methods — radiod-aware uniqueness is automatic.
|
|
10
|
+
|
|
11
|
+
### Backward Compatibility
|
|
12
|
+
|
|
13
|
+
- `generate_multicast_ip(unique_id)` without `radiod_host` produces identical results to v3.6.0.
|
|
14
|
+
- `allocate_ssrc()` without `radiod_host` changes the hash format (trailing separator added), so SSRC values will differ from v3.6.0 for existing deployments. This is intentional — channels will be re-created with new SSRCs on upgrade. The old SSRCs were not radiod-aware and could collide when a client talked to multiple radiod instances.
|
|
15
|
+
- `ManagedStream`, `RadiodStream`, and `RTPRecorder` require no changes — they receive the already-computed SSRC/address via `ChannelInfo`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [3.6.0] - 2026-04-09
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **L6 BPSK PPS chain-delay calibration** (`ka9q/pps_calibrator.py`): New utility module for measuring end-to-end RF-to-RTP chain delay using a local GPS-disciplined BPSK PPS injector (WB6CXC design). Three new public classes:
|
|
24
|
+
- `BpskPpsCalibrator` — detects PPS edges in BPSK IQ streams via phase-transition detection, validates timing consistency, and reports the measured chain delay once locked. Algorithm ported from Scott Newell's wd-record.c `bpsk_state_machine()`.
|
|
25
|
+
- `PpsCalibrationResult` — dataclass returned by the calibrator with `chain_delay_ns`, `chain_delay_samples`, edge counters, and lock status.
|
|
26
|
+
- `NotchFilter500Hz` — biquad IIR notch filter at 500 Hz for interference rejection on the BPSK channel.
|
|
27
|
+
- **`ChannelInfo.chain_delay_correction_ns`** (`ka9q/discovery.py`): New optional field. When set, `rtp_to_wallclock()` automatically subtracts this correction from the computed wall time, compensating for the measured RF/ADC/DSP/RTP chain latency. Defaults to `None` (no correction; backward compatible).
|
|
28
|
+
- All three new classes exported from `ka9q/__init__.py`.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **`rtp_to_wallclock()`** (`ka9q/rtp_recorder.py`): Now applies `channel.chain_delay_correction_ns` when present. Existing callers are unaffected (the field defaults to `None`).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## [3.5.1] - 2026-04-09
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **`DemodType` enum** (`ka9q/types.py`): New auto-generated class mirroring `enum demod_type` from ka9q-radio `radio.h`. Exposes `LINEAR_DEMOD`, `FM_DEMOD`, `WFM_DEMOD`, `SPECT_DEMOD`, `SPECT2_DEMOD`, and `N_DEMOD`.
|
|
41
|
+
- **`WindowType` enum** (`ka9q/types.py`): New auto-generated class mirroring `enum window_type` from ka9q-radio `window.h`. Exposes all 9 FFT window types (`KAISER_WINDOW` through `HP5FT_WINDOW`) plus `N_WINDOW` sentinel.
|
|
42
|
+
- Both new types are exported from `ka9q/__init__.py` and tracked by the drift detection system.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **`set_demod_type()` validation**: Was rejecting demod_type=4 (`SPECT2_DEMOD`), the spectrum v2 mode added in ka9q-radio. Validation range corrected from 0-3 to 0-4.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- **`sync_types.py` expanded**: Now parses 4 C headers (`status.h`, `rtp.h`, `radio.h`, `window.h`) instead of 2. Drift detection covers `DemodType` and `WindowType` in addition to `StatusType` and `Encoding`. The `_check_enum()` helper replaces duplicated per-enum comparison logic.
|
|
51
|
+
- **Compatibility pin bumped** to ka9q-radio `d39fea8` (no protocol-level changes from previous pin `6b0fec7`; intervening commits were wd-record and bug fixes).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## [3.5.0] - 2026-03-31
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **Protocol Drift Detection** (`scripts/sync_types.py`): New tool that code-generates `ka9q/types.py` from the ka9q-radio C headers (`status.h`, `rtp.h`). Three modes:
|
|
60
|
+
- `--check`: exits non-zero if `types.py` is out of sync (for CI and tests)
|
|
61
|
+
- `--apply`: regenerates `types.py` and updates compatibility pins
|
|
62
|
+
- `--diff`: dry-run showing what would change
|
|
63
|
+
- **Compatibility Pin** (`ka9q_radio_compat`): Tracked plain-text file recording the ka9q-radio commit hash that `types.py` was last validated against.
|
|
64
|
+
- **Importable Pin** (`ka9q/compat.py`): `KA9Q_RADIO_COMMIT` constant for use by deployment tooling (e.g. `ka9q-update`).
|
|
65
|
+
- **Drift Test** (`tests/test_protocol_compat.py`): Pytest test that runs `sync_types.py --check` and verifies the pin matches ka9q-radio HEAD. Auto-skips when ka9q-radio source is not present.
|
|
66
|
+
- **New StatusType**: `SPECTRUM_OVERLAP` (116) for FFT window overlap control.
|
|
67
|
+
- **New Encodings**: `MULAW` (10), `ALAW` (11) for telephony-grade audio.
|
|
68
|
+
- **`set_max_delay()`**: New control method replacing `set_packet_buffering()`. Sets maximum aggregation delay in blocks (0-5).
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **StatusType renames** (matching ka9q-radio HEAD):
|
|
73
|
+
- `MINPACKET` → `MAXDELAY`
|
|
74
|
+
- `GAINSTEP` → `UNUSED4`
|
|
75
|
+
- `CONVERTER_OFFSET` → `UNUSED3`
|
|
76
|
+
- `COHERENT_BIN_SPACING` → `UNUSED2`
|
|
77
|
+
- `BLOCKS_SINCE_POLL` → `UNUSED`
|
|
78
|
+
- **Encoding**: `UNUSED_ENCODING` sentinel shifted from 10 to 12.
|
|
79
|
+
- `types.py` is now auto-generated with C header comments preserved.
|
|
80
|
+
|
|
81
|
+
### Removed
|
|
82
|
+
|
|
83
|
+
- `compare_encodings.py` and `compare_status_types.py` (replaced by `scripts/sync_types.py`).
|
|
84
|
+
|
|
85
|
+
### Backward Compatibility
|
|
86
|
+
|
|
87
|
+
- `set_packet_buffering()` retained as a deprecated alias for `set_max_delay()`.
|
|
88
|
+
- `Encoding.F32` and `Encoding.F16` aliases retained for `F32LE` and `F16LE`.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## [3.4.2] - 2026-02-05
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
- **Comprehensive Getting Started Guide**: Added a new `docs/GETTING_STARTED.md` file. This guide provides a step-by-step tutorial for new users, covering installation, a simple first program, core concepts, and troubleshooting tips. It is now the recommended entry point for new users.
|
|
97
|
+
- **Examples README**: Added a new `examples/README.md` file to organize the examples directory. It categorizes examples by complexity (basic, intermediate, advanced) and provides a recommended learning path, making it easier for users to find relevant examples.
|
|
98
|
+
|
|
99
|
+
### Fixed
|
|
100
|
+
|
|
101
|
+
- **`stream_example.py` Bug**: Fixed a critical bug in `examples/stream_example.py` where the code incorrectly iterated over the dictionary returned by `discover_channels`. The example now correctly accesses `ChannelInfo` objects, preventing an `AttributeError` and allowing the example to run as intended.
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- **Updated API Documentation**: The documentation for `create_channel` in `docs/API_REFERENCE.md` has been updated to match the actual implementation. This includes adding the `destination` and `encoding` parameters, correcting the parameter order, and documenting the return type (`int` SSRC).
|
|
106
|
+
- **Updated README**: The main `README.md` has been updated to link to the new Getting Started guide.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## [3.4.1] - 2026-01-27
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- **Stable SSRC Allocation**: Replaced unstable Python `hash()` with `hashlib.sha256` in `allocate_ssrc()`. This ensure SSRCs remain consistent across process restarts, allowing `radiod` to reuse existing receivers and preventing resource exhaustion.
|
|
115
|
+
|
|
116
|
+
## [3.4.0] - 2026-01-13
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- **TTL Reporting**: Implemented decoding of `OUTPUT_TTL` (status type 19) from `radiod`.
|
|
121
|
+
- **TTL Warning**: Added a warning log when `radiod` reports a TTL of 0, indicating multicast restrictions.
|
|
122
|
+
- **Web API**: Exposed the `ttl` value in the `/api/channel/<address>/<ssrc>` endpoint.
|
|
123
|
+
- **Tests**: Added unit and integration tests for TTL decoding and warning logic.
|
|
124
|
+
|
|
125
|
+
### Fixed
|
|
126
|
+
|
|
127
|
+
- **Web UI Start Script**: Fixed `webui/start.sh` to correctly locate `app.py` when running from outside the `webui` directory.
|
|
128
|
+
|
|
129
|
+
## [3.2.7] - 2025-12-17
|
|
130
|
+
|
|
131
|
+
### Added
|
|
132
|
+
|
|
133
|
+
- **ChannelMonitor**: New service that provides automatic recovery from `radiod` restarts. It monitors registered channels and automatically invokes `ensure_channel` to restore them if they disappear.
|
|
134
|
+
- Usage: `monitor = ChannelMonitor(control); monitor.start(); monitor.monitor_channel(...)`
|
|
135
|
+
|
|
136
|
+
## [3.2.6] - 2025-12-17
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- **Output Encoding Support**: Added complete support for specifying output encoding (e.g., F32, S16LE, OPUS) in `ensure_channel` and `create_channel`.
|
|
141
|
+
- `create_channel` now automatically sends the required follow-up `OUTPUT_ENCODING` command to `radiod`.
|
|
142
|
+
- `ensure_channel` verifies the encoding of existing channels and reconfigures them if different from the requested encoding.
|
|
143
|
+
- `ChannelInfo` now includes the `encoding` field for discovered channels.
|
|
144
|
+
|
|
145
|
+
## [3.2.5] - 2025-12-17
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
|
|
149
|
+
- **Destination-Aware Channels**: `ka9q-python` now supports unique destination IP addresses per client application. The `ensure_channel` and `create_channel` methods now accept a `destination` parameter.
|
|
150
|
+
- **Unique IP Generation**: Added `generate_multicast_ip(unique_id)` helper function to deterministically map application IDs to the `239.0.0.0/8` multicast range.
|
|
151
|
+
- **Improved SSRC Allocation**: `allocate_ssrc` now includes the destination address in its hash calculation, ensuring that streams with different destinations get unique SSRCs.
|
|
152
|
+
|
|
153
|
+
## [3.2.4] - 2025-12-16
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
157
|
+
- **Resequencer Fragmented IQ Support** - Fixed resequencer to correctly handle fragmented IQ packets from radiod. The resequencer now uses actual packet sample count for timestamp tracking instead of the fixed `samples_per_packet` value. This prevents false gap detection when radiod fragments large IQ payloads (e.g., IQ 20kHz F32 fragments into 1440+1440+320 byte packets). Affects `_try_output()`, `_handle_lost_packet()`, and `flush()` methods.
|
|
158
|
+
|
|
159
|
+
### Added
|
|
160
|
+
|
|
161
|
+
- **Channel Verification Test Suite** - Comprehensive test suite (`tests/test_channel_verification.py`) that verifies radiod channel creation, encoding, sample rate, and destination configuration. Demonstrates ka9q-python usage patterns and serves as integration test.
|
|
162
|
+
|
|
163
|
+
## [3.2.3] - 2025-12-16
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- **Socket Reconnection Vulnerability** - Fixed vulnerability where socket errors would terminate the receive loop permanently. Both `RadiodStream` and `RTPRecorder` now implement automatic reconnection with exponential backoff (1s to 60s max). This provides robustness against network interface restarts, multicast group membership drops, and transient network errors.
|
|
168
|
+
|
|
169
|
+
## [3.2.2] - 2025-12-13
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
|
|
173
|
+
- **Time Calculation** - Fixed 18-second error in UTC timestamp calculation caused by leap seconds. `rtp_to_wallclock()` now correctly subtracts the current 18-second GPS-UTC offset.
|
|
174
|
+
|
|
175
|
+
## [3.2.1] - 2025-12-11
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
|
|
179
|
+
- **Time Calculation** - Fixed GPS-to-Unix time conversion in `rtp_to_wallclock()`. Previous formula incorrectly applied NTP epoch offset, resulting in future timestamps.
|
|
180
|
+
- **Documentation** - Updated `RTP_TIMING_SUPPORT.md` with the correct formula.
|
|
181
|
+
|
|
182
|
+
## [3.2.0] - 2025-12-01
|
|
183
|
+
|
|
184
|
+
### 🌊 RadiodStream API - Continuous Sample Delivery with Quality Tracking
|
|
185
|
+
|
|
186
|
+
This release adds a high-level streaming API that delivers continuous sample streams with comprehensive quality metadata. Designed for applications like GRAPE, WSPR, CODAR, and SuperDARN that need reliable data capture with gap detection and quality metrics.
|
|
187
|
+
|
|
188
|
+
### Added
|
|
189
|
+
|
|
190
|
+
**Stream Module (`ka9q.stream`):**
|
|
191
|
+
|
|
192
|
+
- `RadiodStream` - High-level sample stream with automatic resequencing and gap filling
|
|
193
|
+
- Callback-based delivery: `on_samples(samples: np.ndarray, quality: StreamQuality)`
|
|
194
|
+
- Handles IQ and audio modes automatically
|
|
195
|
+
- Cross-platform multicast support (Linux, macOS, Windows)
|
|
196
|
+
|
|
197
|
+
**Quality Tracking (`ka9q.stream_quality`):**
|
|
198
|
+
|
|
199
|
+
- `StreamQuality` - Comprehensive quality metrics per batch and cumulative
|
|
200
|
+
- `completeness_pct` - Percentage of expected samples received
|
|
201
|
+
- `total_gap_events` / `total_gaps_filled` - Gap statistics
|
|
202
|
+
- RTP packet metrics: received, lost, duplicate, resequenced
|
|
203
|
+
- RTP timestamps: `first_rtp_timestamp`, `last_rtp_timestamp` for precise timing
|
|
204
|
+
- `GapEvent` - Individual gap details (position, duration, source)
|
|
205
|
+
- `GapSource` - Gap type classification (NETWORK_LOSS, RESEQUENCE_TIMEOUT, EMPTY_PAYLOAD, etc.)
|
|
206
|
+
|
|
207
|
+
**Resequencer (`ka9q.resequencer`):**
|
|
208
|
+
|
|
209
|
+
- `PacketResequencer` - Circular buffer resequencing with gap detection
|
|
210
|
+
- Handles out-of-order packet delivery
|
|
211
|
+
- KA9Q-style signed 32-bit timestamp arithmetic for wrap handling
|
|
212
|
+
- Zero-fills gaps for continuous stream integrity
|
|
213
|
+
- `RTPPacket` - Packet data structure with samples
|
|
214
|
+
- `ResequencerStats` - Resequencing statistics
|
|
215
|
+
|
|
216
|
+
**Examples:**
|
|
217
|
+
|
|
218
|
+
- `examples/stream_example.py` - Basic streaming demonstration
|
|
219
|
+
- `examples/grape_integration_example.py` - Two-phase recording pattern (startup buffer → recording)
|
|
220
|
+
|
|
221
|
+
### Example Usage
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from ka9q import RadiodStream, StreamQuality, discover_channels
|
|
225
|
+
|
|
226
|
+
def on_samples(samples, quality: StreamQuality):
|
|
227
|
+
print(f"Got {len(samples)} samples, {quality.completeness_pct:.1f}% complete")
|
|
228
|
+
for gap in quality.batch_gaps:
|
|
229
|
+
print(f" Gap: {gap.source.value}, {gap.duration_samples} samples")
|
|
230
|
+
|
|
231
|
+
channels = discover_channels('radiod.local')
|
|
232
|
+
stream = RadiodStream(
|
|
233
|
+
channel=channels[10000000],
|
|
234
|
+
on_samples=on_samples,
|
|
235
|
+
samples_per_packet=320, # RTP timestamp increment at 16kHz
|
|
236
|
+
)
|
|
237
|
+
stream.start()
|
|
238
|
+
# ... run until done ...
|
|
239
|
+
final_quality = stream.stop()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Architecture
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
radiod → Multicast → RadiodStream → PacketResequencer → App Callback
|
|
246
|
+
↓
|
|
247
|
+
StreamQuality (per batch + cumulative)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Core delivers:**
|
|
251
|
+
|
|
252
|
+
- Continuous sample stream (gaps zero-filled)
|
|
253
|
+
- Quality metadata with every callback
|
|
254
|
+
|
|
255
|
+
**Applications handle:**
|
|
256
|
+
|
|
257
|
+
- Segmentation (1-minute NPZ, 2-minute WAV, etc.)
|
|
258
|
+
- Format conversion
|
|
259
|
+
- App-specific gap classification (cadence_fill, late_start, etc.)
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## [3.1.0] - 2025-12-01
|
|
264
|
+
|
|
265
|
+
### 🎯 SSRC Abstraction - SSRC-Free Channel Creation
|
|
266
|
+
|
|
267
|
+
This release removes SSRC from the application concern. Applications now specify **what they want** (frequency, mode, sample rate) and the system handles SSRC allocation internally.
|
|
268
|
+
|
|
269
|
+
### Added
|
|
270
|
+
|
|
271
|
+
**SSRC Allocation:**
|
|
272
|
+
|
|
273
|
+
- `allocate_ssrc(frequency_hz, preset, sample_rate, agc, gain)` - Deterministic SSRC allocation from channel parameters. Same parameters always produce the same SSRC, enabling stream sharing across applications.
|
|
274
|
+
|
|
275
|
+
**SSRC-Free `create_channel()`:**
|
|
276
|
+
|
|
277
|
+
- `ssrc` parameter is now **optional** (moved to end of parameters)
|
|
278
|
+
- When omitted, SSRC is auto-allocated using `allocate_ssrc()`
|
|
279
|
+
- Method now **returns the SSRC** (useful when auto-allocated)
|
|
280
|
+
|
|
281
|
+
### Changed
|
|
282
|
+
|
|
283
|
+
- `create_channel()` signature: `frequency_hz` is now the first (required) parameter
|
|
284
|
+
- `create_channel()` now returns `int` (the SSRC) instead of `None`
|
|
285
|
+
|
|
286
|
+
### Cross-Library Compatibility
|
|
287
|
+
|
|
288
|
+
The SSRC allocation algorithm matches signal-recorder's `StreamSpec.ssrc_hash()`:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
key = (round(frequency_hz), preset.lower(), sample_rate, agc, round(gain, 1))
|
|
292
|
+
return hash(key) & 0x7FFFFFFF
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
This ensures:
|
|
296
|
+
|
|
297
|
+
- Same parameters → same SSRC in both ka9q-python and signal-recorder
|
|
298
|
+
- Stream sharing works across applications using either library
|
|
299
|
+
- Deterministic allocation for coordination
|
|
300
|
+
|
|
301
|
+
### Example
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
from ka9q import RadiodControl, allocate_ssrc
|
|
305
|
+
|
|
306
|
+
# SSRC-free API (recommended)
|
|
307
|
+
with RadiodControl("radiod.local") as control:
|
|
308
|
+
ssrc = control.create_channel(
|
|
309
|
+
frequency_hz=14.074e6,
|
|
310
|
+
preset="usb",
|
|
311
|
+
sample_rate=12000
|
|
312
|
+
)
|
|
313
|
+
print(f"Created channel with SSRC: {ssrc}")
|
|
314
|
+
|
|
315
|
+
# Or use allocate_ssrc() directly for coordination
|
|
316
|
+
ssrc = allocate_ssrc(10.0e6, "iq", 16000)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## [3.0.0] - 2025-12-01
|
|
322
|
+
|
|
323
|
+
### 🎉 Major Release: Complete RadioD Feature Exposure
|
|
324
|
+
|
|
325
|
+
This major release exposes **all remaining radiod features** through the Python interface, providing comprehensive control over every aspect of ka9q-radio operation.
|
|
326
|
+
|
|
327
|
+
### Added - 20 New Control Methods
|
|
328
|
+
|
|
329
|
+
**Tracking & Tuning:**
|
|
330
|
+
|
|
331
|
+
- `set_doppler(ssrc, doppler_hz, doppler_rate_hz_per_sec)` - Doppler frequency shift and rate for satellite tracking
|
|
332
|
+
- `set_first_lo(ssrc, frequency_hz)` - Direct hardware tuner frequency control
|
|
333
|
+
|
|
334
|
+
**Signal Processing:**
|
|
335
|
+
|
|
336
|
+
- `set_pll(ssrc, enable, bandwidth_hz, square)` - Phase-locked loop configuration for carrier tracking
|
|
337
|
+
- `set_squelch(ssrc, enable, open_snr_db, close_snr_db)` - SNR-based squelch with hysteresis
|
|
338
|
+
- `set_envelope_detection(ssrc, enable)` - Toggle between envelope (AM) and synchronous detection
|
|
339
|
+
- `set_independent_sideband(ssrc, enable)` - ISB mode (USB/LSB to separate L/R channels)
|
|
340
|
+
- `set_fm_threshold_extension(ssrc, enable)` - Improve FM reception at weak signal levels
|
|
341
|
+
|
|
342
|
+
**AGC & Levels:**
|
|
343
|
+
|
|
344
|
+
- `set_agc_threshold(ssrc, threshold_db)` - Set AGC activation threshold above noise floor
|
|
345
|
+
|
|
346
|
+
**Output Control:**
|
|
347
|
+
|
|
348
|
+
- `set_output_channels(ssrc, channels)` - Configure mono (1) or stereo (2) output
|
|
349
|
+
- `set_output_encoding(ssrc, encoding)` - Select output format (S16BE, S16LE, F32, F16, OPUS)
|
|
350
|
+
- `set_opus_bitrate(ssrc, bitrate)` - Configure Opus encoder bitrate (0=auto, typical 32000-128000)
|
|
351
|
+
- `set_packet_buffering(ssrc, min_blocks)` - Control RTP packet buffering (0-4 blocks)
|
|
352
|
+
- `set_destination(ssrc, address, port)` - Change RTP output multicast destination
|
|
353
|
+
|
|
354
|
+
**Filtering:**
|
|
355
|
+
|
|
356
|
+
- `set_filter2(ssrc, blocksize, kaiser_beta)` - Configure secondary filter for additional selectivity
|
|
357
|
+
|
|
358
|
+
**Spectrum Analysis:**
|
|
359
|
+
|
|
360
|
+
- `set_spectrum(ssrc, bin_bw_hz, bin_count, crossover_hz, kaiser_beta)` - Configure spectrum analyzer parameters
|
|
361
|
+
|
|
362
|
+
**System Control:**
|
|
363
|
+
|
|
364
|
+
- `set_status_interval(ssrc, interval)` - Set automatic status reporting rate
|
|
365
|
+
- `set_demod_type(ssrc, demod_type)` - Switch demodulator type (LINEAR/FM/WFM/SPECTRUM)
|
|
366
|
+
- `set_rf_gain(ssrc, gain_db)` - Control RF front-end gain (hardware-dependent)
|
|
367
|
+
- `set_rf_attenuation(ssrc, atten_db)` - Control RF front-end attenuation (hardware-dependent)
|
|
368
|
+
- `set_options(ssrc, set_bits, clear_bits)` - Set/clear experimental option bits
|
|
369
|
+
|
|
370
|
+
### Updated - Type Definitions
|
|
371
|
+
|
|
372
|
+
Fixed `StatusType` constants in `ka9q/types.py`:
|
|
373
|
+
|
|
374
|
+
- `SPECTRUM_FFT_N = 76` (was UNUSED16)
|
|
375
|
+
- `SPECTRUM_KAISER_BETA = 91` (was UNUSED20)
|
|
376
|
+
- `CROSSOVER = 95` (was UNUSED21)
|
|
377
|
+
|
|
378
|
+
### Documentation
|
|
379
|
+
|
|
380
|
+
**New Documentation Files:**
|
|
381
|
+
|
|
382
|
+
- `NEW_FEATURES.md` - Comprehensive documentation of all 20 new features with examples
|
|
383
|
+
- `QUICK_REFERENCE.md` - Quick reference guide with practical code examples
|
|
384
|
+
- `RADIOD_FEATURES_SUMMARY.md` - Complete implementation summary and verification
|
|
385
|
+
- `examples/advanced_features_demo.py` - Working demonstration script
|
|
386
|
+
|
|
387
|
+
### Feature Coverage
|
|
388
|
+
|
|
389
|
+
This release provides complete coverage of radiod's TLV command set:
|
|
390
|
+
|
|
391
|
+
- ✅ All 35+ radiod TLV commands now supported
|
|
392
|
+
- ✅ Doppler tracking for satellite reception
|
|
393
|
+
- ✅ PLL carrier tracking for coherent detection
|
|
394
|
+
- ✅ SNR squelch with hysteresis
|
|
395
|
+
- ✅ Independent sideband (ISB) mode
|
|
396
|
+
- ✅ FM threshold extension
|
|
397
|
+
- ✅ Secondary filtering
|
|
398
|
+
- ✅ Spectrum analyzer configuration
|
|
399
|
+
- ✅ Output encoding selection
|
|
400
|
+
- ✅ RF hardware controls
|
|
401
|
+
- ✅ Experimental option bits
|
|
402
|
+
|
|
403
|
+
### Use Cases Enabled
|
|
404
|
+
|
|
405
|
+
**Satellite Communications:**
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
control.set_doppler(ssrc=12345, doppler_hz=-5000, doppler_rate_hz_per_sec=100)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Coherent AM Reception:**
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
control.set_pll(ssrc=12345, enable=True, bandwidth_hz=50)
|
|
415
|
+
control.set_envelope_detection(ssrc=12345, enable=False)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Independent Sideband:**
|
|
419
|
+
|
|
420
|
+
```python
|
|
421
|
+
control.set_independent_sideband(ssrc=12345, enable=True)
|
|
422
|
+
control.set_output_channels(ssrc=12345, channels=2)
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Opus Audio Streaming:**
|
|
426
|
+
|
|
427
|
+
```python
|
|
428
|
+
control.set_output_encoding(ssrc=12345, encoding=Encoding.OPUS)
|
|
429
|
+
control.set_opus_bitrate(ssrc=12345, bitrate=64000)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Spectrum Analysis:**
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
control.set_spectrum(ssrc=12345, bin_bw_hz=100, bin_count=512)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Breaking Changes
|
|
439
|
+
|
|
440
|
+
⚠️ **None** - This release is 100% backward compatible. All existing code will continue to work without modification.
|
|
441
|
+
|
|
442
|
+
### Implementation Details
|
|
443
|
+
|
|
444
|
+
- All new methods follow existing design patterns
|
|
445
|
+
- Comprehensive input validation with clear error messages
|
|
446
|
+
- Full logging support for debugging
|
|
447
|
+
- Proper docstrings with examples for all methods
|
|
448
|
+
- Thread-safe operation via existing infrastructure
|
|
449
|
+
- ~400 lines of new, tested code
|
|
450
|
+
|
|
451
|
+
### Verification
|
|
452
|
+
|
|
453
|
+
✅ All code compiles successfully
|
|
454
|
+
✅ All imports validated
|
|
455
|
+
✅ 20 new methods confirmed available
|
|
456
|
+
✅ Pattern consistency verified
|
|
457
|
+
✅ Documentation complete
|
|
458
|
+
|
|
459
|
+
### Migration Guide
|
|
460
|
+
|
|
461
|
+
No migration needed - all changes are additive. Simply update to v3.0.0 and start using the new features as needed.
|
|
462
|
+
|
|
463
|
+
For examples, see:
|
|
464
|
+
|
|
465
|
+
- `NEW_FEATURES.md` for detailed feature documentation
|
|
466
|
+
- `QUICK_REFERENCE.md` for quick code examples
|
|
467
|
+
- `examples/advanced_features_demo.py` for working demonstrations
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## [2.5.0] - 2025-11-30
|
|
472
|
+
|
|
473
|
+
### Added - RTP Recorder Enhancement
|
|
474
|
+
|
|
475
|
+
- **`pass_all_packets` parameter** in `RTPRecorder.__init__()`
|
|
476
|
+
- Allows bypassing internal packet resequencing logic
|
|
477
|
+
- When `True`, passes ALL packets to callback regardless of sequence gaps
|
|
478
|
+
- Metrics still track sequence errors, dropped packets, and timestamp jumps
|
|
479
|
+
- Designed for applications with external resequencers (e.g., signal-recorder's PacketResequencer)
|
|
480
|
+
- `max_packet_gap` parameter ignored when `pass_all_packets=True`
|
|
481
|
+
- No resync state transitions - stays in RECORDING mode continuously
|
|
482
|
+
|
|
483
|
+
- **Updated `_validate_packet()` method** in `RTPRecorder`
|
|
484
|
+
- Conditional resync triggering based on `pass_all_packets` flag
|
|
485
|
+
- Metrics tracking independent of pass-through mode
|
|
486
|
+
- Early return for pass-all mode to bypass resync state handling
|
|
487
|
+
- Preserves original behavior when `pass_all_packets=False` (default)
|
|
488
|
+
|
|
489
|
+
### Documentation
|
|
490
|
+
|
|
491
|
+
- **API Reference** - Added `pass_all_packets` parameter documentation
|
|
492
|
+
- Added example showing external resequencer usage
|
|
493
|
+
- Updated parameter descriptions
|
|
494
|
+
|
|
495
|
+
- **Implementation Guide** - Usage patterns for external resequencing
|
|
496
|
+
|
|
497
|
+
### Backward Compatibility
|
|
498
|
+
|
|
499
|
+
100% backward compatible - `pass_all_packets` defaults to `False`, preserving existing behavior.
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## [2.4.0] - 2025-11-29
|
|
504
|
+
|
|
505
|
+
### Added - RTP Destination Control
|
|
506
|
+
|
|
507
|
+
- **`encode_socket()` function** in `ka9q/control.py`
|
|
508
|
+
- Encodes IPv4 socket addresses in radiod's TLV format (6-byte format)
|
|
509
|
+
- Validates IP addresses and port numbers
|
|
510
|
+
- Matches radiod's `decode_socket()` expectations exactly
|
|
511
|
+
|
|
512
|
+
- **`_validate_multicast_address()` function** in `ka9q/control.py`
|
|
513
|
+
- Validates multicast address format (IP or hostname)
|
|
514
|
+
- Allows both IP addresses and DNS names
|
|
515
|
+
|
|
516
|
+
- **`destination` parameter** to `create_channel()` method
|
|
517
|
+
- Accepts format: "address" or "address:port"
|
|
518
|
+
- Examples: "239.1.2.3", "wspr.local", "239.1.2.3:5004"
|
|
519
|
+
- Enables per-channel RTP destination control
|
|
520
|
+
|
|
521
|
+
- **Full `destination` support** in `tune()` method
|
|
522
|
+
- Removed "not implemented" warning
|
|
523
|
+
- Properly encodes destination socket addresses
|
|
524
|
+
- Supports port specification (defaults to 5004)
|
|
525
|
+
|
|
526
|
+
- **Comprehensive documentation**:
|
|
527
|
+
- `RTP_DESTINATION_FEATURE.md` - Feature documentation with examples
|
|
528
|
+
- `CONTROL_COMPARISON.md` - Command-by-command comparison with control.c
|
|
529
|
+
- `IMPLEMENTATION_STATUS.md` - Complete status of ka9q-python vs control/tune
|
|
530
|
+
- `WEBUI_SUMMARY.md` - Web UI implementation details
|
|
531
|
+
|
|
532
|
+
- **Test suite** for socket encoding
|
|
533
|
+
- `tests/test_encode_socket.py` - Comprehensive tests for encode_socket()
|
|
534
|
+
- Tests roundtrip encoding/decoding
|
|
535
|
+
- Tests error handling and validation
|
|
536
|
+
|
|
537
|
+
### Added - Web UI
|
|
538
|
+
|
|
539
|
+
- **Complete web-based control interface** (`webui/` directory)
|
|
540
|
+
- `webui/app.py` - Flask backend with REST API
|
|
541
|
+
- `webui/templates/index.html` - Modern responsive UI
|
|
542
|
+
- `webui/static/style.css` - Dark theme styling
|
|
543
|
+
- `webui/static/app.js` - Frontend logic with auto-refresh
|
|
544
|
+
- `webui/start.sh` - Quick start script
|
|
545
|
+
- `webui/requirements.txt` - Python dependencies
|
|
546
|
+
- `webui/README.md` - Complete usage documentation
|
|
547
|
+
|
|
548
|
+
- **Web UI Features**:
|
|
549
|
+
- Auto-discovery of radiod instances on LAN
|
|
550
|
+
- Pull-down selector for radiod instances
|
|
551
|
+
- Channel list with frequency, mode, sample rate, destination
|
|
552
|
+
- Real-time channel monitoring (1-second auto-refresh)
|
|
553
|
+
- 4-column layout: Tuning, Filter, Output, Signal
|
|
554
|
+
- Full-width Gain & AGC section
|
|
555
|
+
- Live SNR, baseband power, noise density
|
|
556
|
+
- Error handling with auto-stop after 3 consecutive failures
|
|
557
|
+
- Responsive design (desktop, tablet, mobile)
|
|
558
|
+
- No framework dependencies (vanilla JavaScript)
|
|
559
|
+
|
|
560
|
+
- **Web UI API Endpoints**:
|
|
561
|
+
- `GET /api/discover` - Discover radiod instances
|
|
562
|
+
- `GET /api/channels/<address>` - List channels
|
|
563
|
+
- `GET /api/channel/<address>/<ssrc>` - Get channel status
|
|
564
|
+
- `POST /api/tune/<address>/<ssrc>` - Tune channel
|
|
565
|
+
|
|
566
|
+
### Fixed
|
|
567
|
+
|
|
568
|
+
- **Deduplication** in `discover_radiod_services()`
|
|
569
|
+
- Uses dict with address as key to remove duplicates
|
|
570
|
+
- Sorts results by name for consistency
|
|
571
|
+
- Fixes multiple entries from avahi-browse (IPv4/IPv6, multiple interfaces)
|
|
572
|
+
|
|
573
|
+
- **Timeout handling** in web UI
|
|
574
|
+
- Increased backend timeout from 2s to 10s
|
|
575
|
+
- Added consecutive error tracking (stops after 3 failures)
|
|
576
|
+
- Better error messages for inactive channels
|
|
577
|
+
- Prevents refresh interval overlap
|
|
578
|
+
|
|
579
|
+
- **Channel selection** in web UI
|
|
580
|
+
- Fixed bouncing between multiple channels
|
|
581
|
+
- Only one channel refreshes at a time
|
|
582
|
+
- Proper cleanup when switching channels
|
|
583
|
+
- Added `isRefreshing` flag to prevent race conditions
|
|
584
|
+
|
|
585
|
+
### Changed
|
|
586
|
+
|
|
587
|
+
- **Control comparison** - Documented 52.5% coverage of control.c commands
|
|
588
|
+
- 21 commands fully implemented (all core functionality)
|
|
589
|
+
- 19 advanced commands not yet implemented (PLL, squelch, etc.)
|
|
590
|
+
- 100% coverage of tune.c commands
|
|
591
|
+
|
|
592
|
+
- **Implementation status** - Confirmed ka9q-python is production-ready
|
|
593
|
+
- Complete frequency control
|
|
594
|
+
- Complete mode/preset control
|
|
595
|
+
- Complete filter control (including Kaiser beta)
|
|
596
|
+
- Complete AGC control (all 5 parameters)
|
|
597
|
+
- Complete gain control (manual, RF gain, RF atten)
|
|
598
|
+
- Complete output control (sample rate, encoding, destination)
|
|
599
|
+
- Complete status interrogation
|
|
600
|
+
|
|
601
|
+
## Summary of Changes
|
|
602
|
+
|
|
603
|
+
This release adds:
|
|
604
|
+
|
|
605
|
+
1. **Per-channel RTP destination control** - Clients can now specify unique RTP destinations for each channel
|
|
606
|
+
2. **Web UI** - Modern browser-based interface for monitoring and controlling radiod
|
|
607
|
+
3. **Better discovery** - Deduplicated radiod instance discovery
|
|
608
|
+
4. **Comprehensive documentation** - Full comparison with control.c and implementation status
|
|
609
|
+
|
|
610
|
+
### Files Modified
|
|
611
|
+
|
|
612
|
+
- `ka9q/control.py` - Added encode_socket(), updated tune() and create_channel()
|
|
613
|
+
- `ka9q/discovery.py` - Fixed deduplication in discover_radiod_services()
|
|
614
|
+
- `tests/test_encode_socket.py` - New test suite
|
|
615
|
+
|
|
616
|
+
### Files Added
|
|
617
|
+
|
|
618
|
+
- `webui/` - Complete web UI implementation (7 files)
|
|
619
|
+
- `RTP_DESTINATION_FEATURE.md` - Feature documentation
|
|
620
|
+
- `CONTROL_COMPARISON.md` - Command comparison
|
|
621
|
+
- `IMPLEMENTATION_STATUS.md` - Implementation status
|
|
622
|
+
- `WEBUI_SUMMARY.md` - Web UI documentation
|
|
623
|
+
- `CHANGELOG.md` - This file
|
|
624
|
+
|
|
625
|
+
### Backward Compatibility
|
|
626
|
+
|
|
627
|
+
All changes are backward compatible. Existing code continues to work without modification.
|
|
628
|
+
The `destination` parameter is optional in both `create_channel()` and `tune()`.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Include documentation
|
|
2
2
|
include README.md
|
|
3
3
|
include LICENSE
|
|
4
|
-
include
|
|
5
|
-
include
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
include
|
|
9
|
-
|
|
4
|
+
include CHANGELOG.md
|
|
5
|
+
include RELEASE_NOTES_v3.5.0.md
|
|
6
|
+
|
|
7
|
+
# Include protocol compatibility pin
|
|
8
|
+
include ka9q_radio_compat
|
|
9
|
+
|
|
10
|
+
# Include sync tooling
|
|
11
|
+
recursive-include scripts *.py
|
|
10
12
|
|
|
11
13
|
# Include examples
|
|
12
14
|
recursive-include examples *.py
|
|
@@ -14,6 +16,9 @@ recursive-include examples *.py
|
|
|
14
16
|
# Include tests
|
|
15
17
|
recursive-include tests *.py
|
|
16
18
|
|
|
19
|
+
# Include docs
|
|
20
|
+
recursive-include docs *.md
|
|
21
|
+
|
|
17
22
|
# Exclude compiled files
|
|
18
23
|
global-exclude *.pyc
|
|
19
24
|
global-exclude __pycache__
|