Skip to content

[xvtr] Clamp XVTR Max Power before sending#3273

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:aether/xvtr-max-power-clamp
May 30, 2026
Merged

[xvtr] Clamp XVTR Max Power before sending#3273
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:aether/xvtr-max-power-clamp

Conversation

@jensenpat

Copy link
Copy Markdown
Collaborator

Summary

  • Mirror FlexLib XVTR MaxPower bounds in XvtrPolicy so AetherSDR clamps before sending xvtr set ... max_power=.
  • Add a QDoubleValidator to the Radio Setup XVTR Max Power field using the active radio model and IF-frequency-dependent dBm range.
  • Clamp again on submit, including after IF frequency edits that tighten the allowed Max Power ceiling.
  • Add focused xvtr_policy_test coverage for the FlexLib ranges: -10 dBm floor, +8 dBm high IF ceiling, +10 dBm 6400/6600 low IF ceiling, and +15 dBm default low IF ceiling.

Refs #3246 (fix #3 only: XVTR Max Power clamp).

Test Plan

  • cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
  • cmake --build build -j22
  • ./build/xvtr_policy_test
  • Built app: /Users/patj/.codex/worktrees/145c/AetherSDR/build/AetherSDR.app
  • Deploy attempted with $deploy-aethersdr-test-build; upload reached the remote, but replacing /Users/patj/Desktop/AetherSDR.app failed repeatedly because remote rm returned Operation not permitted for the existing app bundle contents.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

Co-authored-by: Codex <noreply@openai.com>
@jensenpat jensenpat self-assigned this May 29, 2026
@jensenpat jensenpat changed the title Clamp XVTR Max Power before sending [xvtr] Clamp XVTR Max Power before sending May 29, 2026
@jensenpat jensenpat marked this pull request as ready for review May 29, 2026 18:31
@jensenpat jensenpat requested review from a team as code owners May 29, 2026 18:31

@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.

Nice, focused change — thanks @jensenpat. The split between XvtrPolicy (pure policy logic, easy to test) and the dialog wiring is clean, and the test coverage hits the four FlexLib boundary points called out in the description.

A few small observations, none blocking:

  • submitMaxPower(false) change-detection. Using qFuzzyCompare(requested + 1.0, clamped + 1.0) works, but since std::clamp returns the input value verbatim when it's already in range, a direct requested == clamped would be equivalent here (no intervening fp arithmetic) and reads more clearly. Pure nit — feel free to leave as-is.

  • Empty / invalid maxPwrEdit on IF edit. When IF changes and maxPwrEdit is blank or non-numeric, toDouble(&ok) returns false and submitMaxPower(false) no-ops without sending. That's the right call (don't synthesize a value the user never entered), just worth a quick sanity-check that the field is always populated by the load path before this becomes user-visible.

  • usesLegacyLowIfMaxPower model match. Uppercase+trim on the exact strings FLEX-6400/6400M/6600/6600M is what FlexLib reports, so this should be fine, but it's strict — if RadioModel::model() ever returns something with extra suffixes or a different separator for a future variant, it'll silently fall back to the +15 dBm default. The tests pin the current set, so easy to revisit if/when needed.

  • 80 MHz boundary. >= 80.0 puts exactly-80 MHz IF on the high-IF +8 dBm rail, which matches your "high IF caps max power at +8 dBm" test at IF=80.0. Worth confirming this matches FlexLib's >= vs > at the exact boundary, since we're mirroring their behavior.

Conventions look good — XvtrPolicy namespace + free functions consistent with the existing file, QDoubleValidator parented to maxPwrEdit (RAII fine), no QSettings introduced, validator updates pair correctly with the IF-edit handler. Ship it.


🤖 aethersdr-agent · cost: $5.3302 · model: claude-opus-4-7

@ten9876

ten9876 commented May 30, 2026

Copy link
Copy Markdown
Collaborator

@AetherClaude are we good to merge this one?

@aethersdr-agent

Copy link
Copy Markdown
Contributor

@ten9876 I reviewed the diff against src/models/XvtrPolicy.{h,cpp}, RadioSetupDialog.cpp, and the test, plus CI. This looks good to merge — no blockers.

What's solid

Minor, non-blocking nits (fine to land as-is or fold into a follow-up):

  1. Decimal display inconsistency. The field is initialized with one decimal (RadioSetupDialog.cpp:2732, QString::number(x.maxPower, 'f', 1)), but the validator and submitMaxPower both format with two ('f', 2). So an untouched field shows 10.0 and flips to 10.00 after the first edit. Purely cosmetic; aligning the initial render to 'f', 2 would make it consistent.

  2. High-IF boundary is inclusive at 80 MHz. ifFreqMhz >= kHighIfThresholdMhz puts exactly 80.0 in the +8 dBm bucket (the test asserts this). Worth a quick confirm that FlexLib treats the 80 MHz edge the same way, since that's the one value where inclusive vs. exclusive changes the ceiling.

  3. Empty/non-numeric IF text falls through toDouble()0.0 → low-IF branch (default/legacy ceiling). Harmless, just noting the implicit default.

None of these change correctness, so I'd be comfortable merging once you're happy with the cosmetic decimal point.

73, Jeremy KK7GWY & Claude (AI dev partner)


🤖 aethersdr-agent · cost: $3.0873 · model: claude-opus-4-8

@ten9876

ten9876 commented May 30, 2026

Copy link
Copy Markdown
Collaborator

@AetherClaude push a fix for the nits on top of the PR

@aethersdr-agent

Copy link
Copy Markdown
Contributor

@ten9876 I went back through the three nits against the PR diff. Only nit #1 is an actual code change; #2 and #3 were confirmations/notes. Here's the concrete fix.

Nit #1 — decimal display consistency (the real one)

The field is still initialized with one decimal, while the validator and submitMaxPower both use two. So an untouched field renders 10.0 and snaps to 10.00 on the first edit. The PR didn't touch the init line, so this is the only line that needs to change:

src/gui/RadioSetupDialog.cpp:2732

// before
auto* maxPwrEdit = addField(4, 0, "Max Power (dBm):", QString::number(x.maxPower, 'f', 1));

// after
auto* maxPwrEdit = addField(4, 0, "Max Power (dBm):", QString::number(x.maxPower, 'f', 2));

That's a one-character change (12) and aligns the initial render with the validator/submitMaxPower formatting.

Nit #2 — 80 MHz inclusive boundary

ifFreqMhz >= kHighIfThresholdMhz puts exactly 80.0 in the +8 dBm bucket, and the test (tests/xvtr_policy_test.cpp) asserts it. This is a behavioral question about whether FlexLib treats the 80 MHz edge inclusively, not a defect — I'd leave the code as-is unless @jensenpat wants to confirm against FlexLib and flip to > if it should be exclusive. No code change recommended without that confirmation.

Nit #3 — empty/non-numeric IF text

Empty IF text falls through toDouble()0.0 → the low-IF branch, which is the safe/permissive default. Harmless and arguably the desired fallback, so no change needed. If you want it explicit it'd be a comment rather than logic.

So the only fix to land is the 'f', 1'f', 2 change above. It's a pure-cosmetic, zero-risk edit with no test impact.

The aetherclaude-eligible label isn't on this issue yet — a maintainer can authorize the orchestrator to land this fix by adding the aetherclaude-eligible label, and it'll open the follow-up commit on the next webhook cycle.

73, Jeremy KK7GWY & Claude (AI dev partner)


🤖 aethersdr-agent · cost: $1.9395 · model: claude-opus-4-8

@ten9876 ten9876 merged commit 5a2c0e6 into aethersdr:main May 30, 2026
5 checks passed
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
## Summary

- Mirror FlexLib XVTR MaxPower bounds in `XvtrPolicy` so AetherSDR
clamps before sending `xvtr set ... max_power=`.
- Add a `QDoubleValidator` to the Radio Setup XVTR Max Power field using
the active radio model and IF-frequency-dependent dBm range.
- Clamp again on submit, including after IF frequency edits that tighten
the allowed Max Power ceiling.
- Add focused `xvtr_policy_test` coverage for the FlexLib ranges: -10
dBm floor, +8 dBm high IF ceiling, +10 dBm 6400/6600 low IF ceiling, and
+15 dBm default low IF ceiling.

Refs aethersdr#3246 (fix aethersdr#3 only: XVTR Max Power clamp).

## Test Plan

- `cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`
- `cmake --build build -j22`
- `./build/xvtr_policy_test`
- Built app:
`/Users/patj/.codex/worktrees/145c/AetherSDR/build/AetherSDR.app`
- Deploy attempted with `$deploy-aethersdr-test-build`; upload reached
the remote, but replacing `/Users/patj/Desktop/AetherSDR.app` failed
repeatedly because remote `rm` returned `Operation not permitted` for
the existing app bundle contents.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by
@jensenpat

Co-authored-by: Codex <noreply@openai.com>
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.

2 participants