Skip to content

fix: parse hex meter num field and handle M-prefix radio messages#2771

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
NF0T:pr/radio-model-protocol-fixes
May 17, 2026
Merged

fix: parse hex meter num field and handle M-prefix radio messages#2771
ten9876 merged 1 commit into
aethersdr:mainfrom
NF0T:pr/radio-model-protocol-fixes

Conversation

@NF0T

@NF0T NF0T commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Hex meter num parse fixRadioModel::handleMeterStatus used .toInt() without a base argument, silently returning 0 for hex values like 0x3B26ABBA from EXT_WVF meters (e.g. FreeDV_SNR). Changed to .toInt(nullptr, 0) for auto-base detection.

  • M-prefix message handler — M-prefix radio messages (e.g. FreeDV Docker waveform conflict warnings) were fully parsed by CommandParser but silently discarded in RadioModel::onMessageReceived due to the MessageType::Status-only guard. They are now logged via qCWarning(lcProtocol) and surfaced to the user as a QMessageBox::warning dialog in MainWindow. Wire format confirmed from pcap capture: plain text body, no KV structure.

Test plan

  • Connect to radio with FreeDV waveform running, single slice in FDVU — no dialog appears (normal operation)
  • Switch a second slice to FDVU — QMessageBox::warning appears with: "Only one FDVU or FDVL slice can be active at a time. Non-TX slices have been set to USB and/or LSB."
  • Confirm qCWarning(lcProtocol) log entry for the M-message
  • Confirm FreeDV_SNR meter num field parses non-zero (verify via debug log that sourceIndex is non-zero for EXT_WVF meters)

🤖 Generated with Claude Code

RadioModel::handleMeterStatus used toInt() without a base, returning 0
for hex values like 0x3B26ABBA from EXT_WVF meters (FreeDV_SNR). Fix
uses toInt(nullptr, 0) for auto-base detection.

M-prefix radio messages (waveform conflict warnings, etc.) were parsed
by CommandParser but silently discarded in onMessageReceived. Now logged
via qCWarning and surfaced to the user as a QMessageBox::warning dialog.
Wire format confirmed from pcap: plain text body, no KV structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@NF0T NF0T requested review from jensenpat and ten9876 as code owners May 16, 2026 23:11
@ten9876 ten9876 merged commit 681af8b into aethersdr:main May 17, 2026
5 checks passed
@ten9876

ten9876 commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Claude here — landed at 00:25 UTC. Six clean PRs in a single day, Ryan! 🎉

Both fixes have that same "trace it to the actual root" quality your previous five had — the hex meter num parse failure could have been "hide the meter row" or "default to 0 and call it a UX bug", but the actual cause was Qt's toInt() quietly rejecting the 0x prefix that EXT_WVF meters use. One-character fix at the exact right line. Similarly the M-message dispatch — the parser was already correctly tagging the messages, only the consumer was missing. Surgical adds rather than refactoring around the gap.

The modal-dialog choice is right for Phase 0 — M-messages are rare and the current FreeDV conflict warning is exactly the kind of thing operators want to see surface immediately. If we ever see spam patterns from new firmware versions we can add throttling or a status-bar surface as a follow-up. Not a problem to solve today.

Today's tally for you: #2745, #2747, #2752, #2754, #2759, #2771. Six PRs, six distinct code paths (RADE UI → RADE model → CWX UI → CWX core → SmartSDR protocol v4.2.18 → meter parse + M-dispatch). All clean diffs, all landed without rework. Outstanding work — looking forward to more.

73, Jeremy KK7GWY & Claude (AI dev partner)

@NF0T NF0T deleted the pr/radio-model-protocol-fixes branch May 17, 2026 00:26
ten9876 added a commit that referenced this pull request May 17, 2026
…odals (#2785)

## Summary

PR #2771 (merged today) added user-facing dialogs for M-prefix radio
messages. In practice the radio sends an **Info-severity** M-message on
every client connect/disconnect (\"Client connected from IP …\" etc.) —
routine multi-client notices that SmartSDR silently logs. AetherSDR was
popping a modal warning dialog on every connect as a result.

The fix extracts the severity bits that FlexLib documents but
AetherSDR's parser was discarding, then surfaces messages appropriately
by severity.

## Root cause

FlexLib's wire format
([Radio.cs:4498-4516](https://github.com/FlexRadioSystems/FlexLib/blob/main/FlexLib/Radio.cs#L4498))
encodes severity in bits 24-25 of the M-message number:

\`\`\`
M<8-hex-digits>|<text>
        └── (num >> 24) & 0x3 → Info=0, Warning=1, Error=2, Fatal=3
\`\`\`

AetherSDR's \`CommandParser\` was extracting the handle as a single hex
value but **discarding the severity bits**. PR #2771's MainWindow
handler then treated all M-messages identically as
\`QMessageBox::warning\`.

## What changes

- \`CommandParser\`: new \`MessageSeverity\` enum + \`severity\` field
on \`ParsedMessage\`; \`'M':\` case now extracts \`(handle >> 24) &
0x3\` into it
- \`RadioModel::radioMessageReceived\` signal extended to \`(QString,
MessageSeverity)\`
- \`RadioModel::onMessageReceived\` logs at the matching protocol level
(\`qCInfo\` / \`qCWarning\` / \`qCCritical\`) — log path and UI path now
both switch on the same enum so they can't disagree
- \`MainWindow::onRadioMessage\` switches on severity:

| Severity | Behavior |
|---|---|
| **Info** | \`statusBar()->showMessage(text, 5000)\` — 5-second toast,
no modal |
| **Warning** | \`QMessageBox::warning\` (PR #2771's intent preserved) |
| **Error** | \`QMessageBox::critical\` with \"Radio — Error\" title |
| **Fatal** | \`QMessageBox::critical\` with \"Radio — Fatal\" title |

## Behavior changes

- \"Client connected from IP …\" → status-bar toast (was modal popup) ✅
- \"Client disconnected from IP …\" → status-bar toast (was modal popup)
✅
- FreeDV mode-conflict warning from #2771 — unchanged, still modal ✅
- Future ATU / interlock / calibration errors — modal with
\"Error\"/\"Fatal\" title prefix instead of \"Radio\" generic

## Test plan

- [x] Local build clean (402/402 link, only pre-existing warnings)
- [x] Connect to FLEX-8400 — IP notice appears in status bar for 5
seconds, no modal interrupts connection flow. **Confirmed by @ten9876.**
- [ ] Trigger a Warning-severity M-message (e.g. set two slices to FDVU
when FreeDV is running) — modal warning still appears
- [ ] No regression in other M-message consumers (none exist in current
codebase per grep)

## Files

| File | Change |
|---|---|
| \`src/core/CommandParser.h\` | \`MessageSeverity\` enum +
\`ParsedMessage::severity\` field + protocol-format comment refresh |
| \`src/core/CommandParser.cpp\` | Extract severity bits in the \`'M':\`
case |
| \`src/models/RadioModel.h\` | Signal signature + \`CommandParser.h\`
include |
| \`src/models/RadioModel.cpp\` | Switch on severity for log level; emit
with severity |
| \`src/gui/MainWindow.h\` | Slot signature + \`CommandParser.h\`
include |
| \`src/gui/MainWindow.cpp\` | Switch on severity for log + dialog/toast
|

Net: **83 insertions / 16 deletions** across 6 files.

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

Co-authored-by: Claude Opus 4.7 (1M context) <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