Files
DigiRadio/Software/docs/manual/ch-classes.tex
T
micheleandCursor 0fc714e431 Add preset polish and broadcast metadata (fw 0.8.0).
Ship station reorder, DAB playing ids in presets, RDS PS/RT and DAB DLS in tuner status, Si4684 data-service read, host tests, and UI now-playing lines.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 00:01:49 +02:00

269 lines
13 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
\chapter{Class Reference}
\label{ch:classes}
This chapter documents the firmware's public classes at the design level:
what each class is responsible for, which collaborators it depends on, its
key invariants, and how it fits the system. It complements --- and does
not duplicate --- the generated API documentation, which carries the exact
method signatures. The HTTP JSON endpoints are documented separately in
Chapter~\ref{ch:api}.
\begin{drnote}[How this chapter grows]
Per the development rules, every public, architecturally-significant class
(the drivers, the application services, and the public domain-core types)
gets a section here, tagged \texttt{\textbackslash label\{cls:ClassName\}},
added in the same change that introduces the class. A tooling check keeps
this chapter in step with the code, so it is always current.
\end{drnote}
The firmware is under active development. As each public class lands, its
section appears below, grouped by layer: domain core, application
services, and hardware drivers.
% ------------------------------------------------------------------
% Domain core (Slice 1)
% ------------------------------------------------------------------
\section{FirmwareVersion}\label{cls:FirmwareVersion}
Strong type wrapping the firmware release identifier (e.g.\ \texttt{0.1.0}).
Used by \texttt{HealthStatus} and the \texttt{/api/health} endpoint so
version strings are never passed as bare \texttt{char*} across module
boundaries. Invariant: non-empty at construction.
\section{FrequencyKHz}\label{cls:FrequencyKHz}
Validated FM centre frequency in kilohertz (64\,000108\,000). Parsed once
from JSON at the HTTP boundary via \texttt{FrequencyKHz::tryFromKhz()};
trusted downstream by \texttt{ITuner}, \texttt{Si4684Driver}, and status DTOs.
\section{HealthStatus}\label{cls:HealthStatus}
Immutable health-check DTO returned by \texttt{GET /api/health}. Built via
\texttt{HealthStatus::ok(FirmwareVersion)} in the pure core; JSON
serialisation lives in \texttt{serializeHealthStatusJson()}. No ESP-IDF
headers.
% ------------------------------------------------------------------
% Network shell (Slice 1)
% ------------------------------------------------------------------
\section{SoftApConfig}\label{cls:SoftApConfig}
Immutable value type holding SoftAP parameters (SSID, channel, station
limit). Factory \texttt{setupDefault()} yields SSID \texttt{DigiRadio-setup}
for first-time provisioning.
\section{SoftApHost}\label{cls:SoftApHost}
RAII wrapper around the ESP-IDF Wi-Fi stack that starts and stops the
configured SoftAP. Imperative shell; no business logic.
\section{SetupWebServer}\label{cls:SetupWebServer}
Minimal HTTP server: gzipped setup UI, \texttt{GET /api/health},
\texttt{POST /api/wifi}, tuner routes (\texttt{/api/tuner/*}), audio
routes (\texttt{/api/audio/*}), Bluetooth (\texttt{/api/bluetooth/*}), and
station presets (\texttt{/api/stations/*}). JSON parsing and serialisation
delegate to the pure core; credentials persist via \texttt{ISecureStore};
tuner via \texttt{tuner::TunerService}; audio via
\texttt{audio::AudioService}; Bluetooth via \texttt{bluetooth::BluetoothService};
presets via \texttt{station::StationService}.
\section{NetBootstrap}\label{cls:NetBootstrap}
Owns network resources for setup or STA mode.
\texttt{start(store, tuner)} initialises the platform, joins stored Wi-Fi
when credentials exist, or falls back to the \texttt{DigiRadio-setup}
SoftAP. Must outlive \texttt{app\_main} for the process lifetime.
\texttt{start(store, tuner, audio)} also wires the audio REST routes.
% ------------------------------------------------------------------
% Domain core + secure store (Slice 2)
% ------------------------------------------------------------------
\section{Secret}\label{cls:Secret}
Opaque wrapper for sensitive strings. Buffer is zeroised on destruction;
no \texttt{operator<<} and no plaintext serialisation. Shell code uses
\texttt{usePlaintext()} transiently for driver APIs only.
\section{WifiSsid}\label{cls:WifiSsid}
Validated Wi-Fi SSID (1--32 bytes). Parsed once from untrusted JSON at
the HTTP boundary before persistence or driver calls.
\section{WifiCredentials}\label{cls:WifiCredentials}
Domain value pairing \texttt{WifiSsid} with a \texttt{Secret} password.
Open networks use an empty password; WPA-PSK requires 8--63 characters.
\section{ISecureStore}\label{cls:ISecureStore}
Abstract persistence boundary for credentials at rest. Slice~2 implements
Wi-Fi credential save/load/clear; station list and user credentials arrive
in later slices. Host tests use fakes; the shell uses \texttt{NvsSecureStore}.
\section{StaClient}\label{cls:StaClient}
RAII STA join helper with an explicit connect timeout. Assumes
\texttt{esp\_wifi\_init()} was already called by \texttt{NetBootstrap}.
\section{NvsSecureStore}\label{cls:NvsSecureStore}
\texttt{ISecureStore} implementation backed by an NVS namespace. Passwords
are stored as NVS strings and never logged. Production should enable NVS
encryption using the reserved \texttt{nvs\_keys} partition.
% ------------------------------------------------------------------
% Hardware drivers (Slice 3)
% ------------------------------------------------------------------
\section{IFirmwareBlobReader}\label{cls:IFirmwareBlobReader}
Abstract streaming reader for firmware blobs embedded in flash. The Si4684
driver uses it to HOST\_LOAD patch and application images in bounded SPI
chunks without allocating the full image on the heap. Host tests use the
same interface over in-memory buffers.
\section{EmbeddedBlobReader}\label{cls:EmbeddedBlobReader}
Non-owning \texttt{IFirmwareBlobReader} over a contiguous byte range (linker
symbols from \texttt{EMBED\_FILES} or test data). Implements offset-based
\texttt{read()} with truncation at end-of-blob.
\section{Si4684EmbeddedImages}\label{cls:Si4684EmbeddedImages}
Owns \texttt{EmbeddedBlobReader} views over \texttt{rom\_patch\_016.bin},
\texttt{dab\_firmware.bin}, and \texttt{fm\_firmware.bin}. Constructed once;
passed to \texttt{Si4684Driver}. \texttt{applicationImage(Si4684Band)} selects
DAB or FM.
\section{Si4684Driver}\label{cls:Si4684Driver}
Full SPI driver for the Si4684 DAB+/FM tuner (Chapter~\ref{ch:si4684}).
\texttt{boot(Si4684Band)} runs AN649 HOST\_LOAD, configures I\textsuperscript{2}S
and band-specific properties, and records \texttt{loadedBand()}. After boot the
driver exposes FM tuning/seek/RSQ/RDS, DAB ensemble tuning, digital service list
fetch, and \texttt{startDabService}. Property access (\texttt{setProperty},
\texttt{setVolume}) and diagnostics (\texttt{getPartInfo}, \texttt{getSysState})
are included. Wrong-band calls return \texttt{Si4684Error::WrongBand}.
Register-level opcodes remain private; see \texttt{Si4684Types.hpp} for status
DTOs. Full DAB/FM tuning guide: Chapter~\ref{ch:si4684}.
\section{Bt1035Driver}\label{cls:Bt1035Driver}
UART driver for the FSC-BT1035 (Chapter~\ref{ch:bt1035}). \texttt{boot()}
pulses RESET\#, opens UART2 with RTS/CTS, and runs
\texttt{core::bootInitSequence()} (Ping + \texttt{AT+AUXCFG=1}). Returns
\texttt{Bt1035Error} on timeout, ERROR response, or UART failure.
\section{Adau1701Driver}\label{cls:Adau1701Driver}
RAII I\textsuperscript{2}C driver for the ADAU1701 SigmaDSP
(Chapter~\ref{ch:adau1701}). \texttt{boot()} asserts RESET\#,
initialises the shared I2C bus, and replays the SigmaStudio export from
\texttt{Firmware/ADAU1701-Firmware/} on every power-up (no EEPROM self-boot
on DigiRadio). Runtime mixer, EQ, and master volume updates use the
ADAU1701 safeload mechanism via \texttt{applyProfile()} and related methods
(Section~\ref{sec:adau1701-driver}).
\section{Adau1701Dsp}\label{cls:Adau1701Dsp}
\texttt{core::IDsp} adapter over \texttt{Adau1701Driver}. Maps domain-level
audio control to safeload I\textsuperscript{2}C transactions without exposing
parameter RAM addresses to services (Chapter~\ref{ch:adau1701},
Section~\ref{sec:adau1701-stack}).
% ------------------------------------------------------------------
% Domain core — audio (Slice 5)
% ------------------------------------------------------------------
\section{GainDb}\label{cls:GainDb}
Validated decibel gain/attenuation ($-96$\,dB to $+12$\,dB). Used for
input volumes, master level, and EQ band gain. Converted to ADAU 8.23
fixpoint via \texttt{gainDbToLinearFixpoint()} before safeload.
\section{FrequencyHz}\label{cls:FrequencyHz}
Validated PEQ centre frequency (20--20\,000\,Hz) for the 48\,kHz
SigmaStudio project. Parsed at the HTTP boundary before coefficient design.
\section{EqBandIndex}\label{cls:EqBandIndex}
Strong index into the six-band \texttt{Param EQ1} module (0--5). Maps to
parameter RAM via \texttt{adau1701::paramAddrEqBandBase()}.
\section{EqProfile}\label{cls:EqProfile}
Six-band parametric EQ snapshot aligned with the SigmaStudio map
(Chapter~\ref{ch:sigmastudio}): band index~0 is the fixed 20\,Hz
high-pass; bands 1--5 are peaking at 100\,Hz--8\,kHz. Designed in the
pure core; peaking bands are safeloaded by \texttt{Adau1701Driver::applyEq()}
(band~0 is skipped).
\section{IDsp}\label{cls:IDsp}
Abstract ADAU1701 control boundary. Defines \texttt{applyProfile()},
\texttt{setInputVolume()}, \texttt{setEqBand()}, and related intent-level
operations without ESP-IDF types.
\section{IAudioProfileStore}\label{cls:IAudioProfileStore}
Persistence boundary for \texttt{AudioProfile} (mixer, EQ, master). Device
implementation: \texttt{NvsAudioProfileStore}; host tests use fakes.
% ------------------------------------------------------------------
% Application services (Slice 45)
% ------------------------------------------------------------------
\section{ITuner}\label{cls:ITuner}
Abstract tuner boundary in the pure core. Defines boot, band selection,
status readout, FM/DAB tuning, service list, playback, and volume without
ESP-IDF types. \texttt{si4684::Si4684Tuner} implements it on device; host
tests can use fakes.
\section{TunerService}\label{cls:TunerService}
Application service exposing intent-level tuner operations to HTTP and
future UI. Holds a reference to \texttt{core::ITuner}, tracks last tune
target and volume, and maps driver failures to \texttt{core::TunerError}.
\section{Si4684Tuner}\label{cls:Si4684Tuner}
\texttt{ITuner} adapter over \texttt{Si4684Driver}. Translates domain calls
into SPI commands and maps \texttt{Si4684Error} to \texttt{TunerError}.
Constructed once in \texttt{HardwareBootstrap} alongside the driver.
\section{AudioService}\label{cls:AudioService}
Application service for ADAU1701 mixer, EQ, and master volume
(Chapter~\ref{ch:adau1701}, Section~\ref{sec:adau1701-service}). Holds a
reference to \texttt{core::IDsp}, tracks the in-memory \texttt{AudioProfile},
loads from \texttt{IAudioProfileStore} after boot, and applies changes via
safeload. Stereo depth and bass enhance levels are merged into the effective
EQ via \texttt{core::applyEnhancementsToEq()}. Exposed on
\texttt{/api/audio/*} and the web UI Audio section.
\section{EnhanceLevel}\label{cls:EnhanceLevel}
Strong type for 0--100 enhancement intensity (stereo depth and bass boost).
Validated at the HTTP boundary by \texttt{core::parseEnhanceLevelJson()}.
\section{NvsAudioProfileStore}\label{cls:NvsAudioProfileStore}
\texttt{IAudioProfileStore} implementation storing serialised
\texttt{AudioProfile} JSON in NVS namespace \texttt{digiradio}.
\section{StationName}\label{cls:StationName}
Strong type for a preset label (1--32 bytes). Parsed at the HTTP boundary
via \texttt{StationName::tryFrom()}.
\section{BroadcastLabel}\label{cls:BroadcastLabel}
Trimmed on-air label from RDS or DAB chip byte buffers (up to 128 bytes).
Built by \texttt{BroadcastLabel::tryFromChipBytes()} in the pure core.
\section{RdsMetadataAccumulator}\label{cls:RdsMetadataAccumulator}
Stateful RDS decoder assembling program service name and radiotext from
raw block~A--D snapshots returned by the Si4684 driver.
\section{DabDynamicLabelAccumulator}\label{cls:DabDynamicLabelAccumulator}
Reassembles segmented DAB DLS payloads into one dynamic label for
\texttt{TunerStatus}.
\section{PresetSlot}\label{cls:PresetSlot}
Optional hardware preset button index (1--20). Validated by
\texttt{PresetSlot::tryFrom()}.
\section{Station}\label{cls:Station}
Immutable preset value: name, band (DAB/FM), tune coordinates, optional
preset slot. FM presets carry \texttt{FrequencyKHz}; DAB presets carry
ensemble index and optional service/component ids for playback.
\section{StationList}\label{cls:StationList}
Pure-domain ordered collection (max 20 entries) with add/remove/move and
duplicate tune-target rejection. Persisted as JSON through
\texttt{ISecureStore}.
\section{StationService}\label{cls:StationService}
Application service loading/saving presets from NVS and recalling them via
\texttt{TunerService}. Exposed on \texttt{/api/stations/*} and the Presets
web UI section.
\section{BluetoothService}\label{cls:BluetoothService}
Application service for BT1035 pairing and A2DP status
(Chapter~\ref{ch:bt1035}). Delegates to \texttt{Bt1035Driver}; tracks
whether discoverable mode was requested. Exposed on
\texttt{/api/bluetooth/*}.