Skip to content

[codex] Fix KiwiSDR SQL and AGC controls#3749

Merged
ten9876 merged 3 commits into
aethersdr:mainfrom
rfoust:codex/kiwi-squelch-main
Jun 23, 2026
Merged

[codex] Fix KiwiSDR SQL and AGC controls#3749
ten9876 merged 3 commits into
aethersdr:mainfrom
rfoust:codex/kiwi-squelch-main

Conversation

@rfoust

@rfoust rfoust commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

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:

The 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

  • Local build passes (cmake --build build --target kiwi_sdr_protocol_test slice_model_letter_test AetherSDR)
  • Behavior verified on a real radio if applicable
  • Existing tests pass (ctest --test-dir build -R "kiwi_sdr_protocol_test|slice_model_letter_test" --output-on-failure)
  • Reproduction steps documented if user-reported bug

Additional local checks:

  • git diff --check
  • python3 tools/check_a11y.py exits 0; existing warning-only findings remain

Checklist

  • Commits are signed (docs/COMMIT-SIGNING.md)
  • No new flat-key AppSettings calls — Kiwi profile state remains under the existing nested Kiwi settings; SQL margin reuse follows existing app behavior
  • Code is clean-room — not decompiled, disassembled, or reverse-engineered from a proprietary binary
  • All meter UI uses existing meter surfaces/smoothing paths
  • Documentation updated if user-visible behavior changed
  • Security-sensitive changes reference a GHSA if applicable

@rfoust rfoust marked this pull request as ready for review June 23, 2026 00:22
@rfoust rfoust requested review from a team as code owners June 23, 2026 00:22
Copilot AI review requested due to automatic review settings June 23, 2026 00:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/gui/RxApplet.cpp Outdated
Comment on lines +2222 to +2224
// 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.
Comment thread src/core/KiwiSdrClient.h Outdated
Comment on lines +34 to +36
// Kiwi server squelch: 0 open/off, otherwise signed dB offset from
// median RSSI floor for non-NBFM modes.
int squelchThresholdDb{20};
@rfoust rfoust self-assigned this Jun 23, 2026
@rfoust

rfoust commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the two Copilot review comments in follow-up commit 1717b5ee:

  • Clarified the RxApplet SQL-mode comment: Flex Auto SQL is applet-wide across active Flex slice switches, while Kiwi replacement receive keeps Auto SQL as per-slice external receive state.
  • Clarified KiwiSdrReceiverControls::squelchThresholdDb: 0 is off/open, non-NBFM uses signed dB offset from the median RSSI floor, and NBFM uses the raw 1-99 noise squelch level.

Validation before pushing:

  • git diff --check
  • cmake --build build --target AetherSDR

The build passed; only existing unrelated compiler warnings were emitted.

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 — connectSlice now 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 the m_flexSqlMode else-if branch. ✅
  • The squelchThresholdDb field comment in KiwiSdrClient.h now 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:

  • AppSettings used throughout (no stray QSettings); AutoSqlMarginDb/LastManualSquelchLevel reuse the existing keys.
  • m_kiwiSdrSquelchMeterSamples is bounded (removeFirst() past kServerRssiMedianSamples) — no unbounded growth.
  • Local SND squelch gating (pcm.fill(0) on the 0x40 flag) and ignoring SLC/LEVEL for Kiwi-assigned slices both line up with the documented server behavior.
  • AgcTCalibrator::startAutoSweep() and the calibrate context-menu action are correctly disabled under externalReceiveReplacementActive().

One minor thing to consider (not blocking):

  • TciProtocol::cmdAgcGain now returns receiveAgcThreshold(), which for a Kiwi-assigned slice is on the -160..0 dB scale rather than the conventional TCI agc_gain 0..100 range. A TCI client polling agc_gain on 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 ten9876 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@ten9876 ten9876 merged commit 79dae03 into aethersdr:main Jun 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants