[codex] Fix KiwiSDR SQL and AGC controls#3749
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends AetherSDR’s KiwiSDR integration so that when a Kiwi RX antenna/profile is selected, the existing RX surfaces (RxApplet, VFO controls, spectrum overlay, automation snapshot, TCI, shortcuts/controllers) operate the Kiwi “external receive replacement” AGC + SQL behavior, while preserving normal Flex slice AGC/SQL behavior.
Changes:
- Adds independent Kiwi vs Flex AGC/SQL state in
SliceModel, with new signals and “receive*” accessors used by UI/control surfaces. - Implements KiwiSDR server-compatible AGC + squelch command formatting, plus SND squelch-flag parsing and local audio gating on squelch.
- Updates spectrum overlay rendering and auto-squelch routing for Flex vs Kiwi, and adds regression tests for protocol/model behavior.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/slice_model_letter_test.cpp | Adds regression coverage for external receive replacement AGC/SQL ownership and signal behavior. |
| tests/kiwi_sdr_protocol_test.cpp | Expands Kiwi protocol tests for SND squelch flag parsing, W/F byte decoding, and AGC/SQL command formatting helpers. |
| src/models/SliceModel.h | Adds Flex vs receive accessor split and new signals/state for external receive AGC/SQL. |
| src/models/SliceModel.cpp | Routes AGC/SQL setters to external receive state when replacement is active; emits dedicated external signals. |
| src/gui/VfoWidget.h | Introduces standalone SQL mode helpers and Auto SQL margin signal for Kiwi replacement cases. |
| src/gui/VfoWidget.cpp | Makes VFO SQL/AGC controls operate on receive-visible state; adds Kiwi standalone SQL (Off/Manual/Auto) UI behavior. |
| src/gui/SpectrumWidget.h | Adds Kiwi-specific squelch line/meter APIs and internal state for independent Flex vs Kiwi overlays. |
| src/gui/SpectrumWidget.cpp | Implements Kiwi squelch line rendering/pinning, SND-meter floor tracking, and Kiwi-aware auto-squelch suggestion behavior. |
| src/gui/RxApplet.h | Adds slice-attachment checks and per-surface SQL manual bounds helpers (Flex vs Kiwi). |
| src/gui/RxApplet.cpp | Updates SQL + AGC UI logic to use receive-visible state and to maintain independent Kiwi/Flex SQL behavior. |
| src/gui/MainWindow.h | Adds helpers to sync squelch line + auto-squelch enablement across spectrums and Kiwi receiver controls. |
| src/gui/MainWindow.cpp | Switches band snapshot AGC capture to receive-visible AGC values and uses new spectrum sync helpers. |
| src/gui/MainWindow_Wiring.cpp | Reworks spectrum wiring so squelch line + auto-squelch routing follow Flex vs Kiwi ownership rules. |
| src/gui/MainWindow_Shortcuts.cpp | Updates squelch/AGC shortcuts to operate on receive-visible state and Kiwi ranges. |
| src/gui/MainWindow_KiwiSdr.cpp | Pushes receive-visible SQL/AGC into Kiwi receiver controls; activates correct slice when selecting RX source. |
| src/gui/MainWindow_Controllers.cpp | Adjusts controller/MIDI mappings for Kiwi AGC threshold range translation and receive-visible SQL state. |
| src/gui/AgcCalibrationDialog.cpp | Disables calibration for external receive replacement and tracks receive-visible AGC mode for UI updates. |
| src/core/TciProtocol.cpp | Reports/controls SQL and AGC using receive-visible state for TCI clients. |
| src/core/KiwiSdrProtocol.h | Adds constants + helpers for squelch/AGC formatting and squelch slider mapping; extends SND header/meter fields. |
| src/core/KiwiSdrProtocol.cpp | Implements squelch/AGC formatting, W/F byte decoding, and verified SND meter extraction updates. |
| src/core/KiwiSdrManager.h | Adds API to push receiver controls to a Kiwi client for a given assigned slice. |
| src/core/KiwiSdrManager.cpp | Implements forwarding receiver controls to the appropriate Kiwi client. |
| src/core/KiwiSdrClient.h | Updates receiver controls struct to use a squelch threshold field compatible with server commands. |
| src/core/KiwiSdrClient.cpp | Uses new protocol-format helpers, parses squelch flag, and gates audio locally when squelched. |
| src/core/AutomationServer.cpp | Extends automation slice snapshot with receive/flex split fields for AGC/SQL + external replacement flag. |
| src/core/AgcTCalibrator.cpp | Skips AGC-T auto sweep for external receive replacement slices. |
| docs/kiwisdr-cleanroom-design.md | Updates clean-room design notes with verified Kiwi SQL/AGC/SND/WF behavior and command contracts. |
| // Squelch — derive 3-way mode from the current receive surface's | ||
| // squelch on/off state. Auto is client-side only and doesn't survive | ||
| // slice switches, so a freshly-selected slice starts in Off or Manual. |
| // Kiwi server squelch: 0 open/off, otherwise signed dB offset from | ||
| // median RSSI floor for non-NBFM modes. | ||
| int squelchThresholdDb{20}; |
|
Addressed the two Copilot review comments in follow-up commit
Validation before pushing:
The build passed; only existing unrelated compiler warnings were emitted. |
There was a problem hiding this comment.
Thanks for this @rfoust — it's a large change but a genuinely careful one. The Flex/Kiwi state separation in SliceModel (mirrored getters, distinct externalReceive* signals, independent overlay state in SpectrumWidget) is clean, the clean-room source attribution is thorough, and the protocol-level helpers (formatSquelchCommand/formatAgcCommand/squelchSliderLevelToMarginDb/agcDecayMsForMode) are nicely factored out and well-covered by kiwi_sdr_protocol_test. CI is green across build / macOS / Windows / CodeQL / a11y.
A few notes:
Copilot findings — both already addressed in the current revision (false positives against HEAD):
- The "Auto SQL doesn't survive slice switches" comment Copilot flagged is gone —
connectSlicenow reads "Flex keeps the applet-wide Auto mode across active Flex slice switches, while Kiwi replacement receive keeps Auto as per-slice external receive state," which matches them_flexSqlModeelse-if branch. ✅ - The
squelchThresholdDbfield comment inKiwiSdrClient.hnow documents both meanings ("non-NBFM uses signed dB offset from median RSSI floor, while NBFM uses the raw 1-99 noise squelch level"), exactly what Copilot asked for. ✅
Conventions / safety — looks good:
AppSettingsused throughout (no strayQSettings);AutoSqlMarginDb/LastManualSquelchLevelreuse the existing keys.m_kiwiSdrSquelchMeterSamplesis bounded (removeFirst()pastkServerRssiMedianSamples) — no unbounded growth.- Local SND squelch gating (
pcm.fill(0)on the0x40flag) and ignoringSLC/LEVELfor Kiwi-assigned slices both line up with the documented server behavior. AgcTCalibrator::startAutoSweep()and the calibrate context-menu action are correctly disabled underexternalReceiveReplacementActive().
One minor thing to consider (not blocking):
TciProtocol::cmdAgcGainnow returnsreceiveAgcThreshold(), which for a Kiwi-assigned slice is on the-160..0dB scale rather than the conventional TCIagc_gain0..100range. A TCI client pollingagc_gainon a Kiwi-replacement slice would see a negative value. This only matters in the TCI + Kiwi-replacement combination and is arguably the intended "report the active surface" behavior, but worth a deliberate decision (and maybe a one-line comment) since other TCI clients may assume the 0–100 contract.
Nice work — this is solid, and the regression tests give good confidence in the protocol math.
🤖 aethersdr-agent · cost: $9.6327 · model: claude-opus-4-8
The KiwiSDR receive integration now also derives protocol facts beyond the original MSG-key/badp error labels: the SET squelch/SET agc command shapes (LGPL server source) and the AGC/squelch numeric ranges (CuteSDR, Simplified BSD). Update THIRD_PARTY_LICENSES so the canonical license-provenance record matches the shipped code — broaden the scope line and add CuteSDR (BSD-2-Clause) as a distinct sub-component. Facts only; no KiwiSDR/CuteSDR code incorporated. Full per-fact detail in docs/kiwisdr-cleanroom-design.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ten9876
left a comment
There was a problem hiding this comment.
Approving — with one provenance commit pushed on top.
The code is strong and well-vetted (Flex/Kiwi state cleanly separated in SliceModel, protocol helpers factored + covered by kiwi_sdr_protocol_test, SND squelch gating + bounded RSSI-median buffer correct, both prior reviews' findings addressed, CI green).
Pushed 4c4c7091 to close the one gap I found: THIRD_PARTY_LICENSES was still scoped (from #3716) to "only … MSG keys and numeric badp denial codes" and cited only LGPL, but this PR also derives the SET squelch/SET agc command shapes (LGPL server source) and the AGC/squelch numeric ranges from CuteSDR (Simplified BSD) — a distinct, previously-unrecorded license. The commit broadens the scope line, lists the consulted LGPL files, and adds CuteSDR (BSD-2-Clause) as its own sub-component, pointing to docs/kiwisdr-cleanroom-design.md for the per-fact detail. Facts only; no code incorporated. The canonical license file now matches the shipped code.
One deliberate decision worth recording (non-blocking): TciProtocol::cmdAgcGain now returns receiveAgcThreshold() (−160..0 dB) for a Kiwi-replacement slice, vs the conventional TCI agc_gain 0..100 contract — so a TCI client polling that on a Kiwi slice sees a negative value. Reasonable as "report the active surface," but a one-line comment (or a follow-up to map it) would help TCI clients that assume 0–100.
Thanks @rfoust — careful work, and the clean-room attribution discipline is exactly right; I just brought the license file in sync.
Summary
Implements KiwiSDR receive-source SQL and AGC behavior so the existing RX applet, VFO controls, spectrum SQL overlay, automation/TCI state, and Kiwi receiver command path control the Kiwi replacement receiver when a Kiwi RX antenna is selected, while preserving Flex SQL/AGC behavior for normal Flex slices. This adds server-compatible Kiwi squelch and AGC command formatting, independent Kiwi/Flex SQL state, Kiwi-only SQL overlay rendering, local SND squelch audio gating, verified SND meter handling, and regression coverage for the protocol/model behavior.
Constitution principle honored
Principle IV — this remains clean-room and source-attributed. No KiwiSDR served JavaScript/client code, WebSDR code, or AGPL client implementation was copied, translated, or used. Public server/DSP source was consulted only to verify wire protocol facts and numeric ranges.
Source attribution:
rx/rx_sound_cmd.cppis GNU Library GPL v2-or-later and was consulted to verify the acceptedSET agc=...andSET squelch=... param=...parser forms: https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/rx_sound_cmd.cpp#L433-L459rx/rx_sound.cppwas consulted to verify non-NBFM squelch is median-noise-relative and emits the SND squelch UI flag: https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/rx_sound.cpp#L988-L1022 and https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/rx_sound.cpp#L468-L475-160..0 dB, manual gain0..100 dB, and decay20..5000 ms: https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/CuteSDR/agc.cpp#L11-L19 and https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/CuteSDR/agc.cpp#L95-L101The consulted LGPL/GNU Library GPL and Simplified BSD sources are GPL-compatible public sources, and this PR uses only protocol/range facts from them; no source code was incorporated.
Test plan
cmake --build build --target kiwi_sdr_protocol_test slice_model_letter_test AetherSDR)ctest --test-dir build -R "kiwi_sdr_protocol_test|slice_model_letter_test" --output-on-failure)Additional local checks:
git diff --checkpython3 tools/check_a11y.pyexits 0; existing warning-only findings remainChecklist
docs/COMMIT-SIGNING.md)AppSettingscalls — Kiwi profile state remains under the existing nested Kiwi settings; SQL margin reuse follows existing app behavior