Skip to content

fix: route native 4m/2m band selection#2831

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/fix-vhf-uhf-band-select
May 22, 2026
Merged

fix: route native 4m/2m band selection#2831
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/fix-vhf-uhf-band-select

Conversation

@rfoust
Copy link
Copy Markdown
Collaborator

@rfoust rfoust commented May 18, 2026

Summary

Fixes FLEX-6500/6700 built-in 4m/2m band routing and direct frequency entry above 54 MHz.

  • Teach XvtrPolicy to resolve 4m -> band=4 and 2m -> band=2 only when ModelCapabilities reports native 4m/2m support.
  • Preserve user-configured XVTR behavior on other radios, including XVTRs named 2m or 4m.
  • Make configured XVTR buttons carry their exact X<n> stack key so native 4m does not shadow a user XVTR named 4m.
  • Centralize direct-entry MHz detection in FrequencyEntryParser so the VFO widget and RX applet keep the same parsing rules.
  • Treat display-style direct entries such as 144.200.000 and 440.100.000 as MHz and preselect the proper band stack before tuning above 54 MHz.
  • Route RX applet direct-entry through the same MainWindow tune policy as the VFO widget.

Notes

The FLEX-6700 SmartSDR wire capture in #695 confirms native keys band=4 for 4m and band=2 for 2m. I did not add a native 440/70cm key; direct 440 MHz still requires a radio-reported configured XVTR.

Verification

  • cmake --build build --parallel
  • ./build/xvtr_policy_test
  • ./build/frequency_entry_parser_test
  • ctest --test-dir build -R "model_capabilities_test|frequency_entry_parser_test" --output-on-failure
  • git diff --check

Copilot AI review requested due to automatic review settings May 18, 2026 03:20
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes FlexRadio FLEX-6500/6700 native 4m (70 MHz) and 2m (144 MHz) band routing by making band-stack key resolution capability-aware, preventing user-configured XVTRs named “2m/4m” from being shadowed, and ensuring high-VHF direct frequency entries preselect the correct band stack before tuning.

Changes:

  • Extend XvtrPolicy::resolveBandStackKey() to optionally consider ModelCapabilities so native keys "4" / "2" are only used when the connected model reports native 4m/2m support; add regression tests.
  • Ensure configured XVTR buttons carry an explicit X<n> stack-key hint through SpectrumOverlayMenuMainWindow so native VHF doesn’t override same-named XVTRs.
  • Route RX applet direct-entry through MainWindow’s tune policy (with band-stack preselect) and treat display-style entries like 144.200.000 as explicit MHz for >54 MHz tuning.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/xvtr_policy_test.cpp Adds coverage for capability-gated native 2m/4m key resolution.
src/models/XvtrPolicy.h Extends band-stack key resolver API to accept ModelCapabilities.
src/models/XvtrPolicy.cpp Implements capability-aware native band key normalization for 2m/4m.
src/gui/VfoWidget.cpp Treats explicit “MHz-style” inputs as MHz above 54 MHz for direct entry.
src/gui/SpectrumOverlayMenu.h Adds per-button stackKey and extends bandSelected to carry a hint.
src/gui/SpectrumOverlayMenu.cpp Emits bandSelected with stackKey when known (configured XVTR buttons).
src/gui/RxApplet.h Adds directEntryCommitted signal to route tuning via MainWindow policy.
src/gui/RxApplet.cpp Uses explicit-MHz detection and emits directEntryCommitted instead of tuning directly.
src/gui/MainWindow.h Adds band-stack preselect result type and helper declaration.
src/gui/MainWindow.cpp Introduces band-stack preselect-before-tune for commanded direct entries; threads stackKey hints through band selection path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gui/VfoWidget.cpp Outdated
Comment on lines +146 to +165
static bool isExplicitMhzEntry(const QString& rawText, const QString& normalizedText)
{
const int dot = normalizedText.indexOf(QLatin1Char('.'));
if (dot < 0) {
return false;
}

// `14.225.000`, `144.200.000`, and `440.100.000` are MHz.kHz.Hz
// display-style entries. Keep them as MHz even before the slice is
// already on an XVTR/high-frequency band.
if (rawText.count(QLatin1Char('.')) >= 2) {
return true;
}

// Single-dot entries with a normal MHz field are also explicit MHz
// (`14.225`, `144.200`, `440.100`). Preserve the historic HF shortcut
// where `14225.0` means 14.225 MHz by treating five-plus leading digits
// as kHz-style input.
return dot <= 4;
}
Comment thread src/gui/RxApplet.cpp Outdated
Comment on lines +108 to +120
static bool isExplicitMhzEntry(const QString& rawText, const QString& normalizedText)
{
const int dot = normalizedText.indexOf(QLatin1Char('.'));
if (dot < 0) {
return false;
}

if (rawText.count(QLatin1Char('.')) >= 2) {
return true;
}

return dot <= 4;
}
Copy link
Copy Markdown
Contributor

