feat(applet): SSDR-parity PWR/SWR metering for PGXL and TGXL applets#3277
Conversation
Adds the numeric readouts and bargraph missing from the PGXL amplifier applet compared to SmartSDR's reference layout. Principle I (FlexLib authority / display parity). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the PGXL applet improvements for the TGXL tuner:
- External "PWR" / "SWR" row labels with live numeric values
("PWR 987", "SWR 1.2:1") replacing the centred internal gauge labels
- Values suppressed at idle (< 5 W) to avoid noise-floor clutter
- Label text throttled to 10 Hz via QTimer (kMeterReadoutUpdateMs);
bargraph fill continues to animate at full frame rate
- Fwd-power gauge uses 30 ms attack / 800 ms release ballistics so
brief RF bursts remain visible for ~0.8 s after key-up
- HGauge::setBallistics() added (public setter for MeterSmoother
ballistics, same change present in feat/pgxl-parity-telemetry)
Principle I (display parity with SmartSDR reference).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hold The per-tick timer was causing PWR/SWR text to blink visibly because TGXL meter updates arrive at a slower, irregular cadence — values oscillated around the 5 W gate on nearly every timer firing. Replace the polling timer with a synchronous call to updateValueLabels() directly from updateMeters(). Add an 800 ms single-shot hold timer so the label stays visible after power drops below threshold; inter-packet noise below 5 W no longer causes flicker. Principle XI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@AetherClaude ok, let's try this. These changes need to be done as one in preparation for a contest, where the tuner and amp controls need to be displaying the proper information during a major contest. |
|
Acknowledged — contest prep makes the combined PR the right call; doing PGXL and TGXL together avoids a half-instrumented station during the event. I've confirmed the scope maps to files in the tree:
A couple of notes I'll carry into the implementation, mostly to flag to you up front so nothing surprises during the contest:
The 73, Jeremy KK7GWY & Claude (AI dev partner) 🤖 aethersdr-agent · cost: $2.1643 · model: claude-opus-4-7 |
|
@AetherClaude confirmed this is working on Windows, locally. Should be the same on Linux and Mac. |
|
Excellent — that's exactly the layout we were targeting. Screenshot confirms all the SSDR-parity pieces are landing correctly:
Qt's widget stack is platform-agnostic for this kind of layout work (QHBoxLayout / QLabel / custom paint in A few things I'd suggest verifying once you can put it under load during the contest:
Glad this came together in time for the contest prep. Good luck with the operating event! 73, Jeremy KK7GWY & Claude (AI dev partner) 🤖 aethersdr-agent · cost: $0.7608 · model: claude-opus-4-7 |
There was a problem hiding this comment.
Thanks @chibondking — nice consolidation, and the PR description does a great job tracing the SSDR-parity reasoning. A few notes:
Things that look good
PgxlConnectionS-push parser fix (src/core/PgxlConnection.cpp:117-123) is a real bug fix. The originalif (lastSpaceBeforeEq < 0) return;silently dropped the bare-KV form. The new branch handles both prefixed (S0|TRANSMIT_A id=39 …) and bare (S0|id=39 …) bodies correctly, and the inner split-on-space +indexOf('=')still handleskey=value=with=equalssinceindexOfreturns the first=.HGauge::setBallistics()is a clean addition — sits on the existingMeterSmootherplumbing and doesn't disturb the default ballistics for other gauges.- Compound
temp = "A/B"parsing inMainWindow.cppis duplicated across the direct-TCP and radio-proxy paths but that mirrors the existing structure of those two handlers, so I wouldn't refactor it as part of this PR.
Suggestions
-
m_labelTimerruns at 10 Hz unconditionally inAmpApplet(src/gui/AmpApplet.cppconstructor) — it ticks even when the applet is hidden or the PGXL is disconnected. Cheap, but consider stopping/starting it inshowEvent/hideEvent(or justupdate*()-on-write likeTunerAppletdoes) to keep idle wakeups down. Not blocking. -
Two different throttling strategies for nominally the same problem (PGXL = 10 Hz QTimer, TGXL = synchronous + 800 ms single-shot hold). The PR description acknowledges this. Worth a follow-up to converge on one — the synchronous-with-hold pattern in
TunerAppletis the simpler of the two and doesn't waste timer ticks at idle. -
m_labelClearTimerlambda inTunerAppletis wired up beforebuildUI()createsm_pwrLabel/m_swrLabel. It's safe in practice because the timer is only started fromupdateValueLabels()(post-construction), but a one-line comment noting the ordering invariant would help — the next reader will be tempted to move things around. -
Idfield name is acknowledged as a placeholder in the PR description pending pcap analysis. Worth opening a tracking issue so it doesn't fall off — if the real field name turns out to be e.g.drain_irather thanid, the gauge will appear permanently stuck at zero with no compile-time hint that anything is wrong. -
Minor:
AmpApplet::setMeff()now silently discards its argument. If it's truly dead, the slot could be removed (and its callsite inMainWindow) rather than left as a no-op; otherwise a one-line comment in the header next to the declaration would explain that it's intentionally a stub for now.
Nothing here blocks — the parser fix alone is worth landing. LGTM with the above as cleanups.
🤖 aethersdr-agent · cost: $8.4931 · model: claude-opus-4-7
…abels - setPowerScale: add 1K tick and yellowStart to all three scale modes so the green/yellow/red zones render correctly (setRange without yellowStart collapsed the zone to zero-width, showing only green/red) - Amplifier mode ticks now match PGXL exactly: 0 500 1K 1.5K 2K - PWR/SWR row labels bumped from 10px to 11px in both AmpApplet and TunerApplet for better readability. Principle I. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@AetherClaude updated with feedback from the contest |
…ields id= in the PGXL protocol is the device/port identifier (always 2), not drain current. Remove both path handlers to stop showing a static "2". The correct field name for drain current requires pcap analysis of the direct PGXL TCP protocol — deferred post-contest. Vdd/Vac only arrive via direct TCP; the radio proxy path does not forward them, so no change needed there. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
id= is the PGXL drain current field, confirmed working via S-push after the parser fix in PgxlConnection. The idle reading of ~2 A is correct at no-TX; it tracks real current during transmit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a small "● DIRECT" (cyan) / "● RADIO" (grey) label in the bottom info panel so the user can see which telemetry path is active. Direct TCP gives full telemetry (id, vdd, vac, temp, state); the radio proxy fallback provides a subset. Indicator updates on connect/disconnect of the direct PGXL TCP connection. Principle I. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the TX Controls panel behaviour. HGauge gains clearPeak() to disable the marker. Both AmpApplet and TunerApplet track the running peak and restart a 2.5 s single-shot timer on each new high-water mark; the tick clears automatically when no higher value arrives within the hold window. Principle I. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the radio proxy path is active, Vdd and Vac are not forwarded by the radio. setDirectConnected(false) now dims both labels to #505050 and resets their text to —, preventing stale values from misleading the user. setDrainVoltage/setMainsVoltage are no-ops while not directly connected so a future field-name match can't silently overwrite them. Principle I. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jensenpat
left a comment
There was a problem hiding this comment.
Thanks for the PGXL / TGXL meter improvements CJ.
…ethersdr#3277) ## Summary Consolidates PGXL and TGXL applet metering improvements into one PR. Closes aethersdr#3276 and the PGXL applet PR. ### PGXL (Amplifier applet) - **External row labels** — PWR, SWR, and Id labels left-aligned at 72 px carry live numeric values (`PWR 933`, `SWR 1.2:1`, `Id 25`); internal gauge labels cleared - **Id bargraph** — new drain-current gauge (0–70 A, red > 60 A) with label row matching SSDR layout - **Bottom info row** — temperature, Vdd, and Vac values displayed in the empty space left of the OPERATE button - **Slow-release fwd-power ballistics** — `{30 ms attack / 800 ms release}` on fwd gauge so brief TX bursts stay visible - **100 ms label throttle** — value labels update at 10 Hz via QTimer; gauge fill animates at full rate - **S-push parser fix** — `PgxlConnection` was silently dropping S-push messages whose KV string began directly with `key=value` (no prefix word); fixed with a conditional instead of an early return - **Telemetry field fixes** — `tempb`, `vdd`, and compound `temp` (`"34.5/28.1"`) now handled in both direct-TCP and radio-proxy data paths ### TGXL (Tuner applet) - **External row labels** — same 72 px PWR/SWR label pattern as PGXL - **Slow-release fwd-power ballistics** — same `{30 ms / 800 ms}` profile - **Label update strategy** — synchronous update on each meter event (no polling timer) with an 800 ms single-shot hold so inter-packet noise below 5 W doesn't cause flicker ### Shared - **`HGauge::setBallistics()`** — added as public API so individual gauges can opt into custom attack/release curves ### Deferred - Id drain-current field name requires pcap analysis to confirm (PGXL protocol not fully documented); field name placeholder in place ## Test plan - [x] PGXL connected: PWR, SWR, Id bars and labels update during TX; temp/Vdd/Vac show in bottom row - [x] PGXL: fwd gauge decays slowly (~800 ms) after TX ends - [x] TGXL connected: PWR and SWR labels appear during TX, hold 800 ms after, no flicker at threshold - [x] No regression on relay bars, TUNE button, OPERATE/BYPASS/STANDBY cycle, antenna switch 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

Summary
Consolidates PGXL and TGXL applet metering improvements into one PR. Closes #3276 and the PGXL applet PR.
PGXL (Amplifier applet)
PWR 933,SWR 1.2:1,Id 25); internal gauge labels cleared{30 ms attack / 800 ms release}on fwd gauge so brief TX bursts stay visiblePgxlConnectionwas silently dropping S-push messages whose KV string began directly withkey=value(no prefix word); fixed with a conditional instead of an early returntempb,vdd, and compoundtemp("34.5/28.1") now handled in both direct-TCP and radio-proxy data pathsTGXL (Tuner applet)
{30 ms / 800 ms}profileShared
HGauge::setBallistics()— added as public API so individual gauges can opt into custom attack/release curvesDeferred
Test plan
🤖 Generated with Claude Code