Fix manual typographic overflow in tables and API chapter.
Add wrapping table columns, breakable paths, and ragged callout boxes in digiradio-manual.sty, then reflow long endpoint headings, JSON examples, and hardware/driver tables to stay within page margins. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -46,7 +46,7 @@ authoritative DSP program for firmware builds.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}llp{6.5cm}@{}}
|
||||
\begin{tabular}{@{}L{3.8cm}L{3.5cm}L{6.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{File} & \textbf{Role} & \textbf{Used by firmware} \\
|
||||
\midrule
|
||||
@@ -151,7 +151,7 @@ separates concerns as follows:
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}llp{5.8cm}@{}}
|
||||
\begin{tabular}{@{}L{2.5cm}L{3.8cm}L{6.2cm}@{}}
|
||||
\drhead Layer & Type & Responsibility \\
|
||||
\midrule
|
||||
HTTP / UI & \texttt{SetupWebServer}, web UI &
|
||||
@@ -189,7 +189,7 @@ successful \texttt{boot()}.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Method} & \textbf{Purpose} \\
|
||||
\midrule
|
||||
@@ -205,7 +205,7 @@ successful \texttt{boot()}.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Method} & \textbf{Purpose} \\
|
||||
\midrule
|
||||
@@ -237,7 +237,7 @@ runtime-adjustable, matching Table~\ref{tab:ss-runtime}.
|
||||
\subsection{Gain and EQ coefficient path}
|
||||
|
||||
Volume cells (faders, master) store linear gain as ADAU \textbf{8.23 fixpoint}.
|
||||
\texttt{core::gainDbToLinearFixpoint()} converts \texttt{GainDb} before
|
||||
\texttt{core::gainDbTo\-LinearFixpoint()} converts \texttt{GainDb} before
|
||||
\texttt{sigma\_safeload\_param()}.
|
||||
|
||||
PEQ bands use \texttt{core::designPeakingEq()} at 48\,kHz sample rate to
|
||||
@@ -259,13 +259,13 @@ header \texttt{DigiRadio\_IC\_1\_PARAM.h} defines \texttt{ADDR\_*} symbols;
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Domain & \texttt{ADDR\_*} & SigmaStudio block \\
|
||||
\midrule
|
||||
Si4684 L/R & \texttt{SI4674}, \texttt{SI4674\_1} & Si4674 fader \\
|
||||
ESP32 L/R & \texttt{ESP32}, \texttt{ESP32\_1} & ESP32 fader \\
|
||||
Mix L/R & \texttt{STMIXER1\_ST0/1\_VOLUME} & St Mixer1 \\
|
||||
EQ band $n$ & \texttt{PARAMEQ1\_ST$n$\_B0} + 0..4 & Param EQ1 coeffs \\
|
||||
Mix L/R & {\footnotesize\texttt{STMIXER1\_ST0/1\_VOLUME}} & St Mixer1 \\
|
||||
EQ band $n$ & {\footnotesize\texttt{PARAMEQ1\_ST$n$\_B0} + 0..4} & Param EQ1 coeffs \\
|
||||
Master L/R & \texttt{MULTIPLE1}, \texttt{MULTIPLE1\_1} & Multiple 1 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
@@ -335,7 +335,7 @@ use for audio path control:
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Method} & \textbf{Effect} \\
|
||||
\midrule
|
||||
@@ -423,7 +423,7 @@ only if band indices and centre frequencies still match; otherwise reset via
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead Error & Typical cause \\
|
||||
\midrule
|
||||
\texttt{ResetFailed} & GPIO reset line configuration \\
|
||||
|
||||
@@ -27,7 +27,7 @@ All responses use \texttt{Content-Type: application/json} except
|
||||
|
||||
\section{Endpoints}
|
||||
|
||||
\subsection{\texttt{GET /api/health}}
|
||||
\apiendpoint{GET}{/api/health}
|
||||
\label{sec:api-health}
|
||||
|
||||
Returns a health-check DTO serialised by
|
||||
@@ -53,7 +53,7 @@ Returns a health-check DTO serialised by
|
||||
|
||||
HTTP status: \textbf{200 OK} on success.
|
||||
|
||||
\subsection{\texttt{POST /api/wifi}}
|
||||
\apiendpoint{POST}{/api/wifi}
|
||||
\label{sec:api-wifi}
|
||||
|
||||
Accepts Wi-Fi credentials for station (STA) join. The body is parsed by
|
||||
@@ -88,17 +88,16 @@ reboots after the indicated delay.
|
||||
\begin{drcode}[JSON]
|
||||
{"status":"error","reason":"invalid_ssid"}
|
||||
\end{drcode}
|
||||
Serialised by \texttt{core::serializeWifiProvisionErrorJson()}. Reason
|
||||
tokens (never include secrets): \texttt{invalid\_json},
|
||||
\texttt{missing\_field}, \texttt{invalid\_ssid}, \texttt{invalid\_password},
|
||||
\texttt{store\_failed}.
|
||||
Serialised by \texttt{core::serializeWifiProvisionErrorJson()}. Reason tokens (never include secrets):
|
||||
\texttt{invalid\_json}, \texttt{missing\_field}, \texttt{invalid\_ssid},
|
||||
\texttt{invalid\_password}, \texttt{store\_failed}.
|
||||
\end{drnote}
|
||||
|
||||
HTTP status: \textbf{200 OK} on save success; \textbf{400 Bad Request} for
|
||||
parse/validation failures; \textbf{500 Internal Server Error} when NVS
|
||||
persistence fails.
|
||||
|
||||
\subsection{\texttt{GET /api/tuner/status}}
|
||||
\apiendpoint{GET}{/api/tuner/status}
|
||||
\label{sec:api-tuner-status}
|
||||
|
||||
Returns a tuner snapshot serialised by
|
||||
@@ -112,7 +111,8 @@ and~\ref{sec:si4684-fm-session}.
|
||||
{"booted":true,"band":"dab","locked":true,"volume":63,
|
||||
"dab":{"freq_index":12,"fic_quality":80,"cnr_db":25,
|
||||
"playing_service_id":42,"playing_component_id":7,
|
||||
"dynamic_label":"Live show"},"fm":null}
|
||||
"dynamic_label":"Live show"},
|
||||
"fm":null}
|
||||
\end{drcode}
|
||||
For FM, \texttt{fm} carries \texttt{frequency\_khz}, \texttt{rssi\_dbuv},
|
||||
\texttt{snr\_db}, \texttt{stereo}, optional \texttt{station\_name} (RDS PS),
|
||||
@@ -125,7 +125,7 @@ HTTP status: \textbf{200 OK}; \textbf{500} with
|
||||
\texttt{station\_name} and \texttt{radiotext}; DAB responses may include
|
||||
\texttt{dynamic\_label} when a programme is playing.
|
||||
|
||||
\subsection{\texttt{GET /api/tuner/services}}
|
||||
\apiendpoint{GET}{/api/tuner/services}
|
||||
\label{sec:api-tuner-services}
|
||||
|
||||
Lists DAB programmes for the current ensemble via
|
||||
@@ -140,7 +140,7 @@ Lists DAB programmes for the current ensemble via
|
||||
HTTP status: \textbf{200 OK}; \textbf{409 Conflict} when the list cannot be
|
||||
fetched (wrong band, empty ensemble, hardware error).
|
||||
|
||||
\subsection{\texttt{POST /api/tuner/tune}}
|
||||
\apiendpoint{POST}{/api/tuner/tune}
|
||||
\label{sec:api-tuner-tune}
|
||||
|
||||
Tunes to a DAB ensemble or FM frequency. Body parsed by
|
||||
@@ -162,7 +162,7 @@ On success returns the updated status JSON (same shape as
|
||||
\texttt{GET /api/tuner/status}). HTTP status: \textbf{200 OK};
|
||||
\textbf{400} for invalid JSON; \textbf{409} for tune failures.
|
||||
|
||||
\subsection{\texttt{POST /api/tuner/play}}
|
||||
\apiendpoint{POST}{/api/tuner/play}
|
||||
\label{sec:api-tuner-play}
|
||||
|
||||
Starts a DAB audio service. Body parsed by
|
||||
@@ -177,7 +177,7 @@ Starts a DAB audio service. Body parsed by
|
||||
Success response: \texttt{\{"status":"playing"\}}. HTTP status:
|
||||
\textbf{200 OK}; \textbf{409} when playback cannot start.
|
||||
|
||||
\subsection{\texttt{POST /api/tuner/seek}}
|
||||
\apiendpoint{POST}{/api/tuner/seek}
|
||||
\label{sec:api-tuner-seek}
|
||||
|
||||
Seeks FM in the requested direction. Optional JSON body parsed by
|
||||
@@ -194,7 +194,7 @@ Use \texttt{"down"} for downward seek. Omit the body or send an empty JSON
|
||||
object (\texttt{\{\}}) for upward seek (backward compatible).
|
||||
\end{drnote}
|
||||
|
||||
\subsection{\texttt{GET /api/audio/profile}}
|
||||
\apiendpoint{GET}{/api/audio/profile}
|
||||
\label{sec:api-audio-profile-get}
|
||||
|
||||
Returns the current ADAU1701 audio snapshot serialised by
|
||||
@@ -205,8 +205,9 @@ Chapter~\ref{ch:adau1701}.
|
||||
|
||||
\begin{drnote}[Response schema (excerpt)]
|
||||
\begin{drcode}[JSON]
|
||||
{"mixer":{"si4684_left_db":0,"si4684_right_db":0,"esp32_left_db":0,
|
||||
"esp32_right_db":0,"mix_left_db":0,"mix_right_db":0},
|
||||
{"mixer":{"si4684_left_db":0,"si4684_right_db":0,
|
||||
"esp32_left_db":0,"esp32_right_db":0,
|
||||
"mix_left_db":0,"mix_right_db":0},
|
||||
"master":{"left_db":0,"right_db":0},
|
||||
"eq":[{"gain_db":0,"center_hz":40,"q":1.414}, ...],
|
||||
"enhancements":{"stereo_level":0,"bass_level":0}}
|
||||
@@ -218,7 +219,7 @@ Enhancement levels are 0--100; at 0 the base EQ band settings apply.
|
||||
HTTP status: \textbf{200 OK}; \textbf{503} when the audio service is
|
||||
unavailable.
|
||||
|
||||
\subsection{\texttt{PUT /api/audio/profile}}
|
||||
\apiendpoint{PUT}{/api/audio/profile}
|
||||
\label{sec:api-audio-profile-put}
|
||||
|
||||
Applies a full audio profile. Body parsed by
|
||||
@@ -235,7 +236,7 @@ the ADAU1701 and writes NVS key \texttt{audio\_profile\_json}.
|
||||
HTTP status: \textbf{200 OK}; \textbf{400} for parse/validation failures;
|
||||
\textbf{500} when safeload or NVS persistence fails.
|
||||
|
||||
\subsection{\texttt{POST /api/dsp/program}}
|
||||
\apiendpoint{POST}{/api/dsp/program}
|
||||
\label{sec:api-dsp-program}
|
||||
|
||||
Uploads a framed ADAU1701 RAM download blob (\texttt{DRAD} v1, see
|
||||
@@ -255,7 +256,7 @@ for invalid/truncated/CRC failures; \textbf{413} when the body exceeds
|
||||
200\,KiB; \textbf{500} on flash write failure. Pack blobs with
|
||||
\texttt{tools/pack\_dsp\_program.py} or \texttt{core::serializeDspProgramBlob()}.
|
||||
|
||||
\subsection{\texttt{POST /api/system/ota}}
|
||||
\apiendpoint{POST}{/api/system/ota}
|
||||
\label{sec:api-system-ota}
|
||||
|
||||
Streams a raw ESP-IDF application \texttt{.bin} into the inactive OTA slot
|
||||
@@ -278,7 +279,7 @@ for invalid project/magic or flash write failures;
|
||||
\textbf{500} on \texttt{esp\_ota\_end}/set-boot failures. Push with
|
||||
\texttt{curl --data-binary @build/digiradio.bin}.
|
||||
|
||||
\subsection{\texttt{POST /api/audio/reset}}
|
||||
\apiendpoint{POST}{/api/audio/reset}
|
||||
\label{sec:api-audio-reset}
|
||||
|
||||
Restores \texttt{AudioProfile::factoryDefault()} (flat EQ, 0\,dB gains),
|
||||
@@ -286,7 +287,7 @@ applies it to the DSP, and persists to NVS. Success response:
|
||||
\texttt{\{"status":"saved"\}}. HTTP status: \textbf{200 OK}; \textbf{500}
|
||||
on apply/persist failure.
|
||||
|
||||
\subsection{\texttt{POST /api/audio/stereo-enhance}}
|
||||
\apiendpoint{POST}{/api/audio/stereo-enhance}
|
||||
\label{sec:api-audio-stereo-enhance}
|
||||
|
||||
Adjusts stereo depth via a psychoacoustic PEQ overlay on bands 3--5
|
||||
@@ -305,7 +306,7 @@ Success response: \texttt{\{"status":"saved"\}}. HTTP status:
|
||||
\textbf{200 OK}; \textbf{400} for invalid JSON or level; \textbf{500}
|
||||
when safeload or NVS persistence fails.
|
||||
|
||||
\subsection{\texttt{POST /api/audio/bass-enhance}}
|
||||
\apiendpoint{POST}{/api/audio/bass-enhance}
|
||||
\label{sec:api-audio-bass-enhance}
|
||||
|
||||
Adjusts bass emphasis via a PEQ overlay on bands 1--2 (100\,Hz /
|
||||
@@ -316,7 +317,7 @@ Adjusts bass emphasis via a PEQ overlay on bands 1--2 (100\,Hz /
|
||||
% Bluetooth (Slice 7)
|
||||
% ------------------------------------------------------------------
|
||||
|
||||
\subsection{\texttt{GET /api/bluetooth/status}}
|
||||
\apiendpoint{GET}{/api/bluetooth/status}
|
||||
\label{sec:api-bluetooth-status}
|
||||
|
||||
Returns BT1035 boot flag, whether discoverable mode was requested, the
|
||||
@@ -330,24 +331,24 @@ Serialised by \texttt{core::serializeBluetoothStatusJson()}.
|
||||
\end{drcode}
|
||||
\end{drnote}
|
||||
|
||||
\subsection{\texttt{POST /api/bluetooth/pair}}
|
||||
\apiendpoint{POST}{/api/bluetooth/pair}
|
||||
\label{sec:api-bluetooth-pair}
|
||||
|
||||
Enters discoverable mode (\texttt{AT+PAIR=1}). Success:
|
||||
\texttt{\{"status":"pairing"\}}.
|
||||
|
||||
\subsection{\texttt{POST /api/bluetooth/pair/stop}}
|
||||
\apiendpoint{POST}{/api/bluetooth/pair/stop}
|
||||
\label{sec:api-bluetooth-pair-stop}
|
||||
|
||||
Leaves discoverable mode (\texttt{AT+PAIR=0}). Success:
|
||||
\texttt{\{"status":"idle"\}}.
|
||||
|
||||
\subsection{\texttt{POST /api/bluetooth/disconnect}}
|
||||
\apiendpoint{POST}{/api/bluetooth/disconnect}
|
||||
\label{sec:api-bluetooth-disconnect}
|
||||
|
||||
Releases the current A2DP session (\texttt{AT+A2DPDISC}).
|
||||
|
||||
\subsection{\texttt{GET /api/bluetooth/paired}}
|
||||
\apiendpoint{GET}{/api/bluetooth/paired}
|
||||
\label{sec:api-bluetooth-paired}
|
||||
|
||||
Returns paired remotes from \texttt{AT+PLIST}, serialised by
|
||||
@@ -359,7 +360,7 @@ Returns paired remotes from \texttt{AT+PLIST}, serialised by
|
||||
\end{drcode}
|
||||
\end{drnote}
|
||||
|
||||
\subsection{\texttt{POST /api/bluetooth/auto-reconnect}}
|
||||
\apiendpoint{POST}{/api/bluetooth/auto-reconnect}
|
||||
\label{sec:api-bluetooth-auto-reconnect}
|
||||
|
||||
Sets the module auto-reconnect retry count (\texttt{AT+AUTOCONN=0..15}).
|
||||
@@ -376,29 +377,29 @@ Success: \texttt{\{"status":"saved"\}}.
|
||||
% Station presets (Slice 4)
|
||||
% ------------------------------------------------------------------
|
||||
|
||||
\subsection{\texttt{GET /api/stations}}
|
||||
\apiendpoint{GET}{/api/stations}
|
||||
\label{sec:api-stations-get}
|
||||
|
||||
Returns presets serialised by \texttt{core::serializeStationListJson()}.
|
||||
|
||||
\subsection{\texttt{POST /api/stations}}
|
||||
\apiendpoint{POST}{/api/stations}
|
||||
\label{sec:api-stations-post}
|
||||
|
||||
Adds one preset (\texttt{core::parseStationJson()}); persists via
|
||||
\texttt{ISecureStore::saveStationListJson()}.
|
||||
|
||||
\subsection{\texttt{POST /api/stations/remove}}
|
||||
\apiendpoint{POST}{/api/stations/remove}
|
||||
\label{sec:api-stations-remove}
|
||||
|
||||
Removes a preset by list index (\texttt{\{"index":0\}}).
|
||||
|
||||
\subsection{\texttt{POST /api/stations/reorder}}
|
||||
\apiendpoint{POST}{/api/stations/reorder}
|
||||
\label{sec:api-stations-reorder}
|
||||
|
||||
Reorders presets using \texttt{StationList::move()}. Body:
|
||||
\texttt{\{"from":1,"to":0\}}. Success: \texttt{\{"status":"reordered"\}}.
|
||||
|
||||
\subsection{\texttt{POST /api/stations/tune}}
|
||||
\apiendpoint{POST}{/api/stations/tune}
|
||||
\label{sec:api-stations-tune}
|
||||
|
||||
Recalls a preset via \texttt{integration::IntegrationService::recallPreset()}
|
||||
@@ -435,10 +436,10 @@ as \texttt{last\_preset} (u8). Passwords are wrapped in
|
||||
\texttt{core::Secret} in RAM and are never logged or returned by the API.
|
||||
|
||||
\begin{drcaution}[Encryption at rest]
|
||||
Firmware~0.8.3+ enables NVS encryption (\texttt{CONFIG\_NVS\_ENCRYPTION}) and
|
||||
flash encryption in development mode (\texttt{sdkconfig.defaults}). Keys live in
|
||||
the \texttt{nvs\_keys} partition; Wi-Fi passwords remain wrapped in
|
||||
\texttt{core::Secret} in RAM and are never logged. First upgrade from plain NVS
|
||||
requires \texttt{idf.py erase-flash}. HIL checklist:
|
||||
\texttt{Software/docs/security-flash-nvs.md}.
|
||||
Firmware~0.8.3+ enables NVS encryption
|
||||
(\texttt{CONFIG\_NVS\_ENCRYPTION}) and flash encryption in development mode
|
||||
(\texttt{sdkconfig.defaults}). Keys live in the \texttt{nvs\_keys} partition;
|
||||
Wi-Fi passwords remain wrapped in \texttt{core::Secret} in RAM and are never
|
||||
logged. First upgrade from plain NVS requires \texttt{idf.py erase-flash}.
|
||||
HIL checklist: \drpath{Software/docs/security-flash-nvs.md}.
|
||||
\end{drcaution}
|
||||
|
||||
@@ -41,7 +41,8 @@ output (Section~\ref{sec:bt1035-i2s}).
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead Setting & Value \\
|
||||
\midrule
|
||||
Port & UART2 (not the console UART) \\
|
||||
@@ -67,7 +68,7 @@ Every command expects a module reply containing \texttt{OK} or
|
||||
\item treats timeouts and unexpected payloads as errors (never ignored).
|
||||
\end{itemize}
|
||||
|
||||
Host tests in \texttt{components/core/test/bt1035\_at\_test.cpp} lock the
|
||||
Host tests in \drpath{components/core/test/bt1035_at_test.cpp} lock the
|
||||
init sequence (\texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67}) and the parser.
|
||||
|
||||
\section{Mandatory I\textsuperscript{2}S slave mode}
|
||||
@@ -76,11 +77,13 @@ init sequence (\texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67}) and the parser.
|
||||
\begin{drcaution}[I\textsuperscript{2}S init is not optional]
|
||||
The board routes ADAU1701 \texttt{SDATA\_OUT0} (MP6) to the module PCM input
|
||||
with shared BCLK/LRCLK (see Chapter~\ref{ch:hardware}). The init sequence
|
||||
must therefore use \texttt{AT+AUXCFG=3} (I\textsuperscript{2}S mode per
|
||||
programming guide §5.1.25) followed by \texttt{AT+I2SCFG=67} (I\textsuperscript{2}S
|
||||
slave, 48\,kHz, 32-bit per §5.1.4). \texttt{AT+AUXCFG=1} (Line-In) does
|
||||
\textbf{not} match the schematic. AGENTS.md treats skipping I\textsuperscript{2}S
|
||||
init as a production bug.
|
||||
must use:
|
||||
\begin{itemize}
|
||||
\item \texttt{AT+AUXCFG=3} --- I\textsuperscript{2}S mode (§5.1.25)
|
||||
\item \texttt{AT+I2SCFG=67} --- I\textsuperscript{2}S slave, 48\,kHz, 32-bit (§5.1.4)
|
||||
\end{itemize}
|
||||
\texttt{AT+AUXCFG=1} (Line-In) does \textbf{not} match the schematic.
|
||||
AGENTS.md treats skipping I\textsuperscript{2}S init as a production bug.
|
||||
\end{drcaution}
|
||||
|
||||
\section{Boot sequence}
|
||||
@@ -125,7 +128,7 @@ only the I\textsuperscript{2}S bring-up required for the wired audio path.
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}llp{5.8cm}@{}}
|
||||
\begin{tabular}{@{}L{2.5cm}L{3.8cm}L{6.2cm}@{}}
|
||||
\drhead Layer & Type & Responsibility \\
|
||||
\midrule
|
||||
Bootstrap & \texttt{HardwareBootstrap} &
|
||||
@@ -145,14 +148,14 @@ only the I\textsuperscript{2}S bring-up required for the wired audio path.
|
||||
\label{sec:bt1035-at}
|
||||
|
||||
The firmware enumerates every command it sends. Wire formats follow
|
||||
\texttt{Hardware/DATASHEET/FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf}
|
||||
\drpath{Hardware/DATASHEET/FSC-BT1035_programming_user_guide_1.1.1.pdf}
|
||||
(§5 commands, §6 events). Extending the subset requires updating
|
||||
\texttt{core::Bt1035AtCommand}, the manual, and a host test.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}llp{5.2cm}@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.4cm}L{5.5cm}@{}}
|
||||
\drhead Enum & Line sent & Programming guide \\
|
||||
\midrule
|
||||
\texttt{Ping} & \texttt{AT} & link check \\
|
||||
@@ -184,7 +187,8 @@ reconnect count).
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Method} & \textbf{Purpose} \\
|
||||
\midrule
|
||||
@@ -210,7 +214,7 @@ reconnect count).
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead \texttt{Bt1035Error} & Typical cause \\
|
||||
\midrule
|
||||
\texttt{ResetFailed} & GPIO configuration failure \\
|
||||
|
||||
@@ -8,7 +8,7 @@ builds and is unit-tested on the host machine.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead Item & Choice \\
|
||||
\midrule
|
||||
Framework & ESP-IDF v5.5.x (native) \\
|
||||
|
||||
@@ -72,11 +72,15 @@ 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};
|
||||
Minimal HTTP server: gzipped setup UI and typed JSON REST handlers:
|
||||
\begin{itemize}
|
||||
\item \texttt{GET /api/health}, \texttt{POST /api/wifi}
|
||||
\item Tuner: \texttt{/api/tuner/*}
|
||||
\item Audio: \texttt{/api/audio/*}
|
||||
\item Bluetooth: \texttt{/api/bluetooth/*}
|
||||
\item Presets: \texttt{/api/stations/*}
|
||||
\end{itemize}
|
||||
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}.
|
||||
|
||||
@@ -240,7 +240,7 @@ disabled.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Item} & \textbf{Choice} \\
|
||||
\midrule
|
||||
|
||||
@@ -36,7 +36,8 @@ interface.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}llll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{2.6cm}L{4.2cm}L{2.6cm}L{3.8cm}@{}}
|
||||
\drhead Device & Role & Control bus & Firmware \\
|
||||
\midrule
|
||||
Si4684 & DAB+/FM tuner & SPI & host-loaded image \\
|
||||
@@ -152,7 +153,7 @@ The host speaks several interfaces, each chosen for its traffic:
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Bus & Devices & Purpose \\
|
||||
\midrule
|
||||
SPI & Si4684 & fast firmware-image upload, tuner control \\
|
||||
@@ -192,7 +193,7 @@ and the companion chips. The firmware pin definitions
|
||||
\subsection{System and control lines}
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Signal & ESP32-S3 GPIO & Notes \\
|
||||
\midrule
|
||||
USB D$-$ & GPIO19 & native USB \\
|
||||
@@ -207,7 +208,8 @@ and the companion chips. The firmware pin definitions
|
||||
\subsection{Si4684 tuner (SPI)}
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}llll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{2.4cm}L{2.2cm}L{2.8cm}L{5.8cm}@{}}
|
||||
\drhead Signal & Si4684 pin & ESP32-S3 GPIO & Notes \\
|
||||
\midrule
|
||||
SCLK & pin 30 & GPIO13 & \\
|
||||
@@ -225,7 +227,7 @@ and the companion chips. The firmware pin definitions
|
||||
\subsection{ADAU1701 DSP (I\textsuperscript{2}C)}
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Signal & ADAU1701 pin & ESP32-S3 GPIO \\
|
||||
\midrule
|
||||
SDA & --- & GPIO4 \\
|
||||
@@ -247,7 +249,7 @@ serial number. Its 7-bit address is 0x52 (A0 to GND, A1 to 3V3).
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Device & 7-bit address & Set by \\
|
||||
\midrule
|
||||
ADAU1701 & 0x34 & ADDR0, ADDR1 = GND \\
|
||||
@@ -261,7 +263,8 @@ serial number. Its 7-bit address is 0x52 (A0 to GND, A1 to 3V3).
|
||||
\subsection{FSC-BT1035 Bluetooth}
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}llll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{2.2cm}L{2.2cm}L{2.8cm}L{5.8cm}@{}}
|
||||
\drhead Signal & BT1035 pin & ESP32-S3 GPIO & Direction \\
|
||||
\midrule
|
||||
SYS\_CTL & pin 34 & GPIO15 & ESP32 $\rightarrow$ BT \\
|
||||
@@ -285,7 +288,7 @@ I\textsuperscript{2}S source lines that feed the mixer.
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Signal & Path & ADAU1701 / BT1035 pins \\
|
||||
\midrule
|
||||
SDATA\_IN0 & Si4684 $\rightarrow$ ADAU & MP0 (pin 11) \\
|
||||
@@ -302,7 +305,7 @@ I\textsuperscript{2}S source lines that feed the mixer.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Signal & ESP32-S3 GPIO & Direction \\
|
||||
\midrule
|
||||
BCLK & GPIO6 & in from ADAU (master) \\
|
||||
@@ -365,12 +368,13 @@ satisfying the +10\,\textmu s requirement in practice.
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{3.2cm}L{8.2cm}L{2.2cm}@{}}
|
||||
\drhead Check & Requirement (datasheet) & Status \\
|
||||
\midrule
|
||||
RSTB low at power-up & held low until supplies stable +10\,\textmu s & verified (pull-down) \\
|
||||
RSTB release (firmware) & not before supplies stable; boot pulse only & verified (driver) \\
|
||||
RSTB glitch guard (firmware) & \texttt{GPIO\_PULLDOWN\_ENABLE} in \texttt{gpio\_config} & verified (driver) \\
|
||||
RSTB glitch guard (firmware) &
|
||||
\texttt{GPIO\_PULLDOWN\_ENABLE} in \texttt{gpio\_config} & verified \\
|
||||
Core supplies at 1.8\,V & VA = VCORE = VMEM = 1.8\,V & verified \\
|
||||
VIO level & 1.62--3.6\,V (3.3\,V to talk to ESP32) & verified \\
|
||||
Bypass caps & 2.2\,nF + 1\,\textmu F per VIO/VMEM/VCORE rail & verified \\
|
||||
@@ -379,19 +383,17 @@ satisfying the +10\,\textmu s requirement in practice.
|
||||
INTB & interrupt line, external pull-up (GPIO39) & verified \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\caption{Si4684 design checks. References:
|
||||
\texttt{Hardware/DATASHEET/SI4684-A10.pdf} (power sequencing, SPI,
|
||||
supply levels) and \texttt{Hardware/DATASHEET/AN851.pdf} (bypass and layout).}
|
||||
\caption{Si4684 design checks (datasheet references below).}
|
||||
\label{tab:hw-val-si4684}
|
||||
\end{table}
|
||||
|
||||
\begin{drref}[Datasheet]
|
||||
Power sequencing and SPI framing:
|
||||
\texttt{Hardware/DATASHEET/SI4684-A10.pdf}. The user must not pulse SSB high
|
||||
between bytes; SSB frames the whole command/reply.
|
||||
Bypass-capacitor values and placement: \texttt{Hardware/DATASHEET/AN851.pdf},
|
||||
\emph{Si468x Schematic and Layout Guide}. Boot and command protocol: AN649.
|
||||
Local copies: \texttt{Hardware/DATASHEET/} (see \texttt{README.md}).
|
||||
Power sequencing and SPI framing: \drpath{Hardware/DATASHEET/SI4684-A10.pdf}.
|
||||
The user must not pulse SSB high between bytes; SSB frames the whole
|
||||
command/reply. Bypass-capacitor values and placement:
|
||||
\drpath{Hardware/DATASHEET/AN851.pdf}, \emph{Si468x Schematic and Layout
|
||||
Guide}. Boot and command protocol: AN649. Local copies:
|
||||
\drpath{Hardware/DATASHEET/} (see \drpath{README.md}).
|
||||
\end{drref}
|
||||
|
||||
The core, memory, and analogue rails run at 1.8\,V; only VIO is at 3.3\,V
|
||||
@@ -415,7 +417,7 @@ locks up when input data arrives.
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Check & Requirement (datasheet) & Status \\
|
||||
\midrule
|
||||
Clock loopback & MP10$\rightarrow$MP4, MP11$\rightarrow$MP5 wired & verified \\
|
||||
@@ -452,18 +454,17 @@ Schematic \texttt{DigitalRadio.pdf} and BOM list R1 (SCL) and R16 (SDA) as
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{3.5cm}L{7.5cm}L{2.5cm}@{}}
|
||||
\drhead Check & Requirement & Status \\
|
||||
\midrule
|
||||
UART with flow control & TX/RX + RTS/CTS wired & verified \\
|
||||
I\textsuperscript{2}S init (firmware) & \texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67} & driver rule \\
|
||||
I\textsuperscript{2}S init (firmware) &
|
||||
\texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67} & driver rule \\
|
||||
I\textsuperscript{2}S input & receives clocks from ADAU master (slave) & verified \\
|
||||
Reset line & RESET (GPIO17) driven by ESP32 & verified \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\caption{FSC-BT1035 design checks. Datasheet:
|
||||
\texttt{Hardware/DATASHEET/FSC-BT1035\_Datasheet\_EN.pdf}; AT commands:
|
||||
\texttt{FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf} §5.}
|
||||
\caption{FSC-BT1035 design checks (datasheets in \drpath{Hardware/DATASHEET/}).}
|
||||
\label{tab:hw-val-bt1035}
|
||||
\end{table}
|
||||
|
||||
@@ -479,7 +480,8 @@ UART 115200/8/N/1, SSP on, auto-reconnect configurable via
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\small
|
||||
\begin{tabular}{@{}L{2.2cm}L{4.8cm}L{6.6cm}@{}}
|
||||
\drhead Area & Item & Status \\
|
||||
\midrule
|
||||
Si4684 & RSTB pull-down, 1.8\,V rails, bypass caps, SPI & verified \\
|
||||
|
||||
@@ -38,7 +38,8 @@ uGreen licence); \texttt{.gitignore} keeps them on the developer machine only.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}llp{6.2cm}@{}}
|
||||
\footnotesize
|
||||
\begin{tabular}{@{}L{3.2cm}L{2.2cm}L{8.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Local file} & \textbf{Typ.\ size} & \textbf{Source} \\
|
||||
\midrule
|
||||
@@ -99,7 +100,8 @@ python3 tools/fetch_si4684_firmware.py \
|
||||
--from-ugreen-radio-cli ~/Downloads/Files_v16.zip --ugreen-all
|
||||
|
||||
# FM from dabpi / Skyworks eval folder:
|
||||
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware
|
||||
python3 tools/fetch_si4684_firmware.py \\
|
||||
--si46xx-dir /path/to/si46xx_firmware
|
||||
\end{verbatim}
|
||||
|
||||
Low-level helpers: \texttt{tools/extract\_si4684\_blob.py} (C header or copy),
|
||||
@@ -167,7 +169,7 @@ versa for DAB.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\toprule
|
||||
\textbf{Method} & \textbf{Purpose} \\
|
||||
\midrule
|
||||
@@ -284,7 +286,7 @@ selects the blob:
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Band & Image loaded & Primary API \\
|
||||
\midrule
|
||||
\texttt{Si4684Band::Dab} & \texttt{dab\_firmware.bin} &
|
||||
@@ -309,14 +311,16 @@ The setup UI and REST clients use \texttt{tuner::TunerService}, which wraps
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}llp{5.5cm}@{}}
|
||||
\footnotesize
|
||||
\begin{tabular}{@{}L{2.8cm}L{1.6cm}L{8.2cm}@{}}
|
||||
\drhead Endpoint & Band & Action \\
|
||||
\midrule
|
||||
\texttt{POST /api/tuner/tune} &
|
||||
DAB & \texttt{\{"band":"dab","freq\_index":0..37\}} \\
|
||||
DAB & \texttt{\{"band":"dab",}\\
|
||||
& & \texttt{"freq\_index":0..37\}} \\
|
||||
\texttt{POST /api/tuner/tune} &
|
||||
FM & \texttt{\{"band":"fm","frequency\_khz":64000..108000\}} \\
|
||||
FM & \texttt{\{"band":"fm",}\\
|
||||
& & \texttt{"frequency\_khz":64000..108000\}} \\
|
||||
\texttt{GET /api/tuner/services} & DAB only & Programme list for ensemble \\
|
||||
\texttt{POST /api/tuner/play} & DAB only & Start \texttt{service\_id}/\texttt{component\_id} \\
|
||||
\texttt{POST /api/tuner/seek} & FM only & Seek up/down, return new kHz \\
|
||||
|
||||
@@ -32,7 +32,7 @@ settings are collected in Table~\ref{tab:ss-hwcfg}.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead Setting & Value \\
|
||||
\midrule
|
||||
Control port (I\textsuperscript{2}C address) & 0x34 (ADDR0/ADDR1 = GND) \\
|
||||
@@ -57,7 +57,7 @@ matches the board GPIO map (Section~\ref{sec:hw-gpio}).
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead MP pin & Direction / function & Signal \\
|
||||
\midrule
|
||||
MP0 & Input Sdata\_in0 & audio from Si4684 (radio) \\
|
||||
@@ -107,7 +107,7 @@ digital outputs that feed the Bluetooth module.
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Stage & Block & Role \\
|
||||
\midrule
|
||||
Input & Input (ch. 2--5) & radio L/R, ESP32 L/R \\
|
||||
@@ -144,10 +144,11 @@ firmware.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lllll@{}}
|
||||
\footnotesize
|
||||
\begin{tabular}{@{}L{1.4cm}L{2.4cm}L{2.2cm}L{1.6cm}L{1.2cm}@{}}
|
||||
\drhead Band & Type & Frequency & Gain & Q \\
|
||||
\midrule
|
||||
1 & Butterworth High (high-pass) & 20\,Hz & --- & 1.41 \\
|
||||
1 & HP Butterworth & 20\,Hz & --- & 1.41 \\
|
||||
2 & Peaking & 100\,Hz & 0\,dB & 1.0 \\
|
||||
3 & Peaking & 400\,Hz & 0\,dB & 1.0 \\
|
||||
4 & Peaking & 1\,kHz & 0\,dB & 1.0 \\
|
||||
@@ -177,7 +178,7 @@ Table~\ref{tab:ss-lim}.
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
|
||||
\drhead Parameter & Value \\
|
||||
\midrule
|
||||
RMS TC & 50\,dB/s \\
|
||||
@@ -199,7 +200,7 @@ SigmaStudio export (Section~\ref{sec:ss-export}).
|
||||
|
||||
\begin{table}[htbp]
|
||||
\centering
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
|
||||
\drhead Control & Block & Runtime-adjustable \\
|
||||
\midrule
|
||||
Source levels (2) & Si4674 / ESP32 faders & yes \\
|
||||
|
||||
@@ -23,10 +23,16 @@
|
||||
\RequirePackage{titlesec}
|
||||
\RequirePackage{booktabs}
|
||||
\RequirePackage{array}
|
||||
\RequirePackage{ragged2e}
|
||||
\RequirePackage{tabularx}
|
||||
\RequirePackage{enumitem}
|
||||
\RequirePackage[most]{tcolorbox}
|
||||
\RequirePackage{graphicx}
|
||||
|
||||
% Wrapping column type for tables (use L{width} instead of l).
|
||||
\newcolumntype{L}[1]{>{\RaggedRight\arraybackslash}p{#1}}
|
||||
\setlength{\emergencystretch}{5em}
|
||||
|
||||
% ---------- Fonts (engine-aware) ---------------------------------------
|
||||
\ifPDFTeX
|
||||
\RequirePackage[T1]{fontenc}
|
||||
@@ -72,6 +78,7 @@
|
||||
\setlength{\parindent}{0pt}
|
||||
|
||||
% ---------- Links -------------------------------------------------------
|
||||
\RequirePackage{xurl}
|
||||
\RequirePackage{hyperref}
|
||||
\hypersetup{colorlinks=true, linkcolor=drPetrol, urlcolor=drAmber,
|
||||
citecolor=drTeal}
|
||||
@@ -119,6 +126,7 @@
|
||||
boxed title style={boxrule=0pt, arc=0.8mm,
|
||||
left=2.2mm, right=2.2mm, top=0.6mm, bottom=0.6mm},
|
||||
before skip=8pt, after skip=8pt,
|
||||
before upper={\RaggedRight},
|
||||
}}
|
||||
|
||||
\newtcolorbox{drnote}[1][Note]{dr@base,
|
||||
@@ -174,5 +182,12 @@
|
||||
}
|
||||
% inline code: \drcode|std::expected<T,E>|
|
||||
\newcommand{\code}[1]{{\ttfamily\color{drPetrol}#1}}
|
||||
% Breakable repo/file paths (use instead of long \texttt{...}).
|
||||
\newcommand{\drpath}[1]{\nolinkurl{#1}}
|
||||
% HTTP API subsection headings that wrap at slashes.
|
||||
\newcommand{\apiendpoint}[2]{%
|
||||
\subsection{\texorpdfstring{%
|
||||
{\raggedright\texttt{#1} \texttt{#2}\par}}{#1 #2}}%
|
||||
}
|
||||
|
||||
\endinput
|
||||
|
||||
Reference in New Issue
Block a user