@aethersdr-agent aethersdr-agent Bot left a comment

Choose a reason for hiding this comment

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

Thanks for tackling this, @rfoust — the XvtrPolicy capability-gating and the X<n> stack-key plumbing through SpectrumOverlayMenu are a clean design and the new test coverage in xvtr_policy_test.cpp exercises the right cases (native wins on capable radio; same-named XVTR still resolves on non-capable). The BandStackPreselectResult flow with the 250 ms re-tune timer is a sensible way to let the band-stack settle before the final retune.

A few things to flag before merge:

1. Branch is behind main — would revert PR #2826 (FFT Line slider, #2722)

git merge-base main HEAD for this branch is 26008b2c, which predates 4d5b4d7a ("Honor FFT Line slider on QPainter (software) render path"). The diff against current main includes a src/gui/SpectrumWidget.cpp hunk that:

  • removes the drawLine / "width 0 = Off" guard from both the heat-map and solid-fill branches of drawSpectrum
  • removes the cosmetic QPen with setWidthF(m_fftLineWidth) and hardcodes QPen(..., 1.5) back in
  • drops the update() call from setFftLineWidth

These changes aren't in your PR description or stated file list, and they undo the freshly-landed software-render path fix. Please rebase on main so the merge keeps #2722's behavior. (The file isn't even listed in the PR's "Files changed" overview in the description, so I assume this is purely a rebase artifact rather than intentional.)

2. Duplicated isExplicitMhzEntry() — Copilot's flag is valid

Confirmed: the helper is byte-identical in src/gui/VfoWidget.cpp:146 and src/gui/RxApplet.cpp:108, both as file-static. The parsing rule ("≥2 dots → MHz; single dot with ≤4 leading digits → MHz") is non-obvious and exactly the sort of thing that will silently diverge the next time someone tweaks one side. Suggest hoisting into a small shared utility (e.g. src/util/FrequencyEntry.{h,cpp} or alongside the existing parsing in BandSettings/XvtrPolicy) and having both widgets call it. Bonus: that's a natural home for a unit test of the heuristic itself.

3. resolveRadioBandStackKey thin wrapper

The new free function in MainWindow.cpp:382 just forwards to XvtrPolicy::resolveBandStackKey with m_radioModel.capabilities(). Two call sites is borderline; given the wrapper has no logic, calling XvtrPolicy::resolveBandStackKey(bandName, xvtrs, m_radioModel.capabilities()) directly would be clearer and matches how the rest of MainWindow uses the policy module. Not a blocker.

4. PR description mentions TX antenna behavior, but no antenna code is in the diff

Keep TX antenna behavior radio-authoritative by reflecting txant / tx_ant_list; no local antenna forcing.

I don't see any txant / tx_ant_list changes in the diff. If that was meant to be in this PR, it got lost; if it landed elsewhere, please drop the bullet from the description so reviewers and the changelog aren't misled.

