ka9q-python 3.15.1__tar.gz → 3.17.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.
Files changed (112) hide show
  1. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/CHANGELOG.md +175 -0
  2. {ka9q_python-3.15.1/ka9q_python.egg-info → ka9q_python-3.17.0}/PKG-INFO +7 -12
  3. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/README.md +1 -1
  4. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/GETTING_STARTED.md +2 -2
  5. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/INSTALLATION.md +5 -5
  6. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/MULTI_STREAM.md +3 -3
  7. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/RECIPES.md +3 -3
  8. ka9q_python-3.17.0/docs/REQUIREMENTS.md +409 -0
  9. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/__init__.py +8 -1
  10. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/compat.py +1 -1
  11. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/control.py +347 -176
  12. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/discovery.py +181 -10
  13. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/multi_stream.py +95 -2
  14. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/rtp_recorder.py +32 -5
  15. ka9q_python-3.17.0/ka9q/status_listener.py +439 -0
  16. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/stream.py +95 -29
  17. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/types.py +1 -1
  18. {ka9q_python-3.15.1 → ka9q_python-3.17.0/ka9q_python.egg-info}/PKG-INFO +7 -12
  19. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_python.egg-info/SOURCES.txt +5 -1
  20. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_radio_compat +1 -1
  21. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/pyproject.toml +6 -6
  22. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/conftest.py +4 -3
  23. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_channel_verification.py +134 -13
  24. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_client_id_destination.py +16 -16
  25. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_ensure_channel_encoding.py +10 -8
  26. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_filter_edges.py +17 -20
  27. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_iq_20khz_f32.py +13 -7
  28. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_listen_multicast.py +13 -5
  29. ka9q_python-3.17.0/tests/test_multistream_gap_storm.py +57 -0
  30. ka9q_python-3.17.0/tests/test_multistream_prune.py +84 -0
  31. ka9q_python-3.17.0/tests/test_status_listener.py +347 -0
  32. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_tune_live.py +13 -3
  33. ka9q_python-3.15.1/setup.py +0 -47
  34. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/LICENSE +0 -0
  35. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/MANIFEST.in +0 -0
  36. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/API_REFERENCE.md +0 -0
  37. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/ARCHITECTURE.md +0 -0
  38. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/CLI_GUIDE.md +0 -0
  39. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/RTP_TIMING_SUPPORT.md +0 -0
  40. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/SECURITY.md +0 -0
  41. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/TESTING_GUIDE.md +0 -0
  42. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/docs/TUI_GUIDE.md +0 -0
  43. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/advanced_features_demo.py +0 -0
  44. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/channel_cleanup_example.py +0 -0
  45. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/codar_oceanography.py +0 -0
  46. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/diagnostics/diagnose_packets.py +0 -0
  47. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/diagnostics/repro_utc_bug.py +0 -0
  48. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/discover_example.py +0 -0
  49. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/grape_integration_example.py +0 -0
  50. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/hf_band_scanner.py +0 -0
  51. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/multi_stream_smoke.py +0 -0
  52. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/rtp_recorder_example.py +0 -0
  53. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/simple_am_radio.py +0 -0
  54. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/spectrum_example.py +0 -0
  55. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/stream_example.py +0 -0
  56. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/superdarn_recorder.py +0 -0
  57. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/test_channel_operations.py +0 -0
  58. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/test_improvements.py +0 -0
  59. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/test_timing_fields.py +0 -0
  60. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/tune.py +0 -0
  61. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/examples/tune_example.py +0 -0
  62. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/_multicast.py +0 -0
  63. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/addressing.py +0 -0
  64. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/cli.py +0 -0
  65. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/exceptions.py +0 -0
  66. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/managed_stream.py +0 -0
  67. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/monitor.py +0 -0
  68. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/pps_calibrator.py +0 -0
  69. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/resequencer.py +0 -0
  70. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/spectrum_stream.py +0 -0
  71. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/status.py +0 -0
  72. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/stream_quality.py +0 -0
  73. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/tui.py +0 -0
  74. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q/utils.py +0 -0
  75. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_python.egg-info/dependency_links.txt +0 -0
  76. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_python.egg-info/entry_points.txt +0 -0
  77. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_python.egg-info/requires.txt +0 -0
  78. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/ka9q_python.egg-info/top_level.txt +0 -0
  79. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/scripts/check_upstream_drift.py +0 -0
  80. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/scripts/sync_types.py +0 -0
  81. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/setup.cfg +0 -0
  82. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/__init__.py +0 -0
  83. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_addressing.py +0 -0
  84. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_create_split_encoding.py +0 -0
  85. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_decode_description.py +0 -0
  86. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_decode_functions.py +0 -0
  87. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_encode_functions.py +0 -0
  88. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_encode_socket.py +0 -0
  89. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_integration.py +0 -0
  90. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_lifetime.py +0 -0
  91. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_managed_stream_recovery.py +0 -0
  92. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_monitor.py +0 -0
  93. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_multicast_helpers.py +0 -0
  94. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_multihomed.py +0 -0
  95. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_native_discovery.py +0 -0
  96. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_parse_rtp_samples_iq.py +0 -0
  97. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_performance_fixes.py +0 -0
  98. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_protocol_compat.py +0 -0
  99. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_remove_channel.py +0 -0
  100. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_rtp_recorder.py +0 -0
  101. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_security_features.py +0 -0
  102. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_spectrum.py +0 -0
  103. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_ssrc_dest_unit.py +0 -0
  104. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_ssrc_encoding_unit.py +0 -0
  105. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_ssrc_radiod_host_unit.py +0 -0
  106. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_status_decoder.py +0 -0
  107. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_ttl_warning.py +0 -0
  108. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_tune.py +0 -0
  109. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_tune_cli.py +0 -0
  110. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_tune_debug.py +0 -0
  111. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_tune_method.py +0 -0
  112. {ka9q_python-3.15.1 → ka9q_python-3.17.0}/tests/test_upstream_drift.py +0 -0
