Skip to content

Fix waterfall TX trail by gating on radio interlock state (#1927)#2368

Merged
ten9876 merged 1 commit into
mainfrom
fix/waterfall-tx-trail-1927
May 5, 2026
Merged

Fix waterfall TX trail by gating on radio interlock state (#1927)#2368
ten9876 merged 1 commit into
mainfrom
fix/waterfall-tx-trail-1927

Conversation

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Summary

Fixes #1927.

The waterfall continued to show TX-contaminated data for 10–23 seconds after PTT release. Root cause: SpectrumWidget::setTransmitting(false) was driven from TransmitModel::moxChanged, which fires the instant the user releases PTT — before the radio actually leaves the TRANSMITTING state.

Sequence that produced the trail:

  1. User releases PTT → moxChanged(false) → waterfall unfreezes immediately
  2. xmit 0 is sent to the radio
  3. Radio walks TRANSMITTING → UNKEY_REQUESTED → RECEIVE
  4. During step 3 the radio keeps streaming TX-contaminated tiles/FFT, which now get painted into the unfrozen waterfall
  5. Those rows take 10–23 s to scroll off depending on waterfall speed (matches the observed timing in the issue, including @kn7k's 10+ s CW report)

Fix

Move the spectrum setTransmitting(tx) loop from the moxChanged handler to the radioTransmittingChanged handler in MainWindow.cpp. radioTransmittingChanged is driven by the actual interlock state == "TRANSMITTING" transition (RadioModel.cpp), so the waterfall now stays frozen until the radio confirms it has left TRANSMITTING.

Audio / DAX / RADE / serial-port PTT calls remain on moxChanged to preserve the low-latency local-edge behavior for TX/RX audio switching (waiting for interlock there would introduce audible lag).

The m_hasNativeWaterfall reset on TX→RX in SpectrumWidget.h:334 is already in place, so the FFT-fallback stale-tile concern is already handled.

Side-effect win: radioTransmittingChanged is not ownership-gated, so the waterfall now also freezes when another Multi-Flex client triggers TX — which the ownership-gated moxChanged previously missed.

Test plan

  • Flex-8600 (or any radio with a visible interlock window): TX in USB/SSB → release PTT → waterfall unfreezes cleanly with no trailing TX rows
  • Repeat in CW (covers @kn7k's report)
  • Repeat with low waterfall speed (where the issue was most visible)
  • TX audio switching latency unchanged (no perceptible delay on TX/RX edges, DAX still pristine)
  • Multi-Flex: another client TXes → this client's waterfall freezes for that window (new behavior)
  • S-Meter, TX indicator, RADE, serial-port PTT unchanged

— AetherClaude (automated agent for AetherSDR)

Waterfall was unfreezing the instant the user released PTT, but the
radio keeps streaming TX-contaminated tiles/FFT during the
UNKEY_REQUESTED window. Those rows then took 10–23 s to scroll off the
visible waterfall at typical speeds.

Move the SpectrumWidget::setTransmitting() calls from the moxChanged
handler to the radioTransmittingChanged handler, which fires on the
actual interlock state==TRANSMITTING transition. Audio/DAX/serial PTT
calls stay on moxChanged so TX/RX audio switching keeps its low-latency
local edge.

Side-effect win: radioTransmittingChanged is not ownership-gated, so
the waterfall now also freezes when another Multi-Flex client triggers
TX — previously missed.

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

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the detailed root-cause writeup — the diagnosis matches the code paths I traced. The fix is small, targeted, and the asymmetric handling (audio/DAX/RADE/serial PTT stay on moxChanged for low-latency edge alignment, only the visual freeze moves to interlock state) is the right call.

A few things I checked and one question:

Verified

  • RadioModel::radioTransmittingChanged is emitted on every interlock state=... status (RadioModel.cpp:3317), so the listener will see the actual TRANSMITTING → UNKEY_REQUESTED → RECEIVE walk and only flip the spectrum back to RX once the interlock leaves TRANSMITTING. That's exactly the gate you want.
  • SpectrumWidget::setTransmitting (SpectrumWidget.h:329-341) is edge-guarded (if (tx && !m_transmitting) / if (!tx && m_transmitting)), so the multiple radioTransmittingChanged emissions during one TX cycle are idempotent — no double-restore of m_preTxAutoBlack, no repeated m_hasNativeWaterfall=false. Safe.
  • m_appletPanel->sMeterWidget()->setTransmitting(tx) was already on this signal, so the new spectrum gating now matches the S-Meter's behavior — consistent.
  • The ownership-gating side-effect win is real: radioTransmittingChanged is emitted before the m_txOwnedByUs check at line 3319, so other-client TX will now freeze this client's waterfall. Worth covering in the test plan as you have it.

Question — TX entry side
The writeup carefully covers the unkey transition (TRANSMITTING → UNKEY_REQUESTED → RECEIVE) but doesn't say what happens on the keying side. With the old code, moxChanged(true) froze the spectrum the instant the user pressed PTT. With this PR, the freeze waits for state == "TRANSMITTING", so during any pre-TX states (PTT_REQUESTED, KEY_REQUESTED, TX-delay window, etc.) the spectrum will keep painting whatever the radio sends. If the radio's TX chain ever leaks contaminated tiles before reaching TRANSMITTING (analogous to the unkey window), this fix would expose a small leading trail.

In practice I'd expect the interlock semantics to keep TX-contamination strictly inside TRANSMITTING, but it's worth a quick check on the TX-edge captures you already have. If you see clean entry on the Flex-8600 captures, no change needed — just call it out in the PR notes so future-you doesn't have to re-derive it.

Otherwise this looks good to merge. Nice fix.

@ten9876 ten9876 merged commit dcd3f5a into main May 5, 2026
5 checks passed
@ten9876 ten9876 deleted the fix/waterfall-tx-trail-1927 branch May 5, 2026 05:59
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.

Ver 0.8.21 and 0.8.22 After TX water still shows my last transmitted signal for 23 second

2 participants