On restart, AetherSDR restores persisted broken panadapter state instead of defaulting to single-pan safe mode
Labels: bug, GUI, priority: medium
Related: multi-panadapter FFT/waterfall broken state issue (filed separately)
Related: #152 (multi-panadapter support)
What
When AetherSDR is restarted after a session where the second panadapter was
in a broken state (FFT blank, not closeable), it restores the broken
panadapter layout from persisted settings rather than defaulting to a
clean single-panadapter state. The user is immediately back in the broken
state with no path to recovery short of manually editing the settings file.
Why This Happens
AetherSDR persists panadapter layout state (number of open pans, pan IDs,
geometry) across sessions via AppSettings. On restart, it reads this
state and attempts to recreate the saved layout. When the saved layout
includes a panadapter that was corrupt at save time, the corruption is
faithfully reproduced on the next launch.
This is a fundamental dirty-state persistence problem: the app saves
whatever state it is in at shutdown — including broken states — and
unconditionally restores it on startup, with no validation that the
persisted state is actually healthy.
Why It Matters
A user who encounters the broken-panadapter bug (filed separately) and
restarts AetherSDR expecting a clean slate instead finds themselves in the
same broken state immediately. The restart that should be the recovery
path becomes a trap. Combined with the inability to close the faulty pan
from the UI, the user has no in-app recovery option at all.
How SmartSDR Handles It
SmartSDR for Windows never persists multi-panadapter layout client-side.
On connect, it requests the radio's current panadapter state and builds the
UI from live radio data only. If the radio reports only one panadapter,
SmartSDR shows one — regardless of what the previous session looked like.
There is no "dirty load" because there is no client-side layout persistence
to go stale. The radio is the single source of truth for panadapter count
and configuration.
The Design Tradeoff
This is a conscious architectural decision with two valid positions:
Option A — Radio as source of truth (SmartSDR approach)
On connect, request panadapter state from the radio (sub pan all) and
build the UI entirely from the radio's response. Do not persist panadapter
count or pan IDs client-side. If the radio reports one pan, show one. If it
reports two, show two.
- Pro: can never load a stale or corrupt layout. Always reflects actual
radio state.
- Con: loses any client-side display preferences (zoom, dBm range,
waterfall speed) that the radio does not store. These would need to be
re-applied heuristically (e.g. by pan frequency match) on reconnect.
Option B — Persist with validation (safer client-side persistence)
Continue persisting layout client-side but add a health check on load:
before restoring a saved panadapter, verify that the radio actually has a
live panadapter with that ID. If validation fails, silently discard the
saved pan and default to single-pan layout.
// In RadioModel or PanadapterStack — on connect, after sub pan all
for (const auto& savedPanId : savedPanIds) {
if (!m_activePanIds.contains(savedPanId)) {
// Radio doesn't know about this pan — don't restore it
AppSettings::instance().remove("Pan2Id"); // clean up stale entry
continue;
}
restorePanadapter(savedPanId);
}
- Pro: preserves client-side display preferences across sessions.
- Con: more complex; validation logic must be correct or it silently
discards valid state.
Option C — Fail safe, no alert (recommended minimum)
Regardless of which option is chosen for the long term, implement an
immediate fail-safe fallback: if any panadapter fails to initialise
correctly on load (FFT stream not arriving within a timeout, stream ID
not confirmed by the radio, widget in error state), silently drop that
pan and continue with a single-pan layout. No popup, no error dialog —
consistent with SmartSDR's behaviour. The user gets a working app rather
than a broken one.
Suggested Behavior (Recommended: Option C now, Option A or B later)
Immediate fix (Option C)
Add a startup health check in PanadapterStack or RadioModel: after
connect and after VITA-49 streaming begins, verify each restored panadapter
has received at least one valid FFT frame (PCC 0x8003) within a
reasonable timeout (e.g. 5 seconds). If a pan fails this check:
- Silently remove it from the layout.
- Clean up its persisted state from
AppSettings so it does not come
back on the next restart.
- Log a diagnostic message (no user-facing alert).
Long-term (Option A or B — design decision for Jeremy)
Decide whether panadapter layout should be radio-authoritative (Option A)
or client-persisted-with-validation (Option B). This decision affects
AppSettings key design for pan state, the wirePanadapter() / reconnect
flow, and how client-side display preferences (zoom, gain, black level) are
associated with pans across sessions.
Protocol Hints
Confirming live panadapter IDs from radio (on connect)
The radio responds with display pan <id> status objects for each active
panadapter. The set of IDs in these responses is the ground truth for what
pans actually exist. Any persisted pan ID not in this set should be
discarded on load.
Confirming FFT stream is live (health check)
A panadapter is healthy if PCC 0x8003 packets for its stream ID arrive
within ~5 seconds of client udpport registration. If no packets arrive,
the radio is not streaming FFT for that pan and the pan should be
considered invalid.
Relevant source locations
src/core/AppSettings — pan layout persistence keys (pan count, pan
IDs, geometry); identify which keys need to be cleared on failed load
src/gui/PanadapterStack — pan creation on startup; add health check
timeout per pan; silent removal of failed pans
src/models/RadioModel — sub pan all response handling; expose set
of live pan IDs for validation against persisted state
src/core/PanadapterStream — FFT packet arrival; add per-pan
"first frame received" signal for health check timeout logic
On restart, AetherSDR restores persisted broken panadapter state instead of defaulting to single-pan safe mode
Labels:
bug,GUI,priority: mediumRelated: multi-panadapter FFT/waterfall broken state issue (filed separately)
Related: #152 (multi-panadapter support)
What
When AetherSDR is restarted after a session where the second panadapter was
in a broken state (FFT blank, not closeable), it restores the broken
panadapter layout from persisted settings rather than defaulting to a
clean single-panadapter state. The user is immediately back in the broken
state with no path to recovery short of manually editing the settings file.
Why This Happens
AetherSDR persists panadapter layout state (number of open pans, pan IDs,
geometry) across sessions via
AppSettings. On restart, it reads thisstate and attempts to recreate the saved layout. When the saved layout
includes a panadapter that was corrupt at save time, the corruption is
faithfully reproduced on the next launch.
This is a fundamental dirty-state persistence problem: the app saves
whatever state it is in at shutdown — including broken states — and
unconditionally restores it on startup, with no validation that the
persisted state is actually healthy.
Why It Matters
A user who encounters the broken-panadapter bug (filed separately) and
restarts AetherSDR expecting a clean slate instead finds themselves in the
same broken state immediately. The restart that should be the recovery
path becomes a trap. Combined with the inability to close the faulty pan
from the UI, the user has no in-app recovery option at all.
How SmartSDR Handles It
SmartSDR for Windows never persists multi-panadapter layout client-side.
On connect, it requests the radio's current panadapter state and builds the
UI from live radio data only. If the radio reports only one panadapter,
SmartSDR shows one — regardless of what the previous session looked like.
There is no "dirty load" because there is no client-side layout persistence
to go stale. The radio is the single source of truth for panadapter count
and configuration.
The Design Tradeoff
This is a conscious architectural decision with two valid positions:
Option A — Radio as source of truth (SmartSDR approach)
On connect, request panadapter state from the radio (
sub pan all) andbuild the UI entirely from the radio's response. Do not persist panadapter
count or pan IDs client-side. If the radio reports one pan, show one. If it
reports two, show two.
radio state.
waterfall speed) that the radio does not store. These would need to be
re-applied heuristically (e.g. by pan frequency match) on reconnect.
Option B — Persist with validation (safer client-side persistence)
Continue persisting layout client-side but add a health check on load:
before restoring a saved panadapter, verify that the radio actually has a
live panadapter with that ID. If validation fails, silently discard the
saved pan and default to single-pan layout.
discards valid state.
Option C — Fail safe, no alert (recommended minimum)
Regardless of which option is chosen for the long term, implement an
immediate fail-safe fallback: if any panadapter fails to initialise
correctly on load (FFT stream not arriving within a timeout, stream ID
not confirmed by the radio, widget in error state), silently drop that
pan and continue with a single-pan layout. No popup, no error dialog —
consistent with SmartSDR's behaviour. The user gets a working app rather
than a broken one.
Suggested Behavior (Recommended: Option C now, Option A or B later)
Immediate fix (Option C)
Add a startup health check in
PanadapterStackorRadioModel: afterconnect and after VITA-49 streaming begins, verify each restored panadapter
has received at least one valid FFT frame (PCC
0x8003) within areasonable timeout (e.g. 5 seconds). If a pan fails this check:
AppSettingsso it does not comeback on the next restart.
Long-term (Option A or B — design decision for Jeremy)
Decide whether panadapter layout should be radio-authoritative (Option A)
or client-persisted-with-validation (Option B). This decision affects
AppSettingskey design for pan state, thewirePanadapter()/ reconnectflow, and how client-side display preferences (zoom, gain, black level) are
associated with pans across sessions.
Protocol Hints
Confirming live panadapter IDs from radio (on connect)
The radio responds with
display pan <id>status objects for each activepanadapter. The set of IDs in these responses is the ground truth for what
pans actually exist. Any persisted pan ID not in this set should be
discarded on load.
Confirming FFT stream is live (health check)
A panadapter is healthy if PCC
0x8003packets for its stream ID arrivewithin ~5 seconds of
client udpportregistration. If no packets arrive,the radio is not streaming FFT for that pan and the pan should be
considered invalid.
Relevant source locations
src/core/AppSettings— pan layout persistence keys (pan count, panIDs, geometry); identify which keys need to be cleared on failed load
src/gui/PanadapterStack— pan creation on startup; add health checktimeout per pan; silent removal of failed pans
src/models/RadioModel—sub pan allresponse handling; expose setof live pan IDs for validation against persisted state
src/core/PanadapterStream— FFT packet arrival; add per-pan"first frame received" signal for health check timeout logic