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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,8 @@ set(GUI_SOURCES
src/gui/WaveformScopeModel.cpp
src/gui/WaveformWidget.cpp
src/gui/AetherClockApplet.cpp
src/gui/WfmApplet.cpp
src/gui/WfmLockScope.cpp
src/gui/ClockAlignmentWidget.cpp
src/gui/ClientEqApplet.cpp
src/gui/ClientEqCurveWidget.cpp
Expand Down
12 changes: 6 additions & 6 deletions docs/architecture/aetherd-touchpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Burndown manifest for the engine/UI decoupling ([RFC](../aetherd-headless-engine
| `core/AetherRxProfiles.h` | 1 | universal — Named-profile save/recall/import-export for the receive DSP chain; operates on core-profile DSP state only, same precedent as core/ChannelStripPresets.h, whose RX capture/apply it shares. | unconverted |
| `core/AetherTxProfiles.h` | 1 | universal — Named-profile save/recall/import-export for the transmit DSP chain; operates on core-profile DSP state only. Mirror of core/AetherRxProfiles.h, and shares ChannelStripPresets' TX capture/apply. | unconverted |
| `core/AgcTCalibrator.h` | 1 | universal — Engine algo sweeping slice AGC threshold vs audio RMS/S-meter to recommend a value; only canonical state. | unconverted |
| `core/AppSettings.h` | 107 | ui-support — Client-side XML settings store (SSDR.settings-style key/value persistence); app plumbing, not radio state. | unconverted |
| `core/AppSettings.h` | 108 | ui-support — Client-side XML settings store (SSDR.settings-style key/value persistence); app plumbing, not radio state. | unconverted |
| `core/AudioEngine.h` | 47 | mixed(flex) — Client audio I/O + full RX/TX DSP chain (universal) fused with Flex VITA-49/DAX/Opus TX and Kiwi buffering | unconverted |
| `core/AudioOutputRouter.h` | 1 | ui-support — Registry fanning the user-selected QAudioDevice to local playback sinks; OS device plumbing, no radio state | unconverted |
| `core/AutomationBridgeSettings.h` | 3 | ui-support — Owned configuration for the agent automation bridge (enabled / txAllowed / txAck / readOnly) under one nested key; the secret token lives in the OS keychain, not here. Dev and test tooling — same home decision as core/AutomationServer.h. NOTE for RFC §6: txAllowed() is read as a TX-guard input by BOTH AutomationServer and Hl2Backend, so this header is a step-4 consolidation target. | unconverted |
Expand Down Expand Up @@ -149,7 +149,7 @@ Burndown manifest for the engine/UI decoupling ([RFC](../aetherd-headless-engine
| `core/SystemInventory.h` | 1 | ui-support — Startup and support-bundle inventory of host CPU, SIMD and RAM capabilities. Process diagnostics, not radio state. | unconverted |
| `core/TciServer.h` | 3 | mixed(flex) — TCI WebSocket server for WSJT-X et al: protocol surface is canonical radio state, but audio/IQ rides Flex DAX | unconverted |
| `core/TgxlConnection.h` | 3 | peripheral(4o3a) — Direct TCP client for the 4O3A Tuner Genius XL (port 9010, relay/autotune), reverse-engineered from the 4O3A management app — a standalone accessory transport, not SmartSDR. Not radio-family wire; a peripheral accessory, NOT behind the IRadioBackend radio seam (reclassified from vendor(flex), #4087 follow-up). | unconverted |
| `core/ThemeManager.h` | 165 | ui-support — Qt token-based theming singleton (colors/fonts/QSS, theme files, editor hooks) — pure client GUI plumbing, no radio state. | unconverted |
| `core/ThemeManager.h` | 167 | ui-support — Qt token-based theming singleton (colors/fonts/QSS, theme files, editor hooks) — pure client GUI plumbing, no radio state. | unconverted |
| `core/ThreadCpuRing.h` | 2 | ui-support — Short host-thread CPU history used by Runtime Monitor peak and sparkline presentation. Diagnostic UI support, not radio state. | unconverted |
| `core/TimeFrameVoter.h` | 1 | universal — Shared AetherClock time-frame types plus confidence-weighted cross-frame bit voting over a sliding window. Map-agnostic pure DSP/logic — no Qt, no GUI, no vendor ties. | unconverted |
| `core/TxKeyingMarker.h` | 14 | ui-support — QWidget property marker guarding TX-keying controls from the automation bridge; GUI-shell plumbing, no radio state. | unconverted |
Expand Down Expand Up @@ -179,7 +179,7 @@ Burndown manifest for the engine/UI decoupling ([RFC](../aetherd-headless-engine
| `core/backends/HealthSnapshotMerge.h` | 1 | universal — The snapshot merge rule, family-neutral by construction: a key the winner declares but omits from `values` means "not reported" and must not erase a base value. Moved out of backends/hl2/Hl2TelemetrySource.h (which keeps hl2MergeHealth as a forwarder) because AutomationServer::doHealth() and RadioHealthDialog both need it, and neither may include a family header to get it. Names no family. | unconverted |
| `core/backends/IRadioBackend.h` | 2 | universal — THE radio seam (RFC §5.5) — the canonical intent verbs, typed deltas and normalized signals every family implements. Universal by definition: the UI reaching this header is the seam working as designed, not coupling. Everything below it in core/backends/<family>/ is family-private. | unconverted |
| `core/backends/NoiseFloorAutoAdjustGate.h` | 2 | universal — The ONE predicate deciding whether the noise-floor auto-adjust may move the display reference level, as an OR over two backend-neutral properties (a real dBm-range echo, or absolute spectrum bins). Deliberately free of Qt and of RadioCapabilities so the widget and its test read the same function rather than two copies; the UI reaching it is the seam working, not coupling. Family backends populate the capability it is called with. | unconverted |
| `core/backends/RadioCapabilities.h` | 10 | universal — Backend-neutral capability descriptor consumed above the radio seam. Universal by definition; family implementations populate it. | unconverted |
| `core/backends/RadioCapabilities.h` | 11 | universal — Backend-neutral capability descriptor consumed above the radio seam. Universal by definition; family implementations populate it. | unconverted |
| `core/backends/SquelchLevelScale.h` | 2 | universal — Where a slice's squelch level sits on the panadapter's vertical axis, as a backend-published record (RadioCapabilities::squelchLevelScale) plus the mode filter and Auto-SQL predicate both the widget and MainWindow read, so the SQL line and Auto SQL share one gate. No family name or wire concept; each backend declares its own map or leaves it absent (#6092). | unconverted |
| `core/backends/anan/AnanDiscovery.h` | 2 | vendor(anan) — openHPSDR Protocol 2 discovery and ANAN-G2 identity handling. Family-specific discovery belongs below the ANAN backend seam. | unconverted |
| `core/backends/anan/AnanSettings.h` | 1 | ui-support — Client-side connection and ADC configuration for the ANAN backend. Persisted setup plumbing, not live radio state. | unconverted |
Expand Down Expand Up @@ -232,15 +232,15 @@ Burndown manifest for the engine/UI decoupling ([RFC](../aetherd-headless-engine
| `models/ModelCapabilities.h` | 1 | mixed(flex) — Per-model capability table mirroring FlexLib ModelInfo.cs (RadioPlatform, has2Meters/has4Meters, loop A/B). This is the universal question 'what can this radio do', answered exclusively from a vendor table — and its band-availability half is precisely the band truth RFC §4.1 assigns to the capability descriptor. Consumed above the seam by SpectrumOverlayMenu, XvtrPolicy, WaveformInstallGate and MainWindow_Wiring. | unconverted |
| `models/NetEntry.h` | 2 | ui-support — Net scheduler entry: RRULE/timezone/reminder metadata, operator-scoped local JSON; radio state only via embedded MemoryEntry | unconverted |
| `models/Nr2SettingsModel.h` | 5 | universal — Process-wide owner of client-side NR2 configuration as one versioned object (Principle V), so every editing surface shares state. Engine DSP configuration; radio-agnostic. | unconverted |
| `models/PanadapterModel.h` | 4 | mixed(flex) — Per-pan display state is core-profile; DAX IQ ch, client_handle, VITA stream IDs, SmartSDR kv parsing are flex. | unconverted |
| `models/PanadapterModel.h` | 5 | mixed(flex) — Per-pan display state is core-profile; DAX IQ ch, client_handle, VITA stream IDs, SmartSDR kv parsing are flex. | unconverted |
| `models/ProfileLoadCommand.h` | 1 | vendor(flex) — Parses SmartSDR 'profile global/tx/mic load' wire command + recall-hold timing/suppression sentinels; Flex-only | unconverted |
| `models/RadioModel.h` | 51 | mixed(flex) — Central radio aggregate: core slice/pan/TX/meter/memory state fused with Flex protocol, DAX, SmartLink, Multi-Flex | unconverted |
| `models/RadioModel.h` | 52 | mixed(flex) — Central radio aggregate: core slice/pan/TX/meter/memory state fused with Flex protocol, DAX, SmartLink, Multi-Flex | unconverted |
| `models/RadioSession.h` | 1 | universal — Per-radio session aggregate: owns RadioModel + id/label; session concept is core-profile, no vendor surface | unconverted |
| `models/RadioStatusOwnership.h` | 1 | vendor(flex) — SmartSDR status parsing helpers: Flex hex handles, client_handle ownership, remote_audio_rx, interlock gate | unconverted |
| `models/ReceiverSlotCount.h` | 1 | universal — How many receiver letters (A, B, C, ...) the UI offers — the RX applet's slice tabs and the CAT applet's VFO targets — tracked from the connection/capability/slice edges. Family-agnostic: the backend's declared ceiling, floored by the slots live receivers occupy (#5775, #5776). | unconverted |
| `models/Rn2SettingsModel.h` | 1 | universal — Process-wide owner of client-side RN2 configuration as one versioned object (Principle V). Engine DSP configuration; radio-agnostic. | unconverted |
| `models/SliceLinkPolicy.h` | 2 | universal — Pure decision logic for Slice Link (cross-panadapter VFO link) — echo classification on integer Hz, no QObject, no I/O, no model access. Canonical slice state only. | unconverted |
| `models/SliceModel.h` | 34 | mixed(flex) — Slice state (freq/mode/filter/DSP) is core-profile; DAX, index_letter, SmartSDR status KVs are flex ext | unconverted |
| `models/SliceModel.h` | 36 | mixed(flex) — Slice state (freq/mode/filter/DSP) is core-profile; DAX, index_letter, SmartSDR status KVs are flex ext | unconverted |
| `models/SpotModel.h` | 1 | universal — Panadapter spot store (callsign/freq/mode/lifetime/priority) on canonical state; kv ingest is trivially generic | unconverted |
| `models/TnfModel.h` | 1 | universal — Tracking notch filter state (freq/width/depth/permanent, global enable) — generic DSP notch surface; kv parse is transport detail | unconverted |
| `models/TransmitModel.h` | 17 | mixed(flex) — TX state model: power/MOX/VOX/CW/filter are core-profile; ATU, DAX, APD, profiles, interlock are Flex. | unconverted |
Expand Down
6 changes: 6 additions & 0 deletions docs/architecture/radio-capabilities-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ semantics see [local frequency control](../aetherd-local-slice-frequency-control

## Wired and consumed

### Broadcast FM receiver controls

| Record | Flex | HL2 | Sim | Icom | ANAN | RTL-SDR | Consumers |
|---|---|---|---|---|---|---|---|
| `broadcastFmReceive` | absent | absent | absent | absent | absent | de-emphasis 50/75 µs, force Mono, measured reception diagnostics | `WfmApplet` availability; `RadioModel::dispatchSliceWfm` validates the capability and routes `requestSliceWfm`, with explicit refusal reporting |

### Local receive-control records

The optional `receiveModeControl`, `receiveFilterControl`, `receiveAudioControl`,
Expand Down
19 changes: 15 additions & 4 deletions docs/audio-engine-rate-domains.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ device format remains independent: `m_rxProducerRate` describes main input;
`m_rxOutputRate` describes device output. `DEFAULT_SAMPLE_RATE` stays 24000.
Legacy byte input and every Kiwi auxiliary route retain 24 kHz stereo.

An accepted 48 kHz main producer asks the running RX speaker to prefer 48 kHz,
then 44.1 kHz, then 24 kHz through the consolidated `PreservePan` ladder. The
actual device rate remains separately reported; a 24 kHz fallback cannot retain
15 kHz audio. Default 24 kHz producer policy and the input/sidetone ladders are
unchanged. Requests are coalesced on the existing owner thread and checked
against the current producer lease and sink generation before opening. A
stopped speaker stays stopped. A brief retirement gap or same-rate replacement
retains the sink, including an already-negotiated fallback; real replacement
24 kHz PCM restores the legacy policy. Only the RX speaker reopens, preserving
the dedicated CW/Quindar sinks and producer-domain queues and processing state.

## Queues and processing

Raw queues and whole NR2 packets count time in their producer domain. Each
Expand Down Expand Up @@ -70,10 +81,10 @@ fixed-rate contracts. RADE output converts from 24 kHz to the device rate,
independently of the main producer. TX admission, cancellation and deferred
release continue through the inherited #5591 coordinator and wiring.

The new RTL 48 kHz producer and multi-receiver runtime remain disabled.
Recording/container changes (A3), TCI conversion (A4), and decoder/clock
conversion (A5) remain separate; accepting test-injected speaker48 PCM does
not qualify those consumers for a live 48 kHz producer.
The single-receiver RTL WFM candidate now produces native 48 kHz stereo; its
scope and qualification limits are documented in [rtl-wfm.md](rtl-wfm.md).
Multi-receiver admission remains disabled. Recording/container, TCI and
decoder/clock consumers keep their separately defined conversion contracts.

## Software evidence

Expand Down
26 changes: 17 additions & 9 deletions docs/rtl-m1-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,25 @@ blocks to the backend thread, which constructs revocable typed PCM. Queue gaps
are marked discontinuous. `AudioEngine::DEFAULT_SAMPLE_RATE` remains 24000 and
the audio device's output rate remains independently negotiated.

WFM and the other existing non-FM modes retain their exclusive legacy DDC and
24 kHz format. Their demodulation is unchanged; monitor mute continues to clock
an independent pre-monitor tap. They cannot join a multi-FM bank. Selecting FM
with an incompatible inherited wide/sideband filter chooses a 16 kHz passband;
ordinary filter requests and saved restores are never resized. This mode
transition was approved in [the #5924 maintainer ruling](https://github.com/aethersdr/AetherSDR/pull/5924#issuecomment-5787852269). WFM stereo and normalization qualification
remain S1/S2; no replacement WFM claim is made here.
WFM uses an explicitly qualified 384 kHz IQ / 192 kHz WDSP / 48 kHz paired
stereo recipe with independently prepared RF filtering, 50/75 µs de-emphasis
and completed-block stereo observation. Its RF and audio limits, generated
reference results and remaining validation boundaries are documented in
[`rtl-wfm.md`](rtl-wfm.md). Manual WFM squelch remains unavailable with a stated
reason; WDSP's internal automatic squelch remains in use. Saved sessions use a
muted legacy bootstrap before adopting the original receiver recipe and ID.

The other non-FM modes retain their exclusive legacy DDC and 24 kHz format.
Monitor mute continues to clock an independent pre-monitor tap. Production
admission remains one receiver. Selecting FM with an incompatible inherited
wide/sideband filter chooses a 16 kHz passband; ordinary filter requests and
saved restores are never resized. This mode transition was approved in
[the #5924 maintainer ruling](https://github.com/aethersdr/AetherSDR/pull/5924#issuecomment-5787852269).
The desktop FM/FM-N presets use the existing DFM width ladder intersected with
the backend's declared filter range; FMN and NFM share symmetric edge rules.
Fixed radio filter lists retain precedence. WFM filter and squelch controls
are unavailable with accessible reasons, and the backend refuses those edits.
WFM presets use the declared broadcast RF range. Fixed radio filter lists retain
precedence. WFM control placement and recipe choices remain subject to
maintainer review.

## FM squelch

Expand Down
Loading
Loading