Skip to content

[codex] Fix DEXP protocol mapping#3568

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/fix-dexp-protocol
Jun 14, 2026
Merged

[codex] Fix DEXP protocol mapping#3568
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/fix-dexp-protocol

Conversation

@rfoust

@rfoust rfoust commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #3464 by wiring the PHONE applet DEXP controls to the radio protocol keys that SmartSDR actually uses:

  • transmit set compander=0/1 for the DEXP toggle
  • transmit set compander_level=<0..100> for the DEXP threshold slider

The reporter provided a SmartSDR capture on #3464 showing those command/status keys during DEXP toggle and slider changes, and FlexLib v4.2.18 exposes the same CompanderOn / CompanderLevel commands. AetherSDR was previously sending transmit set dexp=... and transmit set noise_gate_level=..., which the radio rejects, so the UI could look changed while radio-side DEXP never changed.

What Changed

  • Map incoming compander / compander_level transmit status into the existing DEXP model state so the PHONE applet follows radio-authoritative state.
  • Change TransmitModel::setDexp() and setDexpLevel() to emit compander / compander_level commands.
  • Remove client-side DexpEnabled / DexpLevel persistence and reconnect restore logic. DEXP is radio-side state; AetherSDR should not replay stale local settings over the radio on reconnect.
  • Fix two stale Speech Processor state reads that were checking companderOn() instead of speechProcessorEnable().
  • Add focused TransmitModel regression coverage for DEXP command emission and compander status parsing.

Maintainer Notes

This intentionally leaves the visible UI label as DEXP; the protocol field is named compander, but the user-facing control is still the downward expander/noise gate. PROC remains backed by the separate speech_processor_enable / speech_processor_level protocol keys.

Validation

  • cmake --build build --target transmit_model_test --parallel
  • ./build/transmit_model_test
  • cmake --build build --target AetherSDR --parallel
  • python3 tools/check_a11y.py src/gui/PhoneApplet.cpp src/gui/PhoneApplet.h src/gui/MainWindow.cpp src/gui/MainWindow_Controllers.cpp src/gui/MainWindow_Shortcuts.cpp src/gui/MainWindow_Wiring.cpp
  • git diff --check upstream/main...HEAD

Fixes #3464.

@rfoust rfoust mentioned this pull request Jun 14, 2026
2 tasks
@rfoust rfoust marked this pull request as ready for review June 14, 2026 03:39
@rfoust rfoust requested a review from a team as a code owner June 14, 2026 03:39
Copilot AI review requested due to automatic review settings June 14, 2026 03:39
@rfoust rfoust requested review from a team as code owners June 14, 2026 03:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the PHONE applet’s DEXP controls by mapping them to the FlexRadio protocol keys SmartSDR actually uses (compander / compander_level), removing stale local persistence/restore, and adding regression coverage to prevent the mapping from regressing again.

Changes:

  • Wire DEXP toggle/level command emission to transmit set compander=0/1 and transmit set compander_level=<0..100>.
  • Parse compander / compander_level status into the existing DEXP model state so the UI follows radio-authoritative state.
  • Remove local DexpEnabled / DexpLevel persistence + reconnect restore logic; fix two Speech Processor state reads; add TransmitModel tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/transmit_model_test.cpp Adds regression coverage for compander-backed DEXP command emission and status parsing.
src/models/TransmitModel.cpp Implements compander-backed DEXP status/command mapping and updates related state change signaling.
src/gui/PhoneApplet.h Updates DEXP documentation/comments to reflect working mapping.
src/gui/PhoneApplet.cpp Removes client-side DEXP persistence writes; relies on model/radio state.
src/gui/MainWindow.cpp Removes now-obsolete comment about avoiding DEXP persistence on close.
src/gui/MainWindow_Wiring.cpp Removes reconnect-time restore of locally persisted DEXP settings.
src/gui/MainWindow_Shortcuts.cpp Fixes PROC shortcut toggle to use speechProcessorEnable() rather than companderOn().
src/gui/MainWindow_Controllers.cpp Fixes MIDI PROC enable readback to use speechProcessorEnable() rather than companderOn().

Comment thread src/models/TransmitModel.cpp Outdated
Comment thread src/models/TransmitModel.cpp Outdated

@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 @rfoust — this is a clean, well-scoped fix and the protocol reasoning checks out against the codebase, not just the SmartSDR capture.

Verified the repurposing is safe. I traced every reader of companderOn()/companderLevel():

  • MainWindow_Controllers.cpp:1765 and MainWindow_Shortcuts.cpp:704 — both stale Speech-Processor reads, correctly repointed to speechProcessorEnable() here.
  • RadioModel.cpp:5677 (mic troubleshooting snapshot) — read-only/diagnostic, fine.

compander was effectively orphaned after the PROC path was reverted to speech_processor_enable/speech_processor_level (the pcap comments at TransmitModel.cpp:534/544, which supersede the older #661/#667 CHANGELOG note). So wiring compander/compander_level to DEXP disturbs no other live control. Dropping the DexpEnabled/DexpLevel flat-key persistence + reconnect replay is the right call for radio-authoritative state.

On the two Copilot findings — valid but low severity. Both compander and the legacy dexp blocks now write m_companderOn/m_dexpOn, and the dexp block runs later, so a single status frame carrying both keys with conflicting values would let the legacy key win. In practice a frame won't carry both (the radio speaks one protocol generation), so this is defensive-only — but the guard is trivial and makes intent explicit. If you touch it, gating the legacy keys on the canonical key being absent is enough:

if (kvs.contains("dexp") && !kvs.contains("compander")) { ... }
if (kvs.contains("noise_gate_level") && !kvs.contains("compander_level")) { ... }

Not a merge blocker. Nice to see focused TransmitModel test coverage for both the command emission and the compander→DEXP status path. 73


🤖 aethersdr-agent · cost: $6.2565 · model: claude-opus-4-8

@rfoust rfoust self-assigned this Jun 14, 2026
Use the radio compander keys observed in the SmartSDR capture and FlexLib for the DEXP toggle and threshold.

Stop persisting DEXP as client-side state so reconnects do not override the radio-authoritative value.

Fixes aethersdr#3464.
@rfoust rfoust force-pushed the codex/fix-dexp-protocol branch from bea3fda to 395555e Compare June 14, 2026 04:05
@ten9876 ten9876 merged commit e22c8a7 into aethersdr:main Jun 14, 2026
6 checks passed
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
Fixes aethersdr#3464. The PHONE applet DEXP controls were sending transmit set dexp=/noise_gate_level= keys the radio rejects; maps them to the SmartSDR-actual compander/compander_level keys (per a v4.2.20 capture + FlexLib v4.2.18 CompanderOn/CompanderLevel). Dual-writes m_dexpOn (PHONE) and m_companderOn (mic-diag) in sync, gates legacy keys on !compander, fixes two stale PROC reads (companderOn -> speechProcessorEnable), and removes client-side DEXP persistence/reconnect-replay (radio-authoritative). Adds transmit_model_test coverage.

Co-authored-by: rfoust <rfoust@users.noreply.github.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.

DEXP Control Response Incorrect

3 participants