fix(cat): rigctld dialect — gray out the meaningless VFO B selector#3698
Conversation
The rigctld (Hamlib) dialect is single-VFO per port: CatPort wires a rigctld
client with only the RX slice (RigctlProtocol has no VFO B input), and split is
create-on-demand (VFOB/SUB resolves to a dedicated TX slice only once a client
issues set_split_vfo 1). So a configured VFO B has no effect on a rigctld port,
yet the CAT-config UI exposed the selector unconditionally and persisted it.
- CatControlApplet: make the VFO B selector dialect-aware — for the Rigctld
dialect force it to "-" and disable it. As a DISPLAY override only: switching a
port's dialect to Rigctld no longer clobbers the operator's saved VFO B
(applyRowToSettings skips persisting VfoB while the dialect is Rigctld), and the
selector is restored from the saved value when the dialect is switched back to a
dual-VFO dialect (Flex / TS-2000). A dialect round-trip is lossless.
- Settings migration seeds VfoB=-1 (not 1) for the default rigctld port.
- Delete src/gui/CatPopoutWindow.{cpp,h}: a dead duplicate of the CAT-config row
(same VFO B selector + applyRowToSettings) that was never instantiated and not
even in the build — it would only drift further out of sync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Robustness fixes from review of the rigctld VFO-B change: - VFO B no longer lost on a rigctld↔dual round-trip when the saved slice isn't currently representable. The VFO combos are bounded by the radio's slice count, so a reconnect to a smaller radio can leave a previously-chosen slice off the list; the combo falls back to its first entry. New persistVfo() keeps the stored value in that case instead of clobbering it with the fallback — it reappears when the slices return. Applies to both VFO A and VFO B. - setMaxSlices() now restores the VFO selectors by DATA value, not by raw index + qMin clamp. The index-based restore could silently repoint a VFO to a different slice when the "—" entry shifted indices or the count shrank; restoring by data falls back to "—"/slice A only when the saved slice is genuinely gone. - Single-vs-dual-VFO is now a dialect capability — dialectSupportsVfoB(CatDialect) in CatPort.h — instead of scattered hard-coded `== CatDialect::Rigctld` checks, so every config surface shares one definition. - updateRowLocked() is display-state only again: the force-to-"—" for single-VFO dialects is idempotent, and the VFO-B restore moved to restoreVfoBForDialect(), invoked from the dialect-change handler (it's a transition, not something to re-run on every lock refresh). - Use CatPort::kVfoNone instead of the magic -1, and derive the dialect from the combo's enum data rather than its row index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Drive-by comment (not a formal review) — the title vs. the diff. The title, "gray out the meaningless VFO B selector," reads as a one-line cosmetic
Two small things:
No objection to the behavior; runtime wiring ( Maintainer note, and this is the real ask: anything that touches shared CAT/persistence behavior with the potential to affect SmartCAT/SmartDAX needs a linked PR + issue review before it lands. SmartCAT/SmartDAX is our largest platform and the primary CAT control path — it is not the place for a drive-by change landed on title-skim alone. This PR is scoped as a rigctld UI fix but it rewrites save/restore semantics for the dual-VFO dialects too (see point 2), and that crossover is exactly what I need surfaced and reviewed explicitly, not buried under a cosmetic title. Timing matters here: dropping a change that reaches into the shared CAT persistence layer one day out from the end of a release cycle is how we end up cleaning up regressions in the field. For changes like this please (a) cross-link the issue and any related PRs, (b) call out in the title/summary that it affects the dual-VFO/SmartCAT path, and (c) give it room in the cycle to be reviewed and tested — not a last-day merge. If it's genuinely rigctld-only, scope it to rigctld-only and leave the dual-VFO persistence path alone. |
|
@jensenpat This only affects rigctld protocol dialect. It does not affect TS-2000 or Flex: those are preserved --- other than the change you note if connecting to a smaller radio. That was noted by /code-review before I submitted, and I didn't think it should be left configured to address a slice that didn't exist. Technically, it's scope creep, but I expected it to be called out by the automated review and didn't want to leave it unresolved. I did submit an issue for this, and the deletion of the dead code was suggested by AetherClaude's review. I can restore that if you like. Or, we can adjust the title. In response to some of the Issues you cited, I've been doing a full sweep of the split VFO behavior, comparing ASDR to SSDR for Win and Mac, reconciling the slight differences. My goal has been to make them match the others. I'll be submitting an issue with those findings in the next day or so. Edit: I didn't expect this PR to make it into this release cycle. I only thought the previous one was important. But, I wanted to get this in for review over the next week. |
There was a problem hiding this comment.
Thanks for a careful, well-documented fix, @K5PTB — the comments explaining why each branch behaves the way it does made this easy to review. The core design (dialectSupportsVfoB() as a single capability rule, display-only override, lossless dialect round-trip) is sound, and CI is green across build/macOS/Windows/CodeQL.
I verified the parts that aren't obvious from the diff alone:
CatPopoutWindow.{cpp,h}deletion is safe. No references anywhere outside the two deleted files, and it isn't inCMakeLists.txt(the source list is explicit, not a glob), so it was genuinely dead. Good cleanup.- Load-time graying works.
buildTableRows()callsupdateRowLocked()per row (CatControlApplet.cpp:485), so a port already saved as rigctld comes up with VFO B forced to "—" and disabled — not just after a dialect toggle. setMaxSlices()restore-by-data preserves the disabled state for rigctld rows, since it restores from the combo's current data ("—") rather than re-reading settings.- MainWindow scope is clean. The three-dot PR diff only touches the migration default (
CatPort_0_VfoB→-1); the locale-date hunk that shows up in a two-dot diff is just a stale-branch artifact (branched at23ef4556, before #3511 merged) and won't revert that feature on merge.
Two small observations, neither blocking:
-
persistVfo()ambiguity for VFO A. When a saved-but-unavailable slice exists (smaller radio) and the combo has fallen back to the fallback entry, a user deliberately selecting that fallback slice (e.g. genuinely picking slice A) is indistinguishable from the fallback and gets ignored in favor of the preserved value. This is the documented, intended trade-off and the right default — just noting it's a real (if rare) corner where a deliberate pick won't stick until the slices return. -
Pre-existing migrated users keep
CatPort_0_VfoB="1". The migration is guarded by!contains("CatPort_0_Port"), so anyone who already migrated under the old seed retains the stored1for the rigctld port. It's harmless (rigctld ignores it, andapplyRowToSettingsno longer persists it), and it would resurface as slice B only if they later switch that port to a dual-VFO dialect — arguably reasonable. Worth a mention only so it's a known behavior, not a surprise.
Nice work, and the issue write-up in #3694 made the intent very clear. 👍
🤖 aethersdr-agent · cost: $4.3580 · model: claude-opus-4-8
ten9876
left a comment
There was a problem hiding this comment.
Thorough review complete — approving.
Verified independently (not just from the diff):
- Satisfies #3694 fully — all three acceptance criteria: rigctld VFO B forced to "—" and disabled (load-time via
updateRowLockedat build, not just on toggle); saved VFO B preserved across a dialect switch and restored on switch-back; migration no longer seeds a VFO B for the default rigctld port. CatPort::kVfoNonereuse replaces magic-1literals (constant pre-existed) — clean.CatPopoutWindowdeletion is safe — every reference lived inside the two deleted files, and it was not inCMakeLists.txt(explicit source list), so it was never compiled.- MainWindow scope is clean — three-dot diff touches only the migration default; no #3511 locale-date revert on merge.
- Restore-by-data (VFO A and B, in load +
setMaxSlices) fixes a latent index/qMinrepointing bug; runtime wiring (CatPort.cpp/RigctlProtocol.cpp) is untouched, so VFO B stays functional where consumed.
On @jensenpat's hold (well-raised): the persistence change does reach the shared path, but its behavioral delta is confined to the smaller-radio-reconnect corner — when a saved slice is unrepresentable, persistVfo preserves it instead of clobbering; for any representable selection on a same-size radio it is byte-for-byte identical to the prior setValue, so the dual-VFO/SmartCAT common path is unchanged. The one documented limitation (a deliberate re-pick of the fallback entry in that corner won't stick until the slices return) is an accepted trade-off.
Decision to land now rather than hold: our release velocity makes a long-lived parallel branch drift too far from main to test meaningfully — holding it would add integration risk rather than reduce it. Scope captured accurately in the squash subject per @jensenpat's point.
Thanks @K5PTB — the per-branch "why" comments made this easy to verify, and the #3694 write-up was excellent.
Summary
Fixes #3694.
The CAT-config UI exposed a VFO B selector for every port regardless of dialect, but the rigctld (Hamlib) dialect is single-VFO per port —
CatPortwires a rigctld client with only the RX slice (RigctlProtocolhas no VFO B input), and split is create-on-demand (VFOB/SUBresolves to a dedicated TX slice only when a client issuesset_split_vfo 1). So a configured VFO B has no effect on a rigctld port, yet the selector was shown and persisted.dialectSupportsVfoB(CatDialect)inCatPort.h, instead of scattered hard-coded checks, so every config surface shares one rule.VfoB=-1(not1) for the default rigctld port.src/gui/CatPopoutWindow.{cpp,h}— a dead duplicate of the CAT-config row (same VFO B selector +applyRowToSettings) that was never instantiated and not in the build.Constitution principle honored
N/A — narrow GUI/config bug fix. No new persistence schema (uses the existing
CatPort_*_Vfo*keys) and no protocol surface change.Test plan
cmake --build build)Checklist
AppSettingscalls — only existingCatPort_*_Vfo*/DialectkeysBuilt and smoke tested on: MacBook Air M2 / RPi 5 Debian trixie / Win 11 i3
🤖 Generated with Claude Code