Capability-gating logic and the direct-entry routing through MainWindow::applyTuneRequest look correct to me — once the rebase is sorted and the helper is shared, this should be in good shape. 73

@rfoust rfoust marked this pull request as draft May 18, 2026 04:18
@rfoust rfoust force-pushed the codex/fix-vhf-uhf-band-select branch from ba739a9 to b1bfc6c Compare May 18, 2026 04:43
@rfoust
Copy link
Copy Markdown
Collaborator Author

rfoust commented May 18, 2026

Addressed the review feedback in b1bfc6c:

  • Rebased onto current main at 4d5b4d7, so the PR no longer carries the stale SpectrumWidget.cpp FFT Line slider rollback.
  • Replaced the duplicated isExplicitMhzEntry() helpers with shared FrequencyEntryParser code used by both VfoWidget and RxApplet.
  • Added frequency_entry_parser_test coverage for display-style MHz entries and the legacy 14225.0 kHz-style shortcut.
  • Removed the thin resolveRadioBandStackKey wrapper and call XvtrPolicy::resolveBandStackKey(...) directly with m_radioModel.capabilities().
  • Updated the PR description to remove the TX antenna bullet and include the shared parser/test changes.

Verified locally with:

  • cmake --build build --parallel
  • ./build/xvtr_policy_test
  • ./build/frequency_entry_parser_test
  • ctest --test-dir build -R "model_capabilities_test|frequency_entry_parser_test" --output-on-failure
  • git diff --check

@rfoust rfoust marked this pull request as ready for review May 18, 2026 04:47
@rfoust rfoust added priority: medium Medium priority priority: high High priority and removed priority: medium Medium priority labels May 21, 2026
@rfoust rfoust force-pushed the codex/fix-vhf-uhf-band-select branch from b1bfc6c to 8775a5f Compare May 21, 2026 03:35
@ten9876 ten9876 force-pushed the codex/fix-vhf-uhf-band-select branch from 8775a5f to 848fd4a Compare May 22, 2026 15:54
@ten9876
Copy link
Copy Markdown
Collaborator

ten9876 commented May 22, 2026

@rfoust I've rebased this branch onto current main (e711fc04) to clear the merge conflict ahead of review. The auto-merge handled 6 of the 7 overlapping files cleanly; the one real conflict was a stale STYLEGUIDE.md comment in src/gui/RxApplet.cpp:107-113 that main had since renamed to docs/applet-style-guide.md and added a "Helpers" section header. I resolved that by keeping main's version — no code change at stake, just the comment.

Audit: per-file line counts on the rebased diff match the original PR within 2 lines (the resolved STYLEGUIDE comment difference). No silent reverts of recent main work in the seven overlapping files (verified vs the pattern from PR #2725).

CI should re-run on the force-push (new head 848fd4ac). Once it goes green and a maintainer signs off, this is ready to land.

73, Jeremy KK7GWY & Claude (AI dev partner)

@ten9876 ten9876 self-assigned this May 22, 2026
@ten9876 ten9876 merged commit 909cd06 into aethersdr:main May 22, 2026
5 checks passed
@ten9876
Copy link
Copy Markdown
Collaborator

ten9876 commented May 22, 2026

Claude here — merged as 909cd06, thanks @rfoust!

This is exactly the kind of PR we love to land: real-world bug
(FLEX-6500/6700 native 4m/2m routing), surgical scope (three coupled
fixes that earn their coupling), and tests that lock the tricky edges
(14225.0 keeps its legacy HF interpretation; native vs same-named
XVTR disambiguation on capable vs non-capable radios).

The FrequencyEntryParser extraction is a nice bonus — it removes
the near-identical parse logic that lived in both VfoWidget and
RxApplet, and makes the rules testable in isolation. Future direct-
entry tweaks will be a lot less scary.

Ships in the next release (target v26.5.3).

73,
Jeremy KK7GWY & Claude (AI dev partner)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: high High priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2m/4m Button now here in F6700 - but with out function => TRX not jump to this band

3 participants