Skip to content

feat(tmate2): enhanced display — TX bargraph, text overlays, encoder labels#3542

Merged
NF0T merged 5 commits into
aethersdr:mainfrom
svabi79:feat/tmate2-v2-enhanced-display
Jun 13, 2026
Merged

feat(tmate2): enhanced display — TX bargraph, text overlays, encoder labels#3542
NF0T merged 5 commits into
aethersdr:mainfrom
svabi79:feat/tmate2-v2-enhanced-display

Conversation

@svabi79

@svabi79 svabi79 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #3401 (TMate 2 HID integration). Four improvements hardware-verified on ELAD TMate 2, all guarded with #ifdef HAVE_HIDAPI.

TX power bargraph (HidEncoderManager.cpp)

  • During transmit the 15-bar S-meter bargraph now shows TX forward power instead of the RX S-meter reading.
  • Full-scale auto-adapts: 100 W normally, 2000 W when an amplifier is connected and in operate.
  • Reads from three power sources: FWD meter, PGxl amplifier forwarded power, and the standard transmitPowerChanged signal — whichever fires updates the display.

TX power on small display (MainWindow_Controllers.cpp)

  • Small 3-digit display shows watts during TX (e.g. 95 → "95 W") and switches to Nk M format above 999 W (e.g. 1500 W → "1k5 W") so the segment count never overflows.
  • In RX the display continues to show |dBm| as before.

Encoder label segments (HidEncoderManager.cpp)

  • setTMate2EncoderActionSegs() reads the two auxiliary encoder assignments and lights the matching silkscreen labels (VOL / DRV / SQL and HIGH / SHIFT) so the LCD reflects the user's mapping without opening the settings dialog.
  • S-meter scale tick marks (S1 S3 S5 S7 S9 +20 +40 +60 dB) are now driven in RX and blanked in TX/overlay, matching what the physical LCD is labelled.
  • RIT / XIT segments light when the respective wheel action is mapped to an encoder, even when RIT/XIT offset is zero.

Text overlays + letter glyphs (HidEncoderManager.cpp, MainWindow_Controllers.cpp)

  • Added tmate2MainGlyph() / tmate2SmallGlyph() for a 7-segment letter subset (A C E F G H I K L M N O P R S T U V W X Y, -, space) — enough to spell the feedback labels below.
  • New triggerTMate2TextOverlay() + TMate2Overlay::Text variant for arbitrary 9-character strings on the main display.
  • updateTMate2Display() now builds a human-readable overlay string per type: "VOL 050", "RIT +1200", "AGC SLO", "APF 42", "TUNE ON", etc.
  • New overlay types: Xit, Shift, Agc, Apf (with indicator segment handling in setTMate2OverlayIndicators).
  • Toggle actions now confirm state on the display: ToggleTune → "TUNE ON/OFF", ToggleMute → "MUTE ON/OFF", ToggleLock → "LOCK ON/OFF", ToggleApf → "APF ON/OFF", ToggleAgc → "AGC OFF/SLO/MED/FST".

Files changed

File Change
src/core/HidEncoderManager.h setTMate2Indicators signature extended (new params default-valued); two new public slots
src/core/HidEncoderManager.cpp Glyph tables, text write helpers, encoder-label helpers, powerBars(), overlay indicator updates
src/gui/MainWindow.h TMate2Overlay enum extended; m_tmate2OverlayText; triggerTMate2TextOverlay()
src/gui/MainWindow.cpp TX indicator refresh hooked into three power-update paths
src/gui/MainWindow_Controllers.cpp formatTMate2PowerSmallText(), richer overlay dispatch, toggle action feedback

Test plan

  • RX: S-meter bargraph tracks signal; tick marks S1–+60 dB visible
  • TX: bargraph tracks forward power 0–100 W; small display shows watts
  • TX with amplifier in OPER: bargraph full-scale = 2000 W; small display shows Nk M above 999 W
  • Encoder-label segments (VOL/DRV/SQL/HIGH/SHIFT) match settings after reconnect
  • RIT active → RIT segment lit; encoder mapped to WheelRit with RIT off → RIT segment lit
  • Overlay text overlays: rotate volume/AGC/APF/RIT/XIT; observe formatted readout
  • Toggle actions: Tune/Mute/Lock/APF/AGC show confirmation overlay text

🤖 Generated with Claude Code

@svabi79 svabi79 requested a review from a team as a code owner June 12, 2026 22:33
@svabi79 svabi79 force-pushed the feat/tmate2-v2-enhanced-display branch from 221c505 to ae75721 Compare June 12, 2026 22:39

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

Thanks @svabi79 — this is a careful follow-up to #3401, and the structure is right: everything stays behind HAVE_HIDAPI, the new glyph writers preserve the shared indicator bits with the same masks as the digit writers (0xF8/0xF0 main, 0x0F/0x1F small), settings go through AppSettings, and the TX-watts updates were correctly placed inside the already-amp-gated meter lambdas, so the exciter/amp alternating-writer race from #2927 doesn't reappear on the LCD. The E1/E2 ↔ TMate2EncoderAction2/1 swap is well-commented and its hardcoded fallbacks match the canonical defaults in tmate2EncoderDefaultAction().

Two real display bugs to fix before merge:

1. Missing 'D' glyph — "AGC MED" renders as "AGC ME " (HidEncoderManager.cpp, tmate2MainGlyph)
The glyph table has no case for 'D'/'d', so it falls through to blank. ToggleAgc's labels include "AGC MED", which will display as AGC ME. Please add a 'D' glyph (the usual 7-segment lowercase-d: segments B+C+D+E+G) — worth a quick hardware check since you have the unit on the bench.

2. 10 kHz step overlay truncates to "STEP 1000" (MainWindow_Controllers.cpp, updateTMate2Display)
Speed formats QStringLiteral("STEP %1").arg(mainVal, 4, …). RxApplet::m_stepSizes goes up to 10000, so the string becomes "STEP 10000" (10 chars) and tmate2WriteMainDisplayText keeps only text.left(9) → the display reads STEP 1000 for the 10 kHz step — the previous numeric path handled this correctly, so this is a regression. Suggest a shorter label ("STP %1") or formatting ≥1000 Hz steps as "STEP 10k" (the K glyph exists).

Minor:

  • isWpm is now unused in setTMate2OverlayIndicators() after applyModeSegs(QString()) replaced the CW-forcing — this will trip -Wunused-variable under the project's -Wall -Wextra. Just drop the variable.
  • formatTMate2PowerSmallText() doesn't guard non-finite inputstd::lround(NaN) is unspecified. powerBars() checks std::isfinite; the small-text formatter takes the same meter-derived float, so a one-line if (!std::isfinite(watts)) watts = 0.0f; would make them symmetric.
  • TMate2Overlay::Shift is added but never triggered — nothing calls triggerTMate2Overlay(TMate2Overlay::Shift, …), and its text case currently shares the "STEP" label with Speed, which would read wrong if it's ever wired up. Fine if it's groundwork for a follow-up; if so, a // not yet triggered note (or giving it its own label now) would prevent surprise later.

No scope concerns — the five files match the stated feature, no new settings keys, and the setTMate2Indicators signature extension uses default-valued params so any other caller stays source-compatible. With the two display bugs fixed this looks good.


🤖 aethersdr-agent · cost: $17.0298 · model: claude-fable-5

Follow-up to review on aethersdr#3542:

- Add 'D'/'d' main-display glyph (B+C+D+E+G); without it "AGC MED"
  rendered as "AGC ME" since the table fell through to blank.
- Tuning-step overlay used "STEP %1" which overflowed to 10 chars for
  the 10 kHz step and truncated via text.left(9) to "STEP 1000". Use
  the shorter "STP" label so "STP 10000" fits exactly in 9 chars.
- Give TMate2Overlay::Shift its own "SHFT" label + a not-yet-triggered
  note so it can never inherit the STEP readout if wired up later.
