Multi-panadapter: 2nd panadapter loses FFT spectrum (waterfall continues), cannot be closed — persistent across reboot and sole-client reconnect
Labels: bug, spectrum, priority: high
Related: #152 (multi-panadapter support)
Edit: This is a pretty complicated issue
What
In a specific Multi-Flex scenario involving three slices across two clients,
AetherSDR's second panadapter enters a broken state where:
- The FFT spectrum display is blank — no signal trace, no noise floor,
nothing.
- The waterfall continues to scroll and display signals normally.
- The broken state persists across radio reboot and across
AetherSDR-only reconnect (disconnecting SSDR entirely does not
recover it).
- The second panadapter cannot be closed from within AetherSDR while
in this state.
Scenario That Triggers the Bug
SSDR connects first → gets Slice A (Pan 1)
AetherSDR connects → gets Slice B (Pan 1) + Slice C (Pan 2) [Multi-Flex]
Radio glitches.
Result: Slice C / Pan 2 in AetherSDR shows waterfall only — no FFT spectrum.
Pan 2 close button is non-functional.
Rebooting radio does not recover.
Disconnecting SSDR, reconnecting AetherSDR alone does not recover.
Note: a separate but related bug exists where connecting AetherSDR without
SSDR also results in unexpected slice assignment (should get A & B, gets
different assignments) — see "Related Bugs" section below.
Steps to Reproduce
- Connect SSDR to the radio. Confirm it holds Slice A on Pan 1.
- Connect AetherSDR in Multi-Flex. Confirm it gets Slice B on Pan 1 and
Slice C on Pan 2.
- Allow or induce a radio glitch (power fluctuation, network hiccup,
firmware watchdog reset, or rapid connect/disconnect cycling).
- After the glitch, observe AetherSDR's Pan 2:
- Expected: FFT spectrum and waterfall both display normally on Pan 2.
- Actual: FFT spectrum is blank. Waterfall scrolls normally.
- Attempt to close Pan 2 via its close button.
- Expected: Pan 2 closes and AetherSDR returns to single-pan layout.
- Actual: close button has no effect. Pan 2 cannot be dismissed.
- Reboot the radio. Reconnect AetherSDR.
- Expected: recovered state — Pan 2 FFT works normally.
- Actual: blank FFT on Pan 2 persists. State survived the reboot.
- Disconnect SSDR entirely. Reconnect AetherSDR as sole client.
- Expected: recovered state.
- Actual: blank FFT on Pan 2 still persists.
Why This Is Non-Trivial
The waterfall continuing while the FFT is blank is the critical diagnostic
clue. Both displays are fed from VITA-49 UDP packets but via different
PCCs:
- FFT spectrum bins → PCC
0x8003
- Waterfall tiles → PCC
0x8004
The fact that 0x8004 (waterfall) is arriving and being rendered while
0x8003 (FFT) is not means the VITA-49 stream for Pan 2 is partially
alive. This points to one of:
- The radio is sending PCC
0x8004 but not 0x8003 for Pan 2's
stream ID after the glitch — the radio-side FFT stream for that
panadapter stalled or was not restarted.
PanadapterStream is receiving 0x8003 packets for Pan 2 but
routing them to the wrong SpectrumWidget — a stream ID mismatch
after the glitch caused setOwnedStreamIds() to associate Pan 2's
FFT stream ID with a stale or incorrect value.
SpectrumWidget for Pan 2 is receiving FFT data but not rendering
it — a paint path failure specific to the second widget instance,
possibly a QWidget::update() call that stopped being invoked after
the glitch.
The persistence across radio reboot eliminates hypothesis (1) as the sole
cause — if the radio were simply not sending the FFT stream, a reboot
would reset it. The persistence across sole-client reconnect strongly
implicates a corrupt client-side state in AetherSDR that survives
disconnect/reconnect: specifically, a stale stream ID, a broken signal
connection between PanadapterStream and the second SpectrumWidget, or
a PanadapterStack layout state that does not fully reinitialise on
reconnect.
The inability to close Pan 2 is a separate but related symptom: the close
button's handler likely checks a state flag (stream active, model valid,
etc.) that is stuck in an inconsistent value after the glitch, causing the
guard condition to block the close action.
Suggested Debugging Steps
-
Capture a diagnostic log during the broken state with the
PanadapterStream logging category enabled. Confirm whether PCC
0x8003 packets for Pan 2's stream ID are arriving at
PanadapterStream. If they are arriving but not reaching
SpectrumWidget, the routing is broken. If they are not arriving, the
radio stopped sending the FFT stream.
-
Check setOwnedStreamIds() — after the glitch, confirm that
PanadapterStream still has the correct Pan 2 FFT stream ID
(0x8003) registered. If the stream ID changed after the glitch (the
radio may assign a new stream ID on reconnect) and
setOwnedStreamIds() was not called with the updated value, all Pan 2
FFT packets would be silently dropped.
-
Check PanadapterStack reinitialisation on reconnect — confirm
that wirePanadapter() is called for Pan 2 on every reconnect, not
just on initial creation. If the signal connections between
PanadapterStream and SpectrumWidget for Pan 2 are established once
at creation and then broken by a disconnect/reconnect cycle without
being rewired, FFT updates would stop arriving at the widget.
-
Check the Pan 2 close button handler — identify what condition is
blocking the close action and why it is stuck after the glitch.
Related Bugs
Separate bug: wrong slice assignment when connecting without SSDR
When connecting AetherSDR as the sole client (SSDR not connected),
AetherSDR should receive Slices A and B. Instead it receives unexpected
slice assignments. This suggests RadioModel's SmartConnect logic
(which calls slice get <id> for existing slices rather than creating
new ones) may be interacting incorrectly with the radio's slice allocation
when no other client session is present. This warrants its own issue but
shares the slice/panadapter assignment code path with the primary bug.
Protocol Hints
VITA-49 stream IDs for Pan 2 (observed values from CLAUDE.md)
- FFT stream: same as panadapter object ID (e.g.
0x40000001 for Pan 2)
- Waterfall stream:
0x42000001 for Pan 2
Re-requesting the FFT stream (if radio stopped sending)
// The panadapter create command that established Pan 2's FFT stream:
display panafall create x=100 y=100
// On reconnect, if stream ID changed, AetherSDR must call:
client udpport <port> // re-register UDP port
// and re-subscribe to the new stream ID
Checking stream registration
Add a log entry in PanadapterStream::setOwnedStreamIds() to capture the
exact FFT and waterfall stream IDs registered for each pan at connect time
and after any reconnect. Compare these against the stream IDs seen in
arriving VITA-49 packets during the broken state.
Relevant source locations
src/core/PanadapterStream — setOwnedStreamIds(), PCC 0x8003
dispatch path; add logging to confirm Pan 2 FFT packets are arriving
and being routed
src/gui/SpectrumWidget — updateSpectrum(): confirm it is being
called for the Pan 2 instance and that QWidget::update() is invoked
src/gui/PanadapterStack — pan creation, wirePanadapter() call on
reconnect, close button handler and its guard condition
src/models/RadioModel — SmartConnect slice get logic; pan stream
ID capture and setOwnedStreamIds() call on reconnect
Multi-panadapter: 2nd panadapter loses FFT spectrum (waterfall continues), cannot be closed — persistent across reboot and sole-client reconnect
Labels:
bug,spectrum,priority: highRelated: #152 (multi-panadapter support)
Edit: This is a pretty complicated issue
What
In a specific Multi-Flex scenario involving three slices across two clients,
AetherSDR's second panadapter enters a broken state where:
nothing.
AetherSDR-only reconnect (disconnecting SSDR entirely does not
recover it).
in this state.
Scenario That Triggers the Bug
Note: a separate but related bug exists where connecting AetherSDR without
SSDR also results in unexpected slice assignment (should get A & B, gets
different assignments) — see "Related Bugs" section below.
Steps to Reproduce
Slice C on Pan 2.
firmware watchdog reset, or rapid connect/disconnect cycling).
Why This Is Non-Trivial
The waterfall continuing while the FFT is blank is the critical diagnostic
clue. Both displays are fed from VITA-49 UDP packets but via different
PCCs:
0x80030x8004The fact that
0x8004(waterfall) is arriving and being rendered while0x8003(FFT) is not means the VITA-49 stream for Pan 2 is partiallyalive. This points to one of:
0x8004but not0x8003for Pan 2'sstream ID after the glitch — the radio-side FFT stream for that
panadapter stalled or was not restarted.
PanadapterStreamis receiving0x8003packets for Pan 2 butrouting them to the wrong
SpectrumWidget— a stream ID mismatchafter the glitch caused
setOwnedStreamIds()to associate Pan 2'sFFT stream ID with a stale or incorrect value.
SpectrumWidgetfor Pan 2 is receiving FFT data but not renderingit — a paint path failure specific to the second widget instance,
possibly a
QWidget::update()call that stopped being invoked afterthe glitch.
The persistence across radio reboot eliminates hypothesis (1) as the sole
cause — if the radio were simply not sending the FFT stream, a reboot
would reset it. The persistence across sole-client reconnect strongly
implicates a corrupt client-side state in AetherSDR that survives
disconnect/reconnect: specifically, a stale stream ID, a broken signal
connection between
PanadapterStreamand the secondSpectrumWidget, ora
PanadapterStacklayout state that does not fully reinitialise onreconnect.
The inability to close Pan 2 is a separate but related symptom: the close
button's handler likely checks a state flag (stream active, model valid,
etc.) that is stuck in an inconsistent value after the glitch, causing the
guard condition to block the close action.
Suggested Debugging Steps
Capture a diagnostic log during the broken state with the
PanadapterStreamlogging category enabled. Confirm whether PCC0x8003packets for Pan 2's stream ID are arriving atPanadapterStream. If they are arriving but not reachingSpectrumWidget, the routing is broken. If they are not arriving, theradio stopped sending the FFT stream.
Check
setOwnedStreamIds()— after the glitch, confirm thatPanadapterStreamstill has the correct Pan 2 FFT stream ID(
0x8003) registered. If the stream ID changed after the glitch (theradio may assign a new stream ID on reconnect) and
setOwnedStreamIds()was not called with the updated value, all Pan 2FFT packets would be silently dropped.
Check
PanadapterStackreinitialisation on reconnect — confirmthat
wirePanadapter()is called for Pan 2 on every reconnect, notjust on initial creation. If the signal connections between
PanadapterStreamandSpectrumWidgetfor Pan 2 are established onceat creation and then broken by a disconnect/reconnect cycle without
being rewired, FFT updates would stop arriving at the widget.
Check the Pan 2 close button handler — identify what condition is
blocking the close action and why it is stuck after the glitch.
Related Bugs
Separate bug: wrong slice assignment when connecting without SSDR
When connecting AetherSDR as the sole client (SSDR not connected),
AetherSDR should receive Slices A and B. Instead it receives unexpected
slice assignments. This suggests
RadioModel'sSmartConnectlogic(which calls
slice get <id>for existing slices rather than creatingnew ones) may be interacting incorrectly with the radio's slice allocation
when no other client session is present. This warrants its own issue but
shares the slice/panadapter assignment code path with the primary bug.
Protocol Hints
VITA-49 stream IDs for Pan 2 (observed values from
CLAUDE.md)0x40000001for Pan 2)0x42000001for Pan 2Re-requesting the FFT stream (if radio stopped sending)
Checking stream registration
Add a log entry in
PanadapterStream::setOwnedStreamIds()to capture theexact FFT and waterfall stream IDs registered for each pan at connect time
and after any reconnect. Compare these against the stream IDs seen in
arriving VITA-49 packets during the broken state.
Relevant source locations
src/core/PanadapterStream—setOwnedStreamIds(), PCC0x8003dispatch path; add logging to confirm Pan 2 FFT packets are arriving
and being routed
src/gui/SpectrumWidget—updateSpectrum(): confirm it is beingcalled for the Pan 2 instance and that
QWidget::update()is invokedsrc/gui/PanadapterStack— pan creation,wirePanadapter()call onreconnect, close button handler and its guard condition
src/models/RadioModel—SmartConnectslice get logic; pan streamID capture and
setOwnedStreamIds()call on reconnect