You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored
feat(gui): make SmartMTR's meter ballistics project canon. Principle XI. (#5847)
## Why
Follow-up to #5845. While fixing the TGXL peak marker, the TGXL gauge
and the TX Controls applet — sitting side by side, reading the same
transmission — visibly disagreed on how the needle and the peak behaved.
They disagreed because they were running different code.
SmartMTR (the VFO flag meter) is the one meter in the tree whose
ballistics were actually designed rather than tuned by eye. Everything
else had drifted:
- a `setBallistics({0.030f, 0.800f})` override copy-pasted across
**six** applets, silently replacing `MeterSmoother`'s defaults;
- **five** separate hand-rolled hold-then-decay peak markers (Tuner,
Amp, Acom, Spe, Vkamp/Tx), no two sharing a hold time or a decay rate.
Jeremy's call: SmartMTR's ballistics are canon.
## What
**One smoother.** `MeterSmoother`'s defaults are now SmartMTR's
d'Arsonval ballistic — 18.2 ms attack / 269 ms release, derived from its
k=0.60/0.06 at 60 Hz. All six `setBallistics()` overrides are
**deleted** rather than re-tuned; the point is that there is one answer,
not a better second one.
**One peak engine.** `MeterExtremes` — SmartMTR's sliding-window
envelope tracker — is generalised with `scaleMin`/`scaleMax` so it works
in watts as well as its own UNIT span, and `HGauge` now drives its peak
marker from it. The marker glides at constant velocity over a 3 s window
and retires because the window rolls past the peak; there is no hold
phase left to tune. Slew is scaled per gauge so a marker crosses any
range in the same ~3.7 s it takes to cross SmartMTR's.
**Device-reported peaks keep their own path.** The TGXL reports `peak`
and the radio reports MICPEAK — both are real measurements taken closer
to the signal than our polling can get. Those feed `setExternalPeak()`,
SmartMTR's external-peak mode: the marker *is* the device's number,
tracked at the fast peak slew, retiring when the device retires it. The
five applet-side hold/decay implementations are gone.
## Two integration bugs found while wiring this up
Both would have frozen the marker on screen, and both are worth knowing
about before touching this again:
1. The engine clamps the marker to sit at or above the needle. Hand it
the *raw* target and it drags the marker straight to the new reading —
no glide at all. It has to be handed the **painted** needle position.
2. The window's clock only advances inside the animation tick. Stop the
timer while a marker is still standing off the needle and the window can
never expire, so the marker stays stranded at the old peak forever.
`tick()`'s return value is now the sole keep-alive.
## Testing
- Full suite: **523/524**. The one failure is
`connection_panel_size_test`, which fails identically on `main`
(pre-existing, ConnectionPanel 150%-scaling, #4515 territory).
- `tgxl_docked_parity_test` and `amp_applet_test` peak tests rewritten.
They assert the **shape** — the marker glides rather than jumping,
stands off above the needle, and comes back down on its own — not the
constants, so the window can be retuned without rewriting them.
- The amp test discriminates: it failed against both integration bugs
above during development.
## Note for review
This changes how **every** meter in the app moves, not just the two that
prompted it. That is the intent, but it is worth eyes on: if some meter
was quietly depending on the slower 800 ms release to look right, this
will change it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01AmTu3avSWtEovX1kuuZsWn
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: jensenpat <patjensen@gmail.com>
0 commit comments