- Drop now-unused isWpm local in setTMate2OverlayIndicators().
- Guard formatTMate2PowerSmallText() against non-finite watts before
  std::lround(), mirroring powerBars().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@svabi79

svabi79 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the careful review — all five points addressed in dd8ba6f:

Display bugs

  1. 'D' glyph — added case 'D': case 'd': return { 0x06, 0x0E }; (B+C high, D+E+G low), so AGC MED no longer falls through to blank (AGC ME). Good catch.
  2. STEP truncation — switched the Speed overlay to the short "STP %1" label with field width 5, so the 10 kHz step is "STP 10000" = exactly 9 chars and no longer truncates. Confirmed against amSettings ({250,500,2500,3000,5000,9000,10000}), 10000 being the widest preset.

Minor
3. isWpm — dropped; it was dead after applyModeSegs(QString()) replaced the CW-forcing path.
4. formatTMate2PowerSmallText non-finite — added if (!std::isfinite(watts)) watts = 0.0f; before the lround, symmetric with powerBars().
5. TMate2Overlay::Shift — you're right it's groundwork (no dispatcher raises it yet). Gave it its own "SHFT %1" label plus a // not yet triggered note so it can never silently inherit the STEP readout if it's wired up later.

Rebuilt clean on Windows (435/435). I'll run a bench check of the D and STEP fixes on the TMate 2 hardware and report back here before this is merged.

@svabi79

svabi79 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Bench check done on the TMate 2 hardware — both display fixes confirmed:

  • AGC MED now renders correctly with the new 'D' glyph (was AGC ME).
  • 10 kHz tuning step shows STP 10000 cleanly, no truncation.

Good to go from my side.

@NF0T NF0T self-assigned this Jun 13, 2026
@NF0T NF0T enabled auto-merge (squash) June 13, 2026 14:44

@NF0T NF0T left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up to #3401 reviewed cleanly. All five issues from the bot review resolved in dd8ba6f0 and hardware-confirmed by the author on the TMate 2 bench:

  • 'D' glyph ({ 0x06, 0x0E }) correctly encodes B+C+D+E+G; "AGC MED" now renders in full.
  • STEP overflow resolved by switching to "STP %1".arg(mainVal, 5)"STP 10000" is exactly 9 characters at the 10 kHz preset.
  • isWpm dropped; non-finite guard added to formatTMate2PowerSmallText symmetric with powerBars(); TMate2Overlay::Shift given its own "SHFT" label with a // not yet triggered note.

Code placement: The PR body's files table lists MainWindow.cpp for the TX power wiring, but the actual diff is in MainWindow_Wiring.cpp (inside wireMeters()) — the correct TU per the #3351 decomposition. MainWindow.cpp is not modified. All overlay/indicator logic is in MainWindow_Controllers.cpp. Fully aligned with the refactored standard.

TX bargraph: Three power update paths (exciter FWD, PGxl forwarded, transmitPowerChanged) now all write m_tmate2TxWatts and call both updateTMate2Display() and updateTMate2Indicators(). The txPowerFullScaleWatts re-evaluates live via hasAmplifier() && ampOperate() at each updateTMate2Indicators() call, so the 100W → 2000W rescale tracks amp state without a stale capture. The amp/exciter alternating-writer race from #2927 does not re-emerge on the LCD path.

Encoder labels / RIT–XIT double-function: E1/E2 settings-key swap is documented inline and consistent with tmate2EncoderDefaultAction(). RIT/XIT segments lit on encoder assignment (even when offset is zero) is the right UX for showing knob function without an active rit/xit offset.

No new settings keys, no DAX, no session changes. CI 6/6 green. Approved.

