Skip to content

Add External APD support (Radio Setup tab + sampler protocol)#2187

Merged
ten9876 merged 1 commit intomainfrom
aether/external-apd
Apr 30, 2026
Merged

Add External APD support (Radio Setup tab + sampler protocol)#2187
ten9876 merged 1 commit intomainfrom
aether/external-apd

Conversation

@ten9876
Copy link
Copy Markdown
Owner

@ten9876 ten9876 commented Apr 30, 2026

Summary

Implements External APD support for SmartSDR 4.2.18 firmware. External APD lets the radio sample its outgoing RF from a coupled feedback path on one of the RX/XVTR inputs (rather than the internal sampler), so the predistortion engine trains against the actual transmitted signal — required when a FLEX-8x00 drives an external linear amplifier (PGXL, etc.).

The apd enable / configurable / equalizer_active plumbing was already in place. This PR adds the sampler subobject, the equalizer-reset command, and the UI.

Changes

Protocol (TransmitModel)

  • New apdSampler(txAnt) getter returning {selected, available} per ANT1/ANT2/XVTA/XVTB.
  • applyApdSamplerStatus(kvs) parses apd sampler tx_ant=ANT1 selected_sampler=RX_A valid_samplers=RX_A,XVTA. If selected_sampler isn't in the valid list, falls back to INTERNAL (matches FlexLib behaviour).
  • setApdSamplerPort(txAnt, port) emits apd sampler tx_ant=ANT sample_port=PORT.
  • resetApdEqualizer() emits apd reset.
  • applyApdStatus() now also handles the bare equalizer_reset flag, emitting a new apdEqualizerResetReceived signal.
  • RadioModel dispatcher routes "apd sampler" to applyApdSamplerStatus; the bare-flag form gets merged into kvs and routed to applyApdStatus.

UI (RadioSetupDialog)

  • New "APD" tab between XVTR and USB Cables. Eagerly added but visibility is gated on transmitModel.apdConfigurable() and updates live via apdStateChanged, so the tab stays hidden on 6000-series radios and pre-4.2.18 firmware.
  • Layout matches the SmartSDR 4.2.18 "External Sampler (per TX ANT)" group: ANT1/XVTA on top row, ANT2/XVTB on bottom, each with a port combo; Equalizer Reset button on its own row.
  • Combo options + selection are kept in sync with the model via apdSamplerChanged (signal-blocked refresh, so user-driven changes don't echo back to the radio).

Teststests/transmit_model_apd_test.cpp, 22 assertions:

  • Sampler status populates available (with INTERNAL first) and selected.
  • Invalid selected_sampler falls back to INTERNAL.
  • Sampler-port command formatted correctly + case-normalised.
  • Empty txAnt or port silently dropped (no spurious command).
  • resetApdEqualizer() emits apd reset.
  • Bare equalizer_reset clears equalizer_active and fires the reset signal.
  • configurable=1/=0 toggles apdConfigurable().
  • Identical sampler status is idempotent (no re-emit).
  • resetState() clears the sampler hash on disconnect.

Reference: Flex.Smoothlake.FlexLib v4.2.18, FlexLib/APD.cs.

Test plan

  • ./build/transmit_model_apd_test — all 22 pass locally.
  • Connect to a FLEX-8600 on firmware 4.2.18: APD tab visible.
  • Connect to a FLEX-6000 series: APD tab not present.
  • Per-antenna combo shows the radio's valid_samplers plus INTERNAL.
  • Selecting RX_A for ANT1 sends apd sampler tx_ant=ANT1 sample_port=RX_A; the echoed status updates the combo without firing a second command.
  • Reset button sends apd reset; subsequent status arrival clears the active indicator.

🤖 Generated with Claude Code

SmartSDR 4.2.18 introduced External APD (Adaptive Pre-Distortion):
per-TX-antenna selection of where the radio takes the feedback sample
its predistortion engine trains against.  The default INTERNAL samples
inside the radio (legacy behaviour); RX_A/RX_B/XVTA/XVTB take a
coupled feedback signal from a receive or transverter input — required
to train APD against the real RF when transmitting through an external
linear amplifier (FLEX-8x00 + PGXL, etc.).

Plumbing already existed for `apd enable`/`configurable`/`equalizer_active`.
This change adds:

* `apd sampler tx_ant=ANT1 selected_sampler=RX_A valid_samplers=...`
  status parsing, including "selected sampler not in valid list" →
  fall back to INTERNAL (matches FlexLib semantics).
* `apd equalizer_reset` bare-flag handling (parser absorbs leading
  bare flags into the object name; we strip and merge into kvs).
* New TransmitModel API: `apdSampler(txAnt)`, `setApdSamplerPort()`,
  `resetApdEqualizer()`, plus `apdSamplerChanged` / `apdEqualizerResetReceived`
  signals.
* New "APD" tab in Radio Setup with four per-antenna sampler combos
  (ANT1/ANT2/XVTA/XVTB) and an Equalizer Reset button.  Tab is hidden
  unless the radio reports `apd configurable=1`, so it stays
  invisible on 6000-series radios and pre-4.2.18 firmware.

Reference: Flex.Smoothlake.FlexLib v4.2.18, FlexLib/APD.cs.

Tests: tests/transmit_model_apd_test.cpp — 22 assertions covering
status parsing, fallback behaviour, command formatting, equalizer
reset, idempotency, and resetState.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@ten9876 ten9876 force-pushed the aether/external-apd branch from d7c7a30 to 0aaa60f Compare April 30, 2026 06:00
@ten9876 ten9876 merged commit 8ca06b7 into main Apr 30, 2026
4 checks passed
@ten9876 ten9876 deleted the aether/external-apd branch April 30, 2026 06:12
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.

1 participant