feat(swr): optional manual sweep range (#2241)#3885
Conversation
There was a problem hiding this comment.
Thanks for this, @M7HNF-Ian — nicely scoped and the safety reasoning is sound. The clamp happens receiver-side in startSwrSweep where the custom bounds are intersected with the already-computed safeLow/safeHigh (which themselves fold in the regional band-plan narrowing from #2800), so a manual range can only ever narrow the sweep and the out-of-region transmit guard is preserved. The signal/slot wiring lines up (the function-pointer connect in MainWindow_Wiring.cpp resolves cleanly to the new 4-arg startSwrSweep), the spin boxes and checkbox are parented into the layout so there's no leak, and the null guards (if (!m_slice), m_slice ? … : -1) are all in place. No AppSettings/QSettings concern since nothing here persists.
One substantive thing worth tightening:
Inverted range silently falls back to a full-band sweep. The guard is:
if (customLowMhz > 0.0 && customHighMhz > customLowMhz) {
...
}If the operator enters From above To (e.g. From 14.200, To 14.100), the condition is false and the code drops through to the full-band safeLow/safeHigh range with no warning. For the exact use case this feature targets — rnash2 wanting to confine the sweep to respect operating privileges — that's the wrong-direction surprise: they think they've constrained the sweep but actually get a full-band transmit. The non-overlapping case already warns; an inverted entry should too rather than silently widening. Suggest splitting the validation so a positive-but-inverted range is rejected with the same kind of QMessageBox::warning instead of falling through.
Minor (optional): the From/To fields are seeded once on first tick (value() <= 0.0), so if the user changes band afterward the seeded edges go stale. Not a correctness issue — the receiver-side clamp still keeps it safe — but re-seeding on band change (or whenever the range is empty) would match the "sensible in-band starting point" intent better.
Nothing here blocks; the safety-critical path is correct. Nice work, and thanks for the clear write-up and the live FLEX-6600 test notes.
🤖 aethersdr-agent · cost: $3.7778 · model: claude-opus-4-8
ten9876
left a comment
There was a problem hiding this comment.
Thanks Ian — nicely scoped, and the safety reasoning checks out.
TX-safety (Principle VI) — clean. The SWR sweep keys the radio, so this is a transmit path, but the custom bounds are clamped inside the already-computed safe range:
sweepLow = std::max(safeLow, customLowMhz);
sweepHigh = std::min(safeHigh, customHighMhz);safeLow/safeHigh already fold in the #2800 regional band-plan narrowing and the out-of-region transmit guard (both untouched), so a manual range can only ever narrow the sweep — never widen it past what the band plan permits. The sub-step-overlap rejection also prevents a zero-width keying. The invariant holds.
🔴 Needs a rebase — merge conflict with #3882. The SWR CSV export (#3882) landed in this same window and added a Save CSV button + swrSweepSaveCsvRequested() signal + m_swrSaveBtn in the exact regions this PR edits. There are real content conflicts in SpectrumOverlayMenu.cpp and SpectrumOverlayMenu.h (the other two files auto-merge clean). It's purely mechanical "keep both" — the CSV button row and the Limit-range row are logically independent, so the resolution keeps the new 4-arg swrSweepStartRequested and the swrSweepSaveCsvRequested signal, plus all members. Please rebase on main and let CI re-run (the current green is from before #3882 merged).
🟡 Worth folding into the same rebase: inverted range silently sweeps full-band. With From > To (both > 0), the guard customHighMhz > customLowMhz is false, so it drops through to the full safeLow/safeHigh. It's not a safety violation — the sweep is still clamped within the safe band — but it's a wrong-direction surprise for the exact use case this targets: an operator confining a sweep to their privileges thinks they've narrowed it but actually gets a full-band sweep. Suggest rejecting a positive-but-inverted range with the same QMessageBox::warning you already use for the non-overlap case.
⚪ Minor (optional): the From/To fields seed once on first tick (value() <= 0.0), so they go stale if the operator changes band afterward. The receiver-side clamp keeps it safe regardless; re-seeding on band change (or whenever the range is empty) would just match the "sensible in-band starting point" intent better.
Clean work and thanks for the live FLEX-6600 test notes. Once it's rebased past #3882 — ideally with the inverted-range warning added — this is a merge.
Add a "Limit range" checkbox and From/To frequency fields to the SWR sweep controls so operators can confine a sweep to a licence sub-band or a slice of interest instead of always sweeping the whole band. Off by default — the full-band sweep behaviour is unchanged. Ticking the box enables the fields and seeds them with the current band's edges (via BandSettings). The seed is refreshed whenever the fields are empty or no longer lie within the active band, so changing band and re-opening the range always starts from a sensible in-band point while a range narrowed within the current band is preserved. The chosen bounds are passed through swrSweepStartRequested() to startSwrSweep(), where they are intersected with the existing in-region safe range. They can therefore only ever narrow the sweep — never widen it past what the regional band plan already permits (aethersdr#2800) — preserving the out-of-region transmit guard. A positive-but-inverted range (From > To) is rejected up front with a warning rather than silently falling through to a full-band sweep, and a range that does not overlap the band by at least one step is likewise rejected. Part of aethersdr#2241 (the resonance/bandwidth display landed earlier in aethersdr#2320).
1ff059b to
74fac62
Compare
|
Thanks Jeremy — all three addressed in the rebased branch:
Builds clean; the TX-safety invariant is untouched (bounds still intersect the in-region safe range). |
ten9876
left a comment
There was a problem hiding this comment.
Verified against the current head (74fac623) — all three prior points resolved and CI green.
TX-safety (Principle VI) holds: the custom bounds are clamped inside the already-computed safe range (std::max(safeLow, customLow) / std::min(safeHigh, customHigh)), which folds in the #2800 regional band-plan narrowing, the edge guard, and the out-of-region TX guard — so a manual range can only ever narrow, never widen. Sub-step overlap check prevents zero-width keying.
- 🔴 Rebase past #3882 — clean 'keep both' (4-arg
swrSweepStartRequested+swrSweepSaveCsvRequested+ Save CSV button all present and wired). - 🟡 Inverted range — now rejected with a warning before any keying instead of falling through to full-band.
- ⚪ Stale seeding — re-seeds when empty or out-of-band, preserves a within-band narrowing.
Clean, well-scoped, and nicely tested on a FLEX-6600. Thanks @M7HNF-Ian — merging.
#3961) ## Release documentation prep for **v26.7.1** (2026-07-02) 29 commits since v26.6.5. Docs-only + version bump — no code behavior change. ### Version bump 26.6.5 → 26.7.1 The three canonical locations (per `AGENTS.md`): - `CMakeLists.txt:2` — `project(AetherSDR VERSION 26.7.1)` → `AETHERSDR_VERSION` (the app's version string) - `README.md` — Current version line - `AGENTS.md` — Current version line ### `CHANGELOG.md` Promoted `[Unreleased]` → **`## [v26.7.1] — 2026-07-02`** in house style (v-prefix, em-dash, "N commits since…" opener + headline), authored from all merged PRs and categorized: - **Added:** 3D stacked-trace spectrum (#3899), 3D dBm scale (#3937), in-process NVIDIA BNR + AFX download-on-demand (#3902), TX meter mouse-over readouts (#3936), SWR manual sweep range (#3885), CW sidetone capture (#3895), KiwiSDR metadata scaffolding (#3898), bridge verbs (#3920) - **Changed:** BNR container/NIM backend removed, 60 fps + per-pixel GPU FFT trace (#3958), FlexLib-sourced model capabilities (#3954/#2177), RX speaker-latency cut (#3897), Display pane sections (#3935) - **Fixed:** #3922, #3926, #3941, #3940, #3942, #3921, #3903, #3892, #3924, #3891, #3890, #3900, #3947 - Fresh empty `[Unreleased]` restored above the release block. Internal/CI/docs/self-fix PRs (#3931/#3916/#3934/#3929) omitted per house style. ### `ROADMAP.md` - Cycle header → "post-v26.7.1" - NVIDIA BNR removed from **In flight** (shipped this cycle) - Five v26.7.1 highlights prepended to **Recently shipped** ### `README.md` - Highlights: GPU spectrum bullet now notes the **per-pixel FFT trace at up to 60 fps** and the **3D stacked-trace** spectrum mode ### Reviewer notes - Touches protected paths (`*.md` + `AGENTS.md` Tier-1 + `CMakeLists.txt`) — needs `@aethersdr/infrastructure` sign-off. - Tagging `v26.7.1` and cutting the release build are **not** part of this PR (docs prep only). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adds the user-bounded sweep range from #2241 (rnash2's request to "manually set the start and end sweep frequency to respect his operating privileges").
A Limit range checkbox with From/To fields in the SWR sweep controls lets an operator confine a sweep to a licence sub-band or a slice of interest instead of always sweeping the whole band.
BandSettings) as a starting point to narrow from.swrSweepStartRequested()tostartSwrSweep(), where they are intersected with the existing in-region safe range — so they can only ever narrow the sweep, never widen it past what the regional band plan already permits (Sweep doesn't respected band limits #2800). The out-of-region transmit guard is preserved.Tested live on a FLEX-6600: ticked Limit range (auto-seeded 14.000–14.350 on 20 m), narrowed To to 14.150, and confirmed the sweep trace covered only 14.000–14.150 instead of the full band.
Note: the resonance/bandwidth-marker portion of #2241 already landed in #2320, so this completes the remaining actionable scope.