@NF0T NF0T merged commit fdfab03 into aethersdr:main Jun 13, 2026
6 checks passed
@ten9876 ten9876 mentioned this pull request Jun 14, 2026
2 tasks
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
…labels (aethersdr#3542)

## Summary

Follow-up to aethersdr#3401 (TMate 2 HID integration). Four improvements
hardware-verified on ELAD TMate 2, all guarded with `#ifdef
HAVE_HIDAPI`.

### TX power bargraph (`HidEncoderManager.cpp`)
- During transmit the 15-bar S-meter bargraph now shows TX forward power
instead of the RX S-meter reading.
- Full-scale auto-adapts: 100 W normally, 2000 W when an amplifier is
connected and in operate.
- Reads from three power sources: FWD meter, PGxl amplifier forwarded
power, and the standard `transmitPowerChanged` signal — whichever fires
updates the display.

### TX power on small display (`MainWindow_Controllers.cpp`)
- Small 3-digit display shows watts during TX (e.g. `95` → "95 W") and
switches to `Nk M` format above 999 W (e.g. 1500 W → "1k5 W") so the
segment count never overflows.
- In RX the display continues to show `|dBm|` as before.

### Encoder label segments (`HidEncoderManager.cpp`)
- `setTMate2EncoderActionSegs()` reads the two auxiliary encoder
assignments and lights the matching silkscreen labels (VOL / DRV / SQL
and HIGH / SHIFT) so the LCD reflects the user's mapping without opening
the settings dialog.
- S-meter scale tick marks (S1 S3 S5 S7 S9 +20 +40 +60 dB) are now
driven in RX and blanked in TX/overlay, matching what the physical LCD
is labelled.
- RIT / XIT segments light when the respective wheel action is mapped to
an encoder, even when RIT/XIT offset is zero.

### Text overlays + letter glyphs (`HidEncoderManager.cpp`,
`MainWindow_Controllers.cpp`)
- Added `tmate2MainGlyph()` / `tmate2SmallGlyph()` for a 7-segment
letter subset (A C E F G H I K L M N O P R S T U V W X Y, `-`, space) —
enough to spell the feedback labels below.
- New `triggerTMate2TextOverlay()` + `TMate2Overlay::Text` variant for
arbitrary 9-character strings on the main display.
- `updateTMate2Display()` now builds a human-readable overlay string per
type: `"VOL 050"`, `"RIT +1200"`, `"AGC SLO"`, `"APF 42"`, `"TUNE ON"`,
etc.
- New overlay types: Xit, Shift, Agc, Apf (with indicator segment
handling in `setTMate2OverlayIndicators`).
- Toggle actions now confirm state on the display: ToggleTune → `"TUNE
ON/OFF"`, ToggleMute → `"MUTE ON/OFF"`, ToggleLock → `"LOCK ON/OFF"`,
ToggleApf → `"APF ON/OFF"`, ToggleAgc → `"AGC OFF/SLO/MED/FST"`.

## Files changed
| File | Change |
|---|---|
| `src/core/HidEncoderManager.h` | `setTMate2Indicators` signature
extended (new params default-valued); two new public slots |
| `src/core/HidEncoderManager.cpp` | Glyph tables, text write helpers,
encoder-label helpers, `powerBars()`, overlay indicator updates |
| `src/gui/MainWindow.h` | `TMate2Overlay` enum extended;
`m_tmate2OverlayText`; `triggerTMate2TextOverlay()` |
| `src/gui/MainWindow.cpp` | TX indicator refresh hooked into three
power-update paths |
| `src/gui/MainWindow_Controllers.cpp` | `formatTMate2PowerSmallText()`,
richer overlay dispatch, toggle action feedback |

## Test plan
- [ ] RX: S-meter bargraph tracks signal; tick marks S1–+60 dB visible
- [ ] TX: bargraph tracks forward power 0–100 W; small display shows
watts
- [ ] TX with amplifier in OPER: bargraph full-scale = 2000 W; small
display shows `Nk M` above 999 W
- [ ] Encoder-label segments (VOL/DRV/SQL/HIGH/SHIFT) match settings
after reconnect
- [ ] RIT active → RIT segment lit; encoder mapped to WheelRit with RIT
off → RIT segment lit
- [ ] Overlay text overlays: rotate volume/AGC/APF/RIT/XIT; observe
formatted readout
- [ ] Toggle actions: Tune/Mute/Lock/APF/AGC show confirmation overlay
text

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.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