@@ -1,5 +1,180 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.17.0] - 2026-06-28
4
+
5
+ First release marked **Production/Stable** (trove classifier 4 → 5). Folds in
6
+ 23 commits of feature and resilience work that had accumulated on `main` past
7
+ the `v3.16.1` tag with no version bump.
8
+
9
+ ### Added
10
+
11
+ - **`RadiodControl.poll_channel(ssrc)`** (`control.py`) — a targeted, O(1)
12
+ status probe for a single channel. Replaces the previous reliance on a full
13
+ channel discovery sweep when only one channel's state is needed.
14
+ - **`MultiStream.prune_frequency(...)`** (`multi_stream.py`) — releases a
15
+ superseded channel slot *and its ring buffer*, fixing a ring leak when a
16
+ frequency is retuned/replaced within a live `MultiStream`.
17
+ - **mDNS hostname + port surfaced by discovery** (`discovery.py`) — additive
18
+ fields on the discovery result; existing consumers are unaffected.
19
+ - **RTP↔GPS offset-step detection (`anchor_epoch`)** (`stream.py`) — a
20
+ `RadiodStream` now detects a step in radiod's RTP↔GPS offset and re-anchors
21
+ its timing reference instead of carrying a stale anchor.
22
+
23
+ ### Changed
24
+
25
+ - **`ensure_channel` now verifies via `poll_channel` (O(1))** instead of a dead
26
+ discovery sweep (`control.py`). Faster, more reliable channel confirmation.
27
+ Note a deliberate relaxation on the *create* path: the channel is now accepted
28
+ on **frequency match alone** — a rate/preset divergence is logged as a warning
29
+ (not raised) and the destination is no longer re-verified. Callers should treat
30
+ the returned `ChannelInfo` as authoritative for the granted encoding/rate
31
+ (the sigmond recorders already do). The reuse path still verifies strictly.
32
+ - **`RadiodStream` binds the channel's multicast group**, not `0.0.0.0`
33
+ (`stream.py`) — avoids cross-talk on hosts carrying multiple multicast groups.
34
+ - **`rtp_to_wallclock` renamed to `rtp_to_utc`** (`rtp_recorder.py`). The name
35
+ "wallclock" wrongly implied a system-clock dependency; the function is purely
36
+ RTP/GPS-referenced. `rtp_to_wallclock` remains as a deprecated alias — no
37
+ caller needs to change.
38
+ - **`anchor_step_threshold_sec` raised 0.25 → 0.75** (`stream.py`) to tolerate
39
+ output-timing jitter on a busy radiod without spuriously re-anchoring.
40
+ - **8 MB receive buffer on `poll_channel`'s status listener** (`control.py`) to
41
+ avoid drops while probing on a busy status multicast group.
42
+ - **ka9q-radio compatibility pin advanced to `9b742e6`** (no protocol drift;
43
+ validated by `check_upstream_drift.py`).
44
+ - **Repository moved to the HamSCI org**; project/doc/URL references updated
45
+ from `mijahauan/` to `HamSCI/`.
46
+
47
+ ### Fixed
48
+
49
+ - **Gap storm now treated as a stream-health failure → re-subscribe**
50
+ (`multi_stream.py`, 228a041). A stale `MultiStream` subscription after a
51
+ radiod restart manifests as a sustained packet-gap storm (not silence); the
52
+ health monitor now detects it and re-subscribes, restoring delivery without
53
+ an external restart. See the sigmond `stale-subscription-gap-storm-protection`
54
+ note.
55
+
56
+ ### Packaging
57
+
58
+ - **Removed the redundant `setup.py`.** All project metadata lives in
59
+ `pyproject.toml`'s PEP 621 `[project]` table (`setuptools.build_meta`
60
+ backend). `setup.py` had drifted to a stale `3.10.0` / `4 - Beta` duplicate
61
+ and was an unused second source of truth.
62
+
63
+ ### Docs / Tests
64
+
65
+ - Added a **requirements baseline** (`docs/REQUIREMENTS.md`, `KQP-*` spec).
66
+ - `CLAUDE.md` documents `MultiStream` as the fourth abstraction layer.
67
+ - The **live channel-verification suite is now gated behind explicit opt-in**
68
+ (`--radiod-host`), so the default `pytest` run no longer hangs waiting on a
69
+ live radiod. Unit suite: 363 passed, 27 skipped.
70
+
71
+ ## [3.16.1] - 2026-05-24
72
+
73
+ ### Fixed
74
+
75
+ - **`ChannelInfo` anchor pair is now atomic** (`channel-info`). Adds
76
+ `ChannelInfo.get_anchor()` / `update_anchor()` — a tuple-based
77
+ atomic snapshot of `(gps_time, rtp_timesnap)`. `rtp_to_wallclock`
78
+ now reads the pair via `get_anchor` (single GIL-atomic attribute
79
+ access) instead of two separate reads; `StatusListener` writes via
80
+ `update_anchor` (single tuple assignment).
81
+
82
+ Why: the `StatusListener` introduced in 3.16.0 refreshes the anchor
83
+ in place at sub-second cadence (~450 ms on a busy host). Direct
84
+ sequential reads of `channel.gps_time` followed by
85
+ `channel.rtp_timesnap` could land between the listener's two writes
86
+ and yield a torn pair off by one listener-cadence interval.
87
+ `rtp_to_wallclock` then returned a wall-time off by that much —
88
+ usually harmless, but consumers comparing against an external time
89
+ reference with a tight gate (e.g. hf-timestd's T5 LB-1421 NMEA
90
+ disambig at ±0.5 s) could be pushed across the threshold and fall
91
+ back to a chrony walk that itself fails during a post-restart
92
+ cascade.
93
+
94
+ Backward compatible: constructor kwargs (`gps_time=`,
95
+ `rtp_timesnap=`) and direct field reads are unchanged; consumers
96
+ that need the pair transactionally must call `get_anchor`. Adds
97
+ 5 new tests (atomic update, construction-time seed, mixed-None
98
+ handling, listener path, 50-iteration consistency smoke test).
99
+
100
+ ### Performance
101
+
102
+ - **`RadiodStream`: `SO_RCVBUF` raised 0 → 64 MB** (`stream.py`).
103
+ Mirrors the 3.16.0-cycle `multi_stream.py` change on the
104
+ single-channel path. Previously `RadiodStream` sockets fell back
105
+ to the kernel default (`rmem_default`, typically 16 MB on hosts
106
+ with sigmond's `rule_kernel_rcvbuf_adequate` provisioning) and were
107
+ vulnerable to GIL-stall packet loss with no other consumer competing
108
+ to drain the buffer. 64 MB matches the `MultiStream` cap; sigmond
109
+ provisions `net.core.rmem_max=128 MB` (after kernel doubling), so
110
+ the request is honored. Observed on bee1 2026-05-23 closing a
111
+ 140 ms-stall-induced `gap=13440` resequencer event on hf-timestd's
112
+ T6 dedicated stream.
113
+
114
+ - **`MultiStream`: `SO_RCVBUF` raised 8 MB → 64 MB** (`multi_stream.py`).
115
+ Observed 412 M UDP `RcvbufErrors` on B4-100 since boot, driven by
116
+ GIL contention preventing Python receiver threads from draining the
117
+ kernel-doubled 16 MB sockets. Bigger absorber → more headroom
118
+ across GIL stalls before packets are dropped. After applying:
119
+ socket `rb` shows 134217728 (128 MB visible after kernel doubling)
120
+ and recv-Q sits at ~50 KB in steady state (was hitting 14 MB / 16
121
+ MB before). Requires `net.core.rmem_max >= 64 MB` to be honored —
122
+ provisioned by sigmond in
123
+ `/etc/sysctl.d/99-wspr-recorder.conf` alongside this change.
124
+
125
+ ## [3.16.0] - 2026-05-23
126
+
127
+ ### Added
128
+
129
+ - **`StatusListener` — continuous STATUS multicast listener.** New
130
+ `ka9q.status_listener.StatusListener` class subscribes to radiod's
131
+ STATUS multicast (port 5006) in a background thread and refreshes
132
+ `ChannelInfo.gps_time` / `.rtp_timesnap` on every broadcast. Replaces
133
+ the previous one-shot `discover_channels` anchor capture, which
134
+ froze the timing anchor at SSRC discovery — leaving `rtp_to_wallclock`
135
+ to project forward from a host-clock value that drifts at the
136
+ chrony slew rate (~3.8 µs/s on a typical disciplined host).
137
+
138
+ Mutates the registered `ChannelInfo` in place so callers holding a
139
+ reference (e.g. hf-timestd's cached `_t6_channel_info`) see fresh
140
+ values immediately. Supports per-SSRC and wildcard callbacks for
141
+ explicit notification. Uses `SO_REUSEPORT` so it can coexist with
142
+ `RadiodControl`'s own status socket without stealing tune/discover
143
+ responses — multicast packets are delivered to every joined socket.
144
+
145
+ Opt-in via `RadiodControl.start_status_listener()`; closing the
146
+ control object stops the listener. See class docstring for usage.
147
+
148
+ - **`RadiodControl.start_status_listener(...)` / `.stop_status_listener(...)`
149
+ / `.status_listener` property** — convenience wiring to attach a
150
+ `StatusListener` to an existing control session. Listener is
151
+ stopped automatically by `RadiodControl.close()`.
152
+
153
+ ### Why this exists
154
+
155
+ Before this release, every ka9q-python consumer (hf-timestd, codar,
156
+ psk, hfdl, wspr, wsprdaemon-client, gpsdo-monitor) labeled data via
157
+ `rtp_to_wallclock(rtp, channel)` with a ChannelInfo whose
158
+ `gps_time`/`rtp_timesnap` were captured once at SSRC discovery.
159
+ For long-running services this meant labels drifted from GPSDO truth
160
+ at the host-clock slew rate — on bee1 (`chrony` slewing at
161
+ ~3.8 µs/s), labels accumulated ~330 ms of drift per day.
162
+
163
+ The chrony SHM-push side of hf-timestd's BPSK PPS path (HPPS / HFPS)
164
+ manifested this most visibly: TS-1 source reported tracking with
165
+ 1 ns standard deviation but drifted at the host slew rate, blocking
166
+ DASI2 grant deployment. Faster anchor refresh closes the drift.
167
+
168
+ ### Backwards compatibility
169
+
170
+ - All existing tests pass unchanged. The listener is **opt-in** —
171
+ consumers that don't call `start_status_listener()` see no behavior
172
+ change.
173
+ - `ChannelInfo` is unchanged structurally; only its mutability
174
+ contract is clarified (the timing fields were always documented as
175
+ "the latest snapshot", which is now true continuously rather than
176
+ once).
177
+
3
178
  ## [3.15.1] - 2026-05-21
4
179
 
5
180
  ### Fixed
@@ -1,17 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ka9q-python
3
- Version: 3.15.1
3
+ Version: 3.17.0
4
4
  Summary: Python interface for ka9q-radio control and monitoring
5
- Home-page: https://github.com/mijahauan/ka9q-python
6
- Author: Michael Hauan AC0G
7
5
  Author-email: Michael Hauan AC0G <ac0g@hauan.org>
8
6
  License: MIT
9
- Project-URL: Homepage, https://github.com/mijahauan/ka9q-python
10
- Project-URL: Documentation, https://github.com/mijahauan/ka9q-python/blob/main/README.md
11
- Project-URL: Repository, https://github.com/mijahauan/ka9q-python
12
- Project-URL: Issues, https://github.com/mijahauan/ka9q-python/issues
7
+ Project-URL: Homepage, https://github.com/HamSCI/ka9q-python
8
+ Project-URL: Documentation, https://github.com/HamSCI/ka9q-python/blob/main/README.md
9
+ Project-URL: Repository, https://github.com/HamSCI/ka9q-python
10
+ Project-URL: Issues, https://github.com/HamSCI/ka9q-python/issues
13
11
  Keywords: ka9q-radio,sdr,ham-radio,radio-control
14
- Classifier: Development Status :: 4 - Beta
12
+ Classifier: Development Status :: 5 - Production/Stable
15
13
  Classifier: Intended Audience :: Science/Research
16
14
  Classifier: Intended Audience :: Telecommunications Industry
17
15
  Classifier: Programming Language :: Python :: 3
@@ -32,10 +30,7 @@ Provides-Extra: tui
32
30
  Requires-Dist: textual>=0.50; extra == "tui"
33
31
  Provides-Extra: opus
34
32
  Requires-Dist: opuslib>=3.0; extra == "opus"
35
- Dynamic: author
36
- Dynamic: home-page
37
33
  Dynamic: license-file
38
- Dynamic: requires-python
39
34
 
40
35
  # ka9q-python
41
36
 
@@ -95,7 +90,7 @@ pip install "ka9q-python[tui,opus]" # multiple
95
90
  Or install from source:
96
91
 
97
92
  ```bash
98
- git clone https://github.com/mijahauan/ka9q-python.git
93
+ git clone https://github.com/HamSCI/ka9q-python.git
99
94
  cd ka9q-python
100
95
  pip install -e .
101
96
  ```
@@ -56,7 +56,7 @@ pip install "ka9q-python[tui,opus]" # multiple
56
56
  Or install from source:
57
57
 
58
58
  ```bash
59
- git clone https://github.com/mijahauan/ka9q-python.git
59
+ git clone https://github.com/HamSCI/ka9q-python.git
60
60
  cd ka9q-python
61
61
  pip install -e .
62
62
  ```
@@ -25,7 +25,7 @@ pip install ka9q-python
25
25
  Or, if you want to install from source:
26
26
 
27
27
  ```bash
28
- git clone https://github.com/mijahauan/ka9q-python.git
28
+ git clone https://github.com/HamSCI/ka9q-python.git
29
29
  cd ka9q-python
30
30
  pip install -e .
31
31
  ```
@@ -235,7 +235,7 @@ Congratulations! You've created your first `ka9q-python` application and learned
235
235
 
236
236
  3. **Learn About Advanced Features**: Check out `examples/advanced_features_demo.py` to see how to use Doppler tracking, PLL configuration, squelch, and more.
237
237
 
238
- 4. **Join the Community**: If you have questions or want to contribute, visit the [GitHub repository](https://github.com/mijahauan/ka9q-python).
238
+ 4. **Join the Community**: If you have questions or want to contribute, visit the [GitHub repository](https://github.com/HamSCI/ka9q-python).
239
239
 
240
240
  ---
241
241
 
@@ -13,12 +13,12 @@ The distribution name is `ka9q-python`; the import name is `ka9q`.
13
13
 
14
14
  ### From GitHub (development version)
15
15
  ```bash
16
- pip install git+https://github.com/mijahauan/ka9q-python.git
16
+ pip install git+https://github.com/HamSCI/ka9q-python.git
17
17
  ```
18
18
 
19
19
  ### From Local Clone
20
20
  ```bash
21
- git clone https://github.com/mijahauan/ka9q-python.git
21
+ git clone https://github.com/HamSCI/ka9q-python.git
22
22
  cd ka9q-python
23
23
  pip install .
24
24
  ```
@@ -27,7 +27,7 @@ pip install .
27
27
 
28
28
  ### Editable Install
29
29
  ```bash
30
- git clone https://github.com/mijahauan/ka9q-python.git
30
+ git clone https://github.com/HamSCI/ka9q-python.git
31
31
  cd ka9q-python
32
32
  pip install -e .
33
33
  ```
@@ -218,7 +218,7 @@ twine upload dist/*
218
218
 
219
219
  ```bash
220
220
  # Clone and install in editable mode
221
- git clone https://github.com/mijahauan/ka9q-python.git
221
+ git clone https://github.com/HamSCI/ka9q-python.git
222
222
  cd ka9q-python
223
223
  pip install -e ".[dev]"
224
224
 
@@ -285,5 +285,5 @@ if __name__ == '__main__':
285
285
  ## Support
286
286
 
287
287
  - Documentation: See README.md and other docs in the repository
288
- - Issues: https://github.com/mijahauan/ka9q-python/issues
288
+ - Issues: https://github.com/HamSCI/ka9q-python/issues
289
289
  - Examples: See `examples/` directory
@@ -38,10 +38,10 @@ Keep `ManagedStream` when:
38
38
  - You specifically want each channel's receive path isolated.
39
39
 
40
40
  Production users:
41
- [psk-recorder](https://github.com/mijahauan/psk-recorder) runs 20
41
+ [psk-recorder](https://github.com/HamSCI/psk-recorder) runs 20
42
42
  channels (10 FT4 + 10 FT8) on bee3 through a single `MultiStream`.
43
- [wspr-recorder](https://github.com/mijahauan/wspr-recorder) and
44
- [hf-timestd](https://github.com/mijahauan/hf-timestd) use the same
43
+ [wspr-recorder](https://github.com/HamSCI/wspr-recorder) and
44
+ [hf-timestd](https://github.com/HamSCI/hf-timestd) use the same
45
45
  pattern.
46
46
 
47
47
  ---
@@ -130,9 +130,9 @@ matters.
130
130
  ## Recipe 2 — Fixed sets of same-type channels (WSPR, PSK, FT8, timing)
131
131
 
132
132
  This is the pattern used by
133
- [wspr-recorder](https://github.com/mijahauan/wspr-recorder),
134
- [psk-recorder](https://github.com/mijahauan/psk-recorder), and
135
- [hf-timestd](https://github.com/mijahauan/hf-timestd):
133
+ [wspr-recorder](https://github.com/HamSCI/wspr-recorder),
134
+ [psk-recorder](https://github.com/HamSCI/psk-recorder), and
135
+ [hf-timestd](https://github.com/HamSCI/hf-timestd):
136
136
 
137
137
  1. Read a band plan (list of frequencies + preset + sample rate).
138
138
  2. For each entry, call `ensure_channel()` — deterministic SSRC