Skip to content

SmartMTR meter view (#3723) — consolidated fast-follow fixes #3750

Description

@ten9876

Consolidated fast-follow for the SmartMTR meter view merged in #3723 (RFC #3450). The feature is solid and shipped opt-in with the S-meter path pixel-identical; these are the review findings deferred to a follow-up so #3723 could land. Grouped by severity. File/line refs are against the #3723 head at merge.

HIGH — team-owned (KiwiSDR)

H1 — KiwiSDR / non-FLEX sources show a false S0 reading on the SmartMTR needle

VfoWidget::pushSmartMtrInput() hardcodes the FLEX scale (in.min = -127.0 S0, in.max = -13.0 S9+60) for every source (src/gui/VfoWidget.cpp:3297-3298). When a KiwiSDR slice has no calibrated meter, the receive path sets the sentinel m_signalDbm = -130.0f and the dBm label correctly shows "Meter ---" (src/gui/VfoWidget.cpp:3488) — but the SmartMTR needle clamps -130 to S0 and renders a confident S0, contradicting the "unavailable" label. The numeric value labels print the raw sub-S0 dBm.

Note: the PR author was not aware of our KiwiSDR public-receiver implementation (#3679 / a71a1c81), so this interaction is on us (AetherSDR team) to fix, not the contributor.

Fix: plumb the existing "no calibrated dBm" state into MeterInput and render no-data (blank / "---") on the needle and value labels instead of pegging S0. Longer term, source the dBm scale (and the S-unit reference) from the active source's meter calibration rather than hardcoding the FLEX mapping.

MEDIUM

M1 — TX/mic ("external-peak") mode never lets the 120 Hz timer settle

In mic mode the held peak stands off above the needle by design, so the keep-alive condition stays true and m_animTimer repaints at 120 Hz over the GPU panadapter for the entire TX duration (src/gui/MeterExtremes.h:147). Bounded (PTT release calls reset()), so not an unbounded leak — but it defeats the idle-savings intent of the perf work done in 0835a632/42d0e144.
Fix: in external-peak mode, keep animating only while actually moving, or decay the external peak toward the needle so it converges when packets pause.

M2 — No isfinite guard; NaN/Inf permanently poisons the meter

A non-finite dBm value flows through std::clamp (returns NaN) into m_smooth (sticks at NaN, timer never stops) and into MeterExtremes::m_sumRaw (NaN forever, corrupting avgRaw() → value labels), with no recovery short of reset() (src/gui/SmartMtrWidget.cpp:128-135, src/gui/MeterExtremes.h:69).
Fix: if (!std::isfinite(input.value)) return; (or coerce to floor) at setMeterInput before it reaches the smoother and record().

M3 — Cross-flag option-control desync with multiple selectors open

With the inline meter selector open on two VFO flags, toggling e.g. "Show extremes" on flag A updates both meters' rendering but leaves flag B's checkbox/combos stale — the global MeterViewController::extremesChanged/txMeterChanged signals are wired only to the rendering push, never to re-seed the per-flag control widgets (src/gui/VfoWidget.cpp:328-333). The meter-view selector buttons re-sync correctly (via applyMeterViewsyncMeterMenuButtons); only the four option controls (m_showExtremesChk, m_extremesSpeedCmb, m_showValuesCmb, m_txMeterCmb) are unsynced.
Fix: connect those signals to a small slot that resets each control from MeterViewController (wrap in QSignalBlocker to avoid a re-broadcast loop), then calls syncSmartMtrSettingsState().

M4 — Font change doesn't invalidate the cached marker layer

The static-layer pixmap cache key is {size, kind, dpr} only; there's no changeEvent() override, so a theme/app font-size change leaves stale label glyphs in m_aboveBar until a resize/kind/DPR change happens to occur (src/gui/SmartMtrWidget.cpp:353).
Fix: override changeEvent and invalidate the cache on QEvent::FontChange / ApplicationFontChange (and StyleChange if a palette path is added).

LOW / NITS

  • L1 — Dead no-op seed call + misleading comment at src/gui/VfoWidget.cpp:885 (pushSmartMtrInput(); // seed the at-rest display): m_smartMtr is still false at construction so the new gate returns immediately; the real seed happens in applyMeterView(). Drop the line or fix the comment.
  • L2src/gui/DisplaySettings.h:11-18 comment claims legacy LeanMode "is migrated into this blob on first read." It's actually an explicit migrateLegacy() call at startup (MainWindow.cpp:971); readObj() does no migration. Reword.
  • L3MeterExtremes leaves stale m_minRaw/m_maxRaw when the sliding window empties (only m_hasData=false is set). Harmless today (all readers gate on hasData()), latent trap for any future reader. Reset both to a sentinel alongside m_hasData=false.

Refs: PR #3723, RFC #3450. Review verified against the merged head; H1, M1, M3 spot-checked against source.

Metadata

Metadata

Assignees

Labels

GUIUser interfacebugSomething isn't workingexternal devicesFlexControl, MIDI, serial port, USB peripheralsmaintainer-reviewRequires maintainer review before any action is takenpriority: mediumMedium priority

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions