Skip to content

feat(protocol): add FlexWaveformModel for firmware v4.2.18 waveform status (#2136)#2759

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
NF0T:feat/flex-waveform-model
May 16, 2026
Merged

feat(protocol): add FlexWaveformModel for firmware v4.2.18 waveform status (#2136)#2759
ten9876 merged 1 commit into
aethersdr:mainfrom
NF0T:feat/flex-waveform-model

Conversation

@NF0T

@NF0T NF0T commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • FlexRadio firmware v4.2.18 broadcasts three waveform status sub-shapes that AetherSDR previously had no handler for — messages fell through silently in onStatusReceived().
  • Adds FlexWaveformModel (new files) to parse and store all three shapes, wired into RadioModel with subscription, command forwarding, and disconnect cleanup.
  • Data model only — no UI changes. Named FlexWaveform* to avoid collision with the existing audio waveform visualization classes (WaveformWidget, StripWaveform).

Fixes #2136

Protocol Details

Wire shapes verified against FlexLib v4.2.18.41174 Radio.cs lines 11162–11321:

object Meaning Key facts
"waveform" Legacy installed list Entries: ,-delimited; name/version: \x7F-delimited
"waveform container" Docker waveform add/remove removed is a bare-word key (no =value)
"waveform wfp_status" WFP power/ready/ipaddr Booleans are case-insensitive string compare

Subscription: sub waveform all (FlexLib Radio.cs:2301) added to connection sequence.
Commands stubbed: waveform uninstall, waveform remove_container, waveform restart (FlexLib Radio.cs:8484–8499).

Files Changed

File Action
src/models/FlexWaveformModel.h New — struct + QObject class
src/models/FlexWaveformModel.cpp New — parse logic + command emitters
src/models/RadioModel.h Add include, accessor, private member
src/models/RadioModel.cpp Wire commandReady, subscription, clear(), dispatch
CMakeLists.txt Add to MODEL_SOURCES + test target
tests/flex_waveform_model_test.cpp New — 27 tests, all pass
docs/issue-2136-feasibility-report.md Internal reference
docs/issue-2136-implementation-plan.md Internal reference

Test Plan

  • ./build/flex_waveform_model_test — 27/27 pass (verified locally)
  • Connect to radio running firmware ≥ v4.2.18, confirm no log noise on waveform status messages
  • Connect to radio running firmware < v4.2.18, confirm harmless sub waveform all (radio ignores unknown sub topics)

Notes for Reviewers

  • CMakeLists.txt is Tier 3 (maintainer-only: @ten9876)
  • All other paths are Tier 1 (@ten9876 or @jensenpat)
  • The prior aethersdr-agent attempt (see issue comments) failed its CI gate due to path restrictions — this is a human-initiated PR with no such constraint

🤖 Generated with Claude Code

…tatus

FlexRadio firmware v4.2.18 introduced three new waveform status sub-shapes
that AetherSDR had no handler for — messages silently fell through.

Add FlexWaveformModel to parse and store all three shapes:
  - "waveform" installed_list — legacy waveform list (comma + DEL-separated)
  - "waveform container" — Docker container add/remove (bare-word removed key)
  - "waveform wfp_status" — Waveform Processor power/ready/ipaddr

Wire into RadioModel: sub waveform all subscription, commandReady forwarding,
clear() on disconnect, and dispatch in onStatusReceived().

Named FlexWaveformModel to avoid confusion with the audio waveform
visualization classes (WaveformWidget, StripWaveform) in src/gui/.

Protocol verified against FlexLib v4.2.18.41174 Radio.cs lines 11162–11321.
All 27 unit tests pass.

Fixes aethersdr#2136

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ten9876 ten9876 merged commit 018c035 into aethersdr:main May 16, 2026
5 checks passed
@ten9876

ten9876 commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Claude here — landed at 23:14 UTC. Fifth contribution today, Ryan! 🎉

This is the kind of PR that makes a maintainer's life easy. Every wire shape cited to a FlexLib v4.2.18.41174 line number, three sub-shapes disambiguated cleanly via the existing parser (no parser changes needed), the bare-word `removed` handling matches the existing `display pan removed` idiom at `RadioModel.cpp:3577` so future contributors can pattern-match, the `FlexWaveform*` naming explicitly avoids confusion with the audio-render `WaveformWidget`/`StripWaveform` classes, and defensive parsing logs and skips rather than crashing on malformed input. 27-assertion test suite covers all three shapes plus edge cases.

The feasibility report and implementation plan are appreciated — they're consistent with the project's "consult FlexLib first" convention and they'll be valuable reference for the next firmware-version bump that adds new status object shapes.

Five PRs today (#2745, #2747, #2752, #2754, #2759), five distinct code paths (RADE UI → RADE model → CWX UI → CWX core → SmartSDR protocol). All five clean diffs that landed without rework. Genuinely remarkable.

73, Jeremy KK7GWY & Claude (AI dev partner)

@NF0T NF0T deleted the feat/flex-waveform-model branch May 17, 2026 00:07
ten9876 pushed a commit that referenced this pull request May 17, 2026
…ment (#2779)

## Summary

Surfaces the data already collected by `FlexWaveformModel` (merged in
#2759) in a non-modal, geometry-persistent dialog at **File →
Waveforms**, mirroring SmartSDR's layout and location.

- **WFP status bar** at the top: power indicator (●), ready indicator
(●), and IP address — all live-updating via
`FlexWaveformModel::wfpStatusChanged`
- **Waveform list**: one row per installed waveform or Docker container,
with name, version, and type badge — live-updating via
`FlexWaveformModel::waveformsChanged`
- **Restart** button per row — fire-and-forget, no confirmation; sends
`waveform restart <name>`
- **Remove** (container) / **Uninstall** (legacy .wfp) button per row —
`QMessageBox::question` confirmation before sending `waveform
remove_container <name>` or `waveform uninstall <name>`
- Install omitted intentionally — Docker containers are managed at the
radio/firmware level, not from the client

## Implementation

`WaveformsDialog` inherits `PersistentDialog` (geometry-persist +
frameless-chrome handling) and takes a `FlexWaveformModel*` in its
constructor. No refresh logic in `MainWindow` — the dialog wires
`FlexWaveformModel` signals directly. `showOrRaisePersistent` handles
lazy-construct, raise-if-open, and frameless toggle registration
automatically.

## Test plan

- [x] **File → Waveforms** opens dialog; re-triggering raises it rather
than opening a second
- [x] WFP status shows correct power/ready state and IP address
- [x] `freedv-flex` (or other container) appears in the list with
version and `[Container]` badge
- [ ] **Restart** sends `waveform restart freedv-flex` — visible in
radio log
- [ ] **Remove** → cancel → no command sent; **Remove** → confirm →
sends `waveform remove_container freedv-flex`
- [ ] Disconnect from radio → list empties, status clears (driven by
`FlexWaveformModel::clear()`)
- [x] Frameless mode toggle applies correctly

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

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ten9876 added a commit that referenced this pull request May 22, 2026
… PR 8) (#2953)

Eight docs leave the top-level docs/ tree, partitioned by purpose:

docs/archive/ — historical planning/session notes, kept for grep
context:
  - issue-2136-feasibility-report.md     (PR #2759, shipped)
  - issue-2136-implementation-plan.md    (PR #2759, shipped)
  - TX_SYNC_FIX_REPORT.md                 (PR #353, RadioModel.cpp still
    references the report by name)
  - aether-dsp-session-notes.md          (#796 maintainer notebook)

docs/data/ — reference fixtures (not bundled, not runtime):
  - SSDR.settings + SmartSDR.exe.config   (SmartSDR parity reference)
  - rxapplet_mode_settings.csv            (per-mode RX control research)
  - vfo_mode_filters.csv                  (VFO filter-preset research;
    VfoWidget.cpp comment updated to new path)

Kept in docs/ (still active):
  - audio_test_plan.md  (17 KB, edited 2026-04-29, ongoing test plan)
  - profile-import-export-manual-checklist.md (PR #2641 QA checklist)

Both new dirs include a one-paragraph README explaining the convention
so a future maintainer doesn't have to guess what belongs where.

Cross-references audited:
  - AppSettings.h:9 mentions "SmartSDR's SSDR.settings" as a concept,
    not a path — no change.
  - RadioModel.cpp:3991 references TX_SYNC_FIX_REPORT by name — no
    change, file is findable via grep/find.
  - VfoWidget.cpp:3324 carried a literal "docs/vfo_mode_filters.csv"
    path — updated to docs/data/.

Verified with a clean local Release build (cmake --build … --target
AetherSDR exits 0).

After this PR, docs/ contains 18 markdown files (architecture/user
docs), the assets/ subdir from PR 5, and the new archive/ + data/
subdirs — matches the acceptance criteria in the cleanup plan.

Principle I.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
…sdr#2933, PR 8) (aethersdr#2953)

Eight docs leave the top-level docs/ tree, partitioned by purpose:

docs/archive/ — historical planning/session notes, kept for grep
context:
  - issue-2136-feasibility-report.md     (PR aethersdr#2759, shipped)
  - issue-2136-implementation-plan.md    (PR aethersdr#2759, shipped)
  - TX_SYNC_FIX_REPORT.md                 (PR aethersdr#353, RadioModel.cpp still
    references the report by name)
  - aether-dsp-session-notes.md          (aethersdr#796 maintainer notebook)

docs/data/ — reference fixtures (not bundled, not runtime):
  - SSDR.settings + SmartSDR.exe.config   (SmartSDR parity reference)
  - rxapplet_mode_settings.csv            (per-mode RX control research)
  - vfo_mode_filters.csv                  (VFO filter-preset research;
    VfoWidget.cpp comment updated to new path)

Kept in docs/ (still active):
  - audio_test_plan.md  (17 KB, edited 2026-04-29, ongoing test plan)
  - profile-import-export-manual-checklist.md (PR aethersdr#2641 QA checklist)

Both new dirs include a one-paragraph README explaining the convention
so a future maintainer doesn't have to guess what belongs where.

Cross-references audited:
  - AppSettings.h:9 mentions "SmartSDR's SSDR.settings" as a concept,
    not a path — no change.
  - RadioModel.cpp:3991 references TX_SYNC_FIX_REPORT by name — no
    change, file is findable via grep/find.
  - VfoWidget.cpp:3324 carried a literal "docs/vfo_mode_filters.csv"
    path — updated to docs/data/.

Verified with a clean local Release build (cmake --build … --target
AetherSDR exits 0).

After this PR, docs/ contains 18 markdown files (architecture/user
docs), the assets/ subdir from PR 5, and the new archive/ + data/
subdirs — matches the acceptance criteria in the cleanup plan.

Principle I.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

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.

Protocol v4.2.18: disambiguate waveform sub-shapes (parser fix)

2 participants