Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions docs/HERMES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2195,8 +2195,8 @@ The Display panel's FPS slider, Clone to all Pans and Reset to Defaults save;
`MainWindow::wirePanDisplayStatus` restores into the widget before it seeds the
shaper. FFT AVG and Wt Avg have a table of their own in that document
(`fftAverages`), kept only for a backend that declares
`BackendPanAveraging::clientPersistsAveraging`. The HL2 declares it false, so on
this radio those two are not remembered.
`BackendPanAveraging::clientPersistsAveraging`. The HL2 declares it, so the
Display panel's FFT AVG slider and Wt Avg toggle are remembered per pan slot too.

The dBm range is the odd one: the pan model, not the widget, is what every
re-seed reads, so a scale the operator moves is put into the model
Expand Down Expand Up @@ -3696,7 +3696,10 @@ behavior is unchanged.

The count was fixed at connect, from a persisted setting. It is now the
operator's, at runtime: "Add Panadapter" and the pane close button. Connect
always comes up with ONE receiver.
always comes up with ONE receiver; the ones the operator had open come back
after link-up through that same add (`Hl2Backend::replayRestoredSession`, from
the `receivers` list of the `OperatingState` document), so the receiver
ceiling at the current span still decides how many return (#5777).

Retiring the persisted count mattered for a reason beyond tidiness: it made
connect the only place the count could change, and a saved 4 was re-imposed on
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/radio-capabilities-map.md

Large diffs are not rendered by default.

48 changes: 25 additions & 23 deletions src/core/RadioStateMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QJsonDocument>

#include <cmath>
#include <utility>

namespace AetherSDR {
namespace RadioStateMemory {
Expand Down Expand Up @@ -33,6 +34,27 @@ bool ownsAgcOffLevel(const RadioCapabilities& caps)
// feature documents (one domain, one document — PR 6).
constexpr const char* kExtRfGainKey = "rfGain";
constexpr const char* kExtTxSetpointsKey = "txSetpoints";
constexpr const char* kExtReceiversKey = "receivers";
constexpr const char* kExtNotchesKey = "notches";

// The declared domains' sub-objects of `ext`; load() and store() share it so
// the two gates cannot drift apart.
QJsonObject gateExtension(const RadioCapabilities& caps, const QJsonObject& ext)
{
const std::pair<Domain, const char*> domains[] = {
{Domain::RfGain, kExtRfGainKey},
{Domain::TxSetpoints, kExtTxSetpointsKey},
{Domain::Receivers, kExtReceiversKey},
{Domain::Notches, kExtNotchesKey},
};
QJsonObject gated;
for (const auto& [domain, key] : domains) {
if (has(caps, domain) && ext.contains(QLatin1String(key))) {
gated.insert(QLatin1String(key), ext.value(QLatin1String(key)));
}
}
return gated;
}

} // namespace

Expand Down Expand Up @@ -115,18 +137,8 @@ RestoredRadioState load(const RadioSettingsScope& scope,
// sub-object is handed over, so a narrowed declaration cannot smuggle
// another domain's data to the backend (PR #4614 review — previously the
// whole blob rode on any one of the ext domains).
const QJsonObject storedExt = doc.value(QStringLiteral("ext")).toObject();
QJsonObject gatedExt;
if (has(caps, Domain::RfGain)
&& storedExt.contains(QLatin1String(kExtRfGainKey))) {
gatedExt.insert(QLatin1String(kExtRfGainKey),
storedExt.value(QLatin1String(kExtRfGainKey)));
}
if (has(caps, Domain::TxSetpoints)
&& storedExt.contains(QLatin1String(kExtTxSetpointsKey))) {
gatedExt.insert(QLatin1String(kExtTxSetpointsKey),
storedExt.value(QLatin1String(kExtTxSetpointsKey)));
}
const QJsonObject gatedExt =
gateExtension(caps, doc.value(QStringLiteral("ext")).toObject());
if (!gatedExt.isEmpty()) {
state.extension = gatedExt;
state.extensionSchemaVersion =
Expand Down Expand Up @@ -245,17 +257,7 @@ bool store(const RadioSettingsScope& scope, const RadioCapabilities& caps,
}

// Extension: same per-domain sub-object gate as load().
QJsonObject gatedExt;
if (has(caps, Domain::RfGain)
&& state.extension.contains(QLatin1String(kExtRfGainKey))) {
gatedExt.insert(QLatin1String(kExtRfGainKey),
state.extension.value(QLatin1String(kExtRfGainKey)));
}
if (has(caps, Domain::TxSetpoints)
&& state.extension.contains(QLatin1String(kExtTxSetpointsKey))) {
gatedExt.insert(QLatin1String(kExtTxSetpointsKey),
state.extension.value(QLatin1String(kExtTxSetpointsKey)));
}
const QJsonObject gatedExt = gateExtension(caps, state.extension);
if (!gatedExt.isEmpty()) {
doc.insert(QStringLiteral("ext"), gatedExt);
doc.insert(QStringLiteral("extVersion"), state.extensionSchemaVersion);
Expand Down
7 changes: 4 additions & 3 deletions src/core/backends/IRadioBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,10 @@ class IRadioBackend : public QObject {
// rfpower drop notice.
virtual void setTxPower(int percent) { Q_UNUSED(percent); }

// TUNE power (0..100) changed while the TUNE carrier may be up. NEVER keys:
// a backend generating its own carrier re-applies drive to one in progress
// and otherwise does nothing, since the next setTune() carries the value.
// TUNE power (0..100) changed: unkeyed, or on a carrier this client keyed.
// NEVER keys: a backend generating its own carrier re-applies drive to one in
// progress; otherwise it may only record the value (HL2 keeps it per band),
// since the next setTune() carries it.
// Owner thread, like setTxPower(). Declaring
// TransmitDriveControl::tunePowerAppliesLive promises it is implemented.
virtual void setTunePower(int percent) { Q_UNUSED(percent); }
Expand Down
4 changes: 4 additions & 0 deletions src/core/backends/RadioCapabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ struct RadioCapabilities {
// The radio's own receive output level. Not the PC sink's, which is
// app-global and stays the flat MasterVolume key.
ReceiveOutputLevel = 1u << 9,
// Each receiver's own setpoints (blanker, APF, squelch, RIT/XIT, audio,
// pan centre) and how many receivers run; the backend replays the set.
Receivers = 1u << 10,
Notches = 1u << 11, // host-side manual notches (centre, width, active)
};
Q_DECLARE_FLAGS(ClientSettingsDomains, ClientSettingsDomain)
ClientSettingsDomains clientSettingsDomains; // default: empty — restore nothing
Expand Down
Loading
Loading