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:
2026-07-08 15:02:30 +02:00
co-authored by Cursor
parent ad5e4827a8
commit fcda4ef151
10 changed files with 141 additions and 110 deletions
+10 -10
View File
@@ -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 \\
+39 -38
View File
@@ -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}
+16 -12
View File
@@ -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 \\
+1 -1
View File
@@ -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) \\
+9 -5
View File
@@ -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}.
+1 -1
View File
@@ -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
+29 -27
View File
@@ -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 \\
+12 -8
View File
@@ -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 \\
+8 -7
View File
@@ -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 \\
+15
View File
@@ -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