Skip to content

Closing a panafall-created panadapter never removes the waterfall stream (display panafall remove missing); removePanadapter uses non-existent 'display pan close' #3843

Description

@jensenpat

Summary

Closing a panafall-created panadapter does not reliably tear it down, because the close path never issues the waterfall-side removal command. Per the FlexLib reference, fully closing a panafall requires both display pan remove 0x<panId> (Panadapter.Close) and display panafall remove 0x<wfStreamId> (Waterfall.Close). AetherSDR sends at most the first. Symptom: a second pan that won't dismiss from the UI and has to be torn down indirectly via slice removal.

This is distinct from #268 (a glitch-induced Multi-Flex corruption where Pan 2's FFT goes blank and the pan gets stuck); here the wrong/incomplete command is the root cause under normal conditions.

Two related defects

1. RadioModel::removePanadapter sends a non-existent command — and is dead code.

src/models/RadioModel.cpp:1838:

void RadioModel::removePanadapter(const QString& panId)
{
    qCDebug(lcProtocol) << "RadioModel::removePanadapter:" << panId;
    sendCmd(QString("display pan close %1").arg(panId));   // ← not a FlexLib command
    // Radio will send "display pan <id> removed" → handled in onStatusReceived
}

FlexLib uses display pan remove (not close) — see Panadapter.Close() in the v4.2.18 reference. A grep shows this method has no callers anywhere in the tree, so it's currently dead, but the public "remove a panadapter" API is wrong and is a latent trap for anything that wires up to it.

2. The live close path omits the waterfall removal.

The actual X-button handler (src/gui/MainWindow_Wiring.cpp:1745) bypasses removePanadapter and sends only the pan-side command:

connect(applet, &PanadapterApplet::closeRequested, this, [this](const QString& panId) {
    if (m_panStack->count() <= 1) return;        // don't close the last pan
    m_radioModel.sendCommand(QString("display pan remove %1").arg(panId));
});

It never sends display panafall remove <waterfallId>, so for a pan created via display panafall create (which allocates a panadapter stream and a waterfall stream) the waterfall side is never explicitly removed.

Why the client-side teardown is fine — the gap is on the send side

The status handler already cleans up both streams once the radio echoes display pan <id> removed (src/models/RadioModel.cpp:4444):

if (kvs.contains("removed") || object.endsWith("removed")) {
    ...
    m_panStream->unregisterPanStream(pan->panStreamId());
    m_panStream->unregisterWfStream(pan->wfStreamId());   // both streams torn down
    emit panadapterRemoved(panId);
    pan->deleteLater();
    ...
}

So the bug is purely that the close request to the radio is incomplete for a panafall.

Confirmed fix shape (already proven live)

The new automation-bridge pan close verb (PR #3842, this issue's sibling) issues the FlexLib-correct pair:

radio->sendCommand("display pan remove "      + panId);
if (!wfId.isEmpty())
    radio->sendCommand("display panafall remove " + wfId);

Driven against a live FLEX-8400M, this closed a panafall-created second pan cleanly (get pans count 2 → 1) without the slice-removal workaround:

pan add            → 2 pans  (0x40000000, 0x40000001)
grab pan 1         → ok
pan close 1        → closed [{panId:0x40000001, waterfallId:0x42000001}]
get pans           → 1 pan

PanadapterModel already exposes panId() and waterfallId() (src/models/PanadapterModel.h), so the wfId is readily available at the close site.

Suggested fix

  1. Make RadioModel::removePanadapter(panId) send display pan remove <panId> and, when the pan has a non-empty waterfallId(), display panafall remove <waterfallId>.
  2. Route the X-button handler (MainWindow_Wiring.cpp:1745) through removePanadapter so there's a single source of truth, instead of an inline sendCommand.
  3. Verify on hardware that the radio echoes display pan <id> removed for a panafall after the pair (the client cleanup at RadioModel.cpp:4444 then runs unchanged). Mind command ordering / radio-authoritative removal per the project's radio-API guidance.

Repro

  1. Connect to a radio, add a second panadapter.
  2. Click the second pan's close (X) button.
  3. Expected: the pan closes, layout returns to single-pan.
  4. Actual: the panafall-created pan does not fully tear down (waterfall stream lingers); it ends up only removable via slice removal.

Related


Filed from investigation during PR #3842. The automation side is fixed there; this issue tracks the production GUI close path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenmulti-panMulti-panadapter layout and slicingpriority: mediumMedium priorityprotocolSmartSDR protocolspectrumPanadapter and waterfall

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions