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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}llp{6.5cm}@{}} \begin{tabular}{@{}L{3.8cm}L{3.5cm}L{6.2cm}@{}}
\toprule \toprule
\textbf{File} & \textbf{Role} & \textbf{Used by firmware} \\ \textbf{File} & \textbf{Role} & \textbf{Used by firmware} \\
\midrule \midrule
@@ -151,7 +151,7 @@ separates concerns as follows:
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}llp{5.8cm}@{}} \begin{tabular}{@{}L{2.5cm}L{3.8cm}L{6.2cm}@{}}
\drhead Layer & Type & Responsibility \\ \drhead Layer & Type & Responsibility \\
\midrule \midrule
HTTP / UI & \texttt{SetupWebServer}, web UI & HTTP / UI & \texttt{SetupWebServer}, web UI &
@@ -189,7 +189,7 @@ successful \texttt{boot()}.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Method} & \textbf{Purpose} \\ \textbf{Method} & \textbf{Purpose} \\
\midrule \midrule
@@ -205,7 +205,7 @@ successful \texttt{boot()}.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Method} & \textbf{Purpose} \\ \textbf{Method} & \textbf{Purpose} \\
\midrule \midrule
@@ -237,7 +237,7 @@ runtime-adjustable, matching Table~\ref{tab:ss-runtime}.
\subsection{Gain and EQ coefficient path} \subsection{Gain and EQ coefficient path}
Volume cells (faders, master) store linear gain as ADAU \textbf{8.23 fixpoint}. 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()}. \texttt{sigma\_safeload\_param()}.
PEQ bands use \texttt{core::designPeakingEq()} at 48\,kHz sample rate to 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] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
\drhead Domain & \texttt{ADDR\_*} & SigmaStudio block \\ \drhead Domain & \texttt{ADDR\_*} & SigmaStudio block \\
\midrule \midrule
Si4684 L/R & \texttt{SI4674}, \texttt{SI4674\_1} & Si4674 fader \\ Si4684 L/R & \texttt{SI4674}, \texttt{SI4674\_1} & Si4674 fader \\
ESP32 L/R & \texttt{ESP32}, \texttt{ESP32\_1} & ESP32 fader \\ ESP32 L/R & \texttt{ESP32}, \texttt{ESP32\_1} & ESP32 fader \\
Mix L/R & \texttt{STMIXER1\_ST0/1\_VOLUME} & St Mixer1 \\ Mix L/R & {\footnotesize\texttt{STMIXER1\_ST0/1\_VOLUME}} & St Mixer1 \\
EQ band $n$ & \texttt{PARAMEQ1\_ST$n$\_B0} + 0..4 & Param EQ1 coeffs \\ EQ band $n$ & {\footnotesize\texttt{PARAMEQ1\_ST$n$\_B0} + 0..4} & Param EQ1 coeffs \\
Master L/R & \texttt{MULTIPLE1}, \texttt{MULTIPLE1\_1} & Multiple 1 \\ Master L/R & \texttt{MULTIPLE1}, \texttt{MULTIPLE1\_1} & Multiple 1 \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
@@ -335,7 +335,7 @@ use for audio path control:
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Method} & \textbf{Effect} \\ \textbf{Method} & \textbf{Effect} \\
\midrule \midrule
@@ -423,7 +423,7 @@ only if band indices and centre frequencies still match; otherwise reset via
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead Error & Typical cause \\ \drhead Error & Typical cause \\
\midrule \midrule
\texttt{ResetFailed} & GPIO reset line configuration \\ \texttt{ResetFailed} & GPIO reset line configuration \\
+40 -39
View File
@@ -27,7 +27,7 @@ All responses use \texttt{Content-Type: application/json} except
\section{Endpoints} \section{Endpoints}
\subsection{\texttt{GET /api/health}} \apiendpoint{GET}{/api/health}
\label{sec:api-health} \label{sec:api-health}
Returns a health-check DTO serialised by 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. HTTP status: \textbf{200 OK} on success.
\subsection{\texttt{POST /api/wifi}} \apiendpoint{POST}{/api/wifi}
\label{sec:api-wifi} \label{sec:api-wifi}
Accepts Wi-Fi credentials for station (STA) join. The body is parsed by 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] \begin{drcode}[JSON]
{"status":"error","reason":"invalid_ssid"} {"status":"error","reason":"invalid_ssid"}
\end{drcode} \end{drcode}
Serialised by \texttt{core::serializeWifiProvisionErrorJson()}. Reason Serialised by \texttt{core::serializeWifiProvisionErrorJson()}. Reason tokens (never include secrets):
tokens (never include secrets): \texttt{invalid\_json}, \texttt{invalid\_json}, \texttt{missing\_field}, \texttt{invalid\_ssid},
\texttt{missing\_field}, \texttt{invalid\_ssid}, \texttt{invalid\_password}, \texttt{invalid\_password}, \texttt{store\_failed}.
\texttt{store\_failed}.
\end{drnote} \end{drnote}
HTTP status: \textbf{200 OK} on save success; \textbf{400 Bad Request} for HTTP status: \textbf{200 OK} on save success; \textbf{400 Bad Request} for
parse/validation failures; \textbf{500 Internal Server Error} when NVS parse/validation failures; \textbf{500 Internal Server Error} when NVS
persistence fails. persistence fails.
\subsection{\texttt{GET /api/tuner/status}} \apiendpoint{GET}{/api/tuner/status}
\label{sec:api-tuner-status} \label{sec:api-tuner-status}
Returns a tuner snapshot serialised by Returns a tuner snapshot serialised by
@@ -111,8 +110,9 @@ and~\ref{sec:si4684-fm-session}.
\begin{drcode}[JSON] \begin{drcode}[JSON]
{"booted":true,"band":"dab","locked":true,"volume":63, {"booted":true,"band":"dab","locked":true,"volume":63,
"dab":{"freq_index":12,"fic_quality":80,"cnr_db":25, "dab":{"freq_index":12,"fic_quality":80,"cnr_db":25,
"playing_service_id":42,"playing_component_id":7, "playing_service_id":42,"playing_component_id":7,
"dynamic_label":"Live show"},"fm":null} "dynamic_label":"Live show"},
"fm":null}
\end{drcode} \end{drcode}
For FM, \texttt{fm} carries \texttt{frequency\_khz}, \texttt{rssi\_dbuv}, For FM, \texttt{fm} carries \texttt{frequency\_khz}, \texttt{rssi\_dbuv},
\texttt{snr\_db}, \texttt{stereo}, optional \texttt{station\_name} (RDS PS), \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{station\_name} and \texttt{radiotext}; DAB responses may include
\texttt{dynamic\_label} when a programme is playing. \texttt{dynamic\_label} when a programme is playing.
\subsection{\texttt{GET /api/tuner/services}} \apiendpoint{GET}{/api/tuner/services}
\label{sec:api-tuner-services} \label{sec:api-tuner-services}
Lists DAB programmes for the current ensemble via 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 HTTP status: \textbf{200 OK}; \textbf{409 Conflict} when the list cannot be
fetched (wrong band, empty ensemble, hardware error). fetched (wrong band, empty ensemble, hardware error).
\subsection{\texttt{POST /api/tuner/tune}} \apiendpoint{POST}{/api/tuner/tune}
\label{sec:api-tuner-tune} \label{sec:api-tuner-tune}
Tunes to a DAB ensemble or FM frequency. Body parsed by 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}; \texttt{GET /api/tuner/status}). HTTP status: \textbf{200 OK};
\textbf{400} for invalid JSON; \textbf{409} for tune failures. \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} \label{sec:api-tuner-play}
Starts a DAB audio service. Body parsed by 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: Success response: \texttt{\{"status":"playing"\}}. HTTP status:
\textbf{200 OK}; \textbf{409} when playback cannot start. \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} \label{sec:api-tuner-seek}
Seeks FM in the requested direction. Optional JSON body parsed by 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). object (\texttt{\{\}}) for upward seek (backward compatible).
\end{drnote} \end{drnote}
\subsection{\texttt{GET /api/audio/profile}} \apiendpoint{GET}{/api/audio/profile}
\label{sec:api-audio-profile-get} \label{sec:api-audio-profile-get}
Returns the current ADAU1701 audio snapshot serialised by Returns the current ADAU1701 audio snapshot serialised by
@@ -205,8 +205,9 @@ Chapter~\ref{ch:adau1701}.
\begin{drnote}[Response schema (excerpt)] \begin{drnote}[Response schema (excerpt)]
\begin{drcode}[JSON] \begin{drcode}[JSON]
{"mixer":{"si4684_left_db":0,"si4684_right_db":0,"esp32_left_db":0, {"mixer":{"si4684_left_db":0,"si4684_right_db":0,
"esp32_right_db":0,"mix_left_db":0,"mix_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}, "master":{"left_db":0,"right_db":0},
"eq":[{"gain_db":0,"center_hz":40,"q":1.414}, ...], "eq":[{"gain_db":0,"center_hz":40,"q":1.414}, ...],
"enhancements":{"stereo_level":0,"bass_level":0}} "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 HTTP status: \textbf{200 OK}; \textbf{503} when the audio service is
unavailable. unavailable.
\subsection{\texttt{PUT /api/audio/profile}} \apiendpoint{PUT}{/api/audio/profile}
\label{sec:api-audio-profile-put} \label{sec:api-audio-profile-put}
Applies a full audio profile. Body parsed by 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; HTTP status: \textbf{200 OK}; \textbf{400} for parse/validation failures;
\textbf{500} when safeload or NVS persistence fails. \textbf{500} when safeload or NVS persistence fails.
\subsection{\texttt{POST /api/dsp/program}} \apiendpoint{POST}{/api/dsp/program}
\label{sec:api-dsp-program} \label{sec:api-dsp-program}
Uploads a framed ADAU1701 RAM download blob (\texttt{DRAD} v1, see 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 200\,KiB; \textbf{500} on flash write failure. Pack blobs with
\texttt{tools/pack\_dsp\_program.py} or \texttt{core::serializeDspProgramBlob()}. \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} \label{sec:api-system-ota}
Streams a raw ESP-IDF application \texttt{.bin} into the inactive OTA slot 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 \textbf{500} on \texttt{esp\_ota\_end}/set-boot failures. Push with
\texttt{curl --data-binary @build/digiradio.bin}. \texttt{curl --data-binary @build/digiradio.bin}.
\subsection{\texttt{POST /api/audio/reset}} \apiendpoint{POST}{/api/audio/reset}
\label{sec:api-audio-reset} \label{sec:api-audio-reset}
Restores \texttt{AudioProfile::factoryDefault()} (flat EQ, 0\,dB gains), 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} \texttt{\{"status":"saved"\}}. HTTP status: \textbf{200 OK}; \textbf{500}
on apply/persist failure. on apply/persist failure.
\subsection{\texttt{POST /api/audio/stereo-enhance}} \apiendpoint{POST}{/api/audio/stereo-enhance}
\label{sec:api-audio-stereo-enhance} \label{sec:api-audio-stereo-enhance}
Adjusts stereo depth via a psychoacoustic PEQ overlay on bands 3--5 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} \textbf{200 OK}; \textbf{400} for invalid JSON or level; \textbf{500}
when safeload or NVS persistence fails. 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} \label{sec:api-audio-bass-enhance}
Adjusts bass emphasis via a PEQ overlay on bands 1--2 (100\,Hz / 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) % Bluetooth (Slice 7)
% ------------------------------------------------------------------ % ------------------------------------------------------------------
\subsection{\texttt{GET /api/bluetooth/status}} \apiendpoint{GET}{/api/bluetooth/status}
\label{sec:api-bluetooth-status} \label{sec:api-bluetooth-status}
Returns BT1035 boot flag, whether discoverable mode was requested, the Returns BT1035 boot flag, whether discoverable mode was requested, the
@@ -330,24 +331,24 @@ Serialised by \texttt{core::serializeBluetoothStatusJson()}.
\end{drcode} \end{drcode}
\end{drnote} \end{drnote}
\subsection{\texttt{POST /api/bluetooth/pair}} \apiendpoint{POST}{/api/bluetooth/pair}
\label{sec:api-bluetooth-pair} \label{sec:api-bluetooth-pair}
Enters discoverable mode (\texttt{AT+PAIR=1}). Success: Enters discoverable mode (\texttt{AT+PAIR=1}). Success:
\texttt{\{"status":"pairing"\}}. \texttt{\{"status":"pairing"\}}.
\subsection{\texttt{POST /api/bluetooth/pair/stop}} \apiendpoint{POST}{/api/bluetooth/pair/stop}
\label{sec:api-bluetooth-pair-stop} \label{sec:api-bluetooth-pair-stop}
Leaves discoverable mode (\texttt{AT+PAIR=0}). Success: Leaves discoverable mode (\texttt{AT+PAIR=0}). Success:
\texttt{\{"status":"idle"\}}. \texttt{\{"status":"idle"\}}.
\subsection{\texttt{POST /api/bluetooth/disconnect}} \apiendpoint{POST}{/api/bluetooth/disconnect}
\label{sec:api-bluetooth-disconnect} \label{sec:api-bluetooth-disconnect}
Releases the current A2DP session (\texttt{AT+A2DPDISC}). Releases the current A2DP session (\texttt{AT+A2DPDISC}).
\subsection{\texttt{GET /api/bluetooth/paired}} \apiendpoint{GET}{/api/bluetooth/paired}
\label{sec:api-bluetooth-paired} \label{sec:api-bluetooth-paired}
Returns paired remotes from \texttt{AT+PLIST}, serialised by 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{drcode}
\end{drnote} \end{drnote}
\subsection{\texttt{POST /api/bluetooth/auto-reconnect}} \apiendpoint{POST}{/api/bluetooth/auto-reconnect}
\label{sec:api-bluetooth-auto-reconnect} \label{sec:api-bluetooth-auto-reconnect}
Sets the module auto-reconnect retry count (\texttt{AT+AUTOCONN=0..15}). Sets the module auto-reconnect retry count (\texttt{AT+AUTOCONN=0..15}).
@@ -376,29 +377,29 @@ Success: \texttt{\{"status":"saved"\}}.
% Station presets (Slice 4) % Station presets (Slice 4)
% ------------------------------------------------------------------ % ------------------------------------------------------------------
\subsection{\texttt{GET /api/stations}} \apiendpoint{GET}{/api/stations}
\label{sec:api-stations-get} \label{sec:api-stations-get}
Returns presets serialised by \texttt{core::serializeStationListJson()}. Returns presets serialised by \texttt{core::serializeStationListJson()}.
\subsection{\texttt{POST /api/stations}} \apiendpoint{POST}{/api/stations}
\label{sec:api-stations-post} \label{sec:api-stations-post}
Adds one preset (\texttt{core::parseStationJson()}); persists via Adds one preset (\texttt{core::parseStationJson()}); persists via
\texttt{ISecureStore::saveStationListJson()}. \texttt{ISecureStore::saveStationListJson()}.
\subsection{\texttt{POST /api/stations/remove}} \apiendpoint{POST}{/api/stations/remove}
\label{sec:api-stations-remove} \label{sec:api-stations-remove}
Removes a preset by list index (\texttt{\{"index":0\}}). 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} \label{sec:api-stations-reorder}
Reorders presets using \texttt{StationList::move()}. Body: Reorders presets using \texttt{StationList::move()}. Body:
\texttt{\{"from":1,"to":0\}}. Success: \texttt{\{"status":"reordered"\}}. \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} \label{sec:api-stations-tune}
Recalls a preset via \texttt{integration::IntegrationService::recallPreset()} 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. \texttt{core::Secret} in RAM and are never logged or returned by the API.
\begin{drcaution}[Encryption at rest] \begin{drcaution}[Encryption at rest]
Firmware~0.8.3+ enables NVS encryption (\texttt{CONFIG\_NVS\_ENCRYPTION}) and Firmware~0.8.3+ enables NVS encryption
flash encryption in development mode (\texttt{sdkconfig.defaults}). Keys live in (\texttt{CONFIG\_NVS\_ENCRYPTION}) and flash encryption in development mode
the \texttt{nvs\_keys} partition; Wi-Fi passwords remain wrapped in (\texttt{sdkconfig.defaults}). Keys live in the \texttt{nvs\_keys} partition;
\texttt{core::Secret} in RAM and are never logged. First upgrade from plain NVS Wi-Fi passwords remain wrapped in \texttt{core::Secret} in RAM and are never
requires \texttt{idf.py erase-flash}. HIL checklist: logged. First upgrade from plain NVS requires \texttt{idf.py erase-flash}.
\texttt{Software/docs/security-flash-nvs.md}. HIL checklist: \drpath{Software/docs/security-flash-nvs.md}.
\end{drcaution} \end{drcaution}
+16 -12
View File
@@ -41,7 +41,8 @@ output (Section~\ref{sec:bt1035-i2s}).
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \small
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead Setting & Value \\ \drhead Setting & Value \\
\midrule \midrule
Port & UART2 (not the console UART) \\ 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). \item treats timeouts and unexpected payloads as errors (never ignored).
\end{itemize} \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. init sequence (\texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67}) and the parser.
\section{Mandatory I\textsuperscript{2}S slave mode} \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] \begin{drcaution}[I\textsuperscript{2}S init is not optional]
The board routes ADAU1701 \texttt{SDATA\_OUT0} (MP6) to the module PCM input 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 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 must use:
programming guide §5.1.25) followed by \texttt{AT+I2SCFG=67} (I\textsuperscript{2}S \begin{itemize}
slave, 48\,kHz, 32-bit per §5.1.4). \texttt{AT+AUXCFG=1} (Line-In) does \item \texttt{AT+AUXCFG=3} --- I\textsuperscript{2}S mode (§5.1.25)
\textbf{not} match the schematic. AGENTS.md treats skipping I\textsuperscript{2}S \item \texttt{AT+I2SCFG=67} --- I\textsuperscript{2}S slave, 48\,kHz, 32-bit (§5.1.4)
init as a production bug. \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} \end{drcaution}
\section{Boot sequence} \section{Boot sequence}
@@ -125,7 +128,7 @@ only the I\textsuperscript{2}S bring-up required for the wired audio path.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}llp{5.8cm}@{}} \begin{tabular}{@{}L{2.5cm}L{3.8cm}L{6.2cm}@{}}
\drhead Layer & Type & Responsibility \\ \drhead Layer & Type & Responsibility \\
\midrule \midrule
Bootstrap & \texttt{HardwareBootstrap} & 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} \label{sec:bt1035-at}
The firmware enumerates every command it sends. Wire formats follow 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 (§5 commands, §6 events). Extending the subset requires updating
\texttt{core::Bt1035AtCommand}, the manual, and a host test. \texttt{core::Bt1035AtCommand}, the manual, and a host test.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}llp{5.2cm}@{}} \begin{tabular}{@{}L{2.4cm}L{3.4cm}L{5.5cm}@{}}
\drhead Enum & Line sent & Programming guide \\ \drhead Enum & Line sent & Programming guide \\
\midrule \midrule
\texttt{Ping} & \texttt{AT} & link check \\ \texttt{Ping} & \texttt{AT} & link check \\
@@ -184,7 +187,8 @@ reconnect count).
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \small
\begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Method} & \textbf{Purpose} \\ \textbf{Method} & \textbf{Purpose} \\
\midrule \midrule
@@ -210,7 +214,7 @@ reconnect count).
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead \texttt{Bt1035Error} & Typical cause \\ \drhead \texttt{Bt1035Error} & Typical cause \\
\midrule \midrule
\texttt{ResetFailed} & GPIO configuration failure \\ \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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead Item & Choice \\ \drhead Item & Choice \\
\midrule \midrule
Framework & ESP-IDF v5.5.x (native) \\ 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. configured SoftAP. Imperative shell; no business logic.
\section{SetupWebServer}\label{cls:SetupWebServer} \section{SetupWebServer}\label{cls:SetupWebServer}
Minimal HTTP server: gzipped setup UI, \texttt{GET /api/health}, Minimal HTTP server: gzipped setup UI and typed JSON REST handlers:
\texttt{POST /api/wifi}, tuner routes (\texttt{/api/tuner/*}), audio \begin{itemize}
routes (\texttt{/api/audio/*}), Bluetooth (\texttt{/api/bluetooth/*}), and \item \texttt{GET /api/health}, \texttt{POST /api/wifi}
station presets (\texttt{/api/stations/*}). JSON parsing and serialisation \item Tuner: \texttt{/api/tuner/*}
delegate to the pure core; credentials persist via \texttt{ISecureStore}; \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 tuner via \texttt{tuner::TunerService}; audio via
\texttt{audio::AudioService}; Bluetooth via \texttt{bluetooth::BluetoothService}; \texttt{audio::AudioService}; Bluetooth via \texttt{bluetooth::BluetoothService};
presets via \texttt{station::StationService}. presets via \texttt{station::StationService}.
+1 -1
View File
@@ -240,7 +240,7 @@ disabled.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Item} & \textbf{Choice} \\ \textbf{Item} & \textbf{Choice} \\
\midrule \midrule
+29 -27
View File
@@ -36,7 +36,8 @@ interface.
\begin{table}[htbp] \begin{table}[htbp]
\centering \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 \\ \drhead Device & Role & Control bus & Firmware \\
\midrule \midrule
Si4684 & DAB+/FM tuner & SPI & host-loaded image \\ 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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Bus & Devices & Purpose \\ \drhead Bus & Devices & Purpose \\
\midrule \midrule
SPI & Si4684 & fast firmware-image upload, tuner control \\ 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} \subsection{System and control lines}
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Signal & ESP32-S3 GPIO & Notes \\ \drhead Signal & ESP32-S3 GPIO & Notes \\
\midrule \midrule
USB D$-$ & GPIO19 & native USB \\ USB D$-$ & GPIO19 & native USB \\
@@ -207,7 +208,8 @@ and the companion chips. The firmware pin definitions
\subsection{Si4684 tuner (SPI)} \subsection{Si4684 tuner (SPI)}
\begin{table}[htbp] \begin{table}[htbp]
\centering \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 \\ \drhead Signal & Si4684 pin & ESP32-S3 GPIO & Notes \\
\midrule \midrule
SCLK & pin 30 & GPIO13 & \\ SCLK & pin 30 & GPIO13 & \\
@@ -225,7 +227,7 @@ and the companion chips. The firmware pin definitions
\subsection{ADAU1701 DSP (I\textsuperscript{2}C)} \subsection{ADAU1701 DSP (I\textsuperscript{2}C)}
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Signal & ADAU1701 pin & ESP32-S3 GPIO \\ \drhead Signal & ADAU1701 pin & ESP32-S3 GPIO \\
\midrule \midrule
SDA & --- & GPIO4 \\ SDA & --- & GPIO4 \\
@@ -247,7 +249,7 @@ serial number. Its 7-bit address is 0x52 (A0 to GND, A1 to 3V3).
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Device & 7-bit address & Set by \\ \drhead Device & 7-bit address & Set by \\
\midrule \midrule
ADAU1701 & 0x34 & ADDR0, ADDR1 = GND \\ 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} \subsection{FSC-BT1035 Bluetooth}
\begin{table}[htbp] \begin{table}[htbp]
\centering \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 \\ \drhead Signal & BT1035 pin & ESP32-S3 GPIO & Direction \\
\midrule \midrule
SYS\_CTL & pin 34 & GPIO15 & ESP32 $\rightarrow$ BT \\ 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] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Signal & Path & ADAU1701 / BT1035 pins \\ \drhead Signal & Path & ADAU1701 / BT1035 pins \\
\midrule \midrule
SDATA\_IN0 & Si4684 $\rightarrow$ ADAU & MP0 (pin 11) \\ 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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Signal & ESP32-S3 GPIO & Direction \\ \drhead Signal & ESP32-S3 GPIO & Direction \\
\midrule \midrule
BCLK & GPIO6 & in from ADAU (master) \\ BCLK & GPIO6 & in from ADAU (master) \\
@@ -365,12 +368,13 @@ satisfying the +10\,\textmu s requirement in practice.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{3.2cm}L{8.2cm}L{2.2cm}@{}}
\drhead Check & Requirement (datasheet) & Status \\ \drhead Check & Requirement (datasheet) & Status \\
\midrule \midrule
RSTB low at power-up & held low until supplies stable +10\,\textmu s & verified (pull-down) \\ 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 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 \\ 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 \\ 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 \\ 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 \\ INTB & interrupt line, external pull-up (GPIO39) & verified \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
\caption{Si4684 design checks. References: \caption{Si4684 design checks (datasheet references below).}
\texttt{Hardware/DATASHEET/SI4684-A10.pdf} (power sequencing, SPI,
supply levels) and \texttt{Hardware/DATASHEET/AN851.pdf} (bypass and layout).}
\label{tab:hw-val-si4684} \label{tab:hw-val-si4684}
\end{table} \end{table}
\begin{drref}[Datasheet] \begin{drref}[Datasheet]
Power sequencing and SPI framing: Power sequencing and SPI framing: \drpath{Hardware/DATASHEET/SI4684-A10.pdf}.
\texttt{Hardware/DATASHEET/SI4684-A10.pdf}. The user must not pulse SSB high The user must not pulse SSB high between bytes; SSB frames the whole
between bytes; SSB frames the whole command/reply. command/reply. Bypass-capacitor values and placement:
Bypass-capacitor values and placement: \texttt{Hardware/DATASHEET/AN851.pdf}, \drpath{Hardware/DATASHEET/AN851.pdf}, \emph{Si468x Schematic and Layout
\emph{Si468x Schematic and Layout Guide}. Boot and command protocol: AN649. Guide}. Boot and command protocol: AN649. Local copies:
Local copies: \texttt{Hardware/DATASHEET/} (see \texttt{README.md}). \drpath{Hardware/DATASHEET/} (see \drpath{README.md}).
\end{drref} \end{drref}
The core, memory, and analogue rails run at 1.8\,V; only VIO is at 3.3\,V 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] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.2cm}L{3.6cm}L{7.2cm}@{}}
\drhead Check & Requirement (datasheet) & Status \\ \drhead Check & Requirement (datasheet) & Status \\
\midrule \midrule
Clock loopback & MP10$\rightarrow$MP4, MP11$\rightarrow$MP5 wired & verified \\ 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] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{3.5cm}L{7.5cm}L{2.5cm}@{}}
\drhead Check & Requirement & Status \\ \drhead Check & Requirement & Status \\
\midrule \midrule
UART with flow control & TX/RX + RTS/CTS wired & verified \\ 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 \\ I\textsuperscript{2}S input & receives clocks from ADAU master (slave) & verified \\
Reset line & RESET (GPIO17) driven by ESP32 & verified \\ Reset line & RESET (GPIO17) driven by ESP32 & verified \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
\caption{FSC-BT1035 design checks. Datasheet: \caption{FSC-BT1035 design checks (datasheets in \drpath{Hardware/DATASHEET/}).}
\texttt{Hardware/DATASHEET/FSC-BT1035\_Datasheet\_EN.pdf}; AT commands:
\texttt{FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf} §5.}
\label{tab:hw-val-bt1035} \label{tab:hw-val-bt1035}
\end{table} \end{table}
@@ -479,7 +480,8 @@ UART 115200/8/N/1, SSP on, auto-reconnect configurable via
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \small
\begin{tabular}{@{}L{2.2cm}L{4.8cm}L{6.6cm}@{}}
\drhead Area & Item & Status \\ \drhead Area & Item & Status \\
\midrule \midrule
Si4684 & RSTB pull-down, 1.8\,V rails, bypass caps, SPI & verified \\ 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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}llp{6.2cm}@{}} \footnotesize
\begin{tabular}{@{}L{3.2cm}L{2.2cm}L{8.2cm}@{}}
\toprule \toprule
\textbf{Local file} & \textbf{Typ.\ size} & \textbf{Source} \\ \textbf{Local file} & \textbf{Typ.\ size} & \textbf{Source} \\
\midrule \midrule
@@ -99,7 +100,8 @@ python3 tools/fetch_si4684_firmware.py \
--from-ugreen-radio-cli ~/Downloads/Files_v16.zip --ugreen-all --from-ugreen-radio-cli ~/Downloads/Files_v16.zip --ugreen-all
# FM from dabpi / Skyworks eval folder: # 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} \end{verbatim}
Low-level helpers: \texttt{tools/extract\_si4684\_blob.py} (C header or copy), Low-level helpers: \texttt{tools/extract\_si4684\_blob.py} (C header or copy),
@@ -167,7 +169,7 @@ versa for DAB.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\toprule \toprule
\textbf{Method} & \textbf{Purpose} \\ \textbf{Method} & \textbf{Purpose} \\
\midrule \midrule
@@ -284,7 +286,7 @@ selects the blob:
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
\drhead Band & Image loaded & Primary API \\ \drhead Band & Image loaded & Primary API \\
\midrule \midrule
\texttt{Si4684Band::Dab} & \texttt{dab\_firmware.bin} & \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] \begin{table}[htbp]
\centering \centering
\small \footnotesize
\begin{tabular}{@{}llp{5.5cm}@{}} \begin{tabular}{@{}L{2.8cm}L{1.6cm}L{8.2cm}@{}}
\drhead Endpoint & Band & Action \\ \drhead Endpoint & Band & Action \\
\midrule \midrule
\texttt{POST /api/tuner/tune} & \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} & \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{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/play} & DAB only & Start \texttt{service\_id}/\texttt{component\_id} \\
\texttt{POST /api/tuner/seek} & FM only & Seek up/down, return new kHz \\ \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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead Setting & Value \\ \drhead Setting & Value \\
\midrule \midrule
Control port (I\textsuperscript{2}C address) & 0x34 (ADDR0/ADDR1 = GND) \\ 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] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
\drhead MP pin & Direction / function & Signal \\ \drhead MP pin & Direction / function & Signal \\
\midrule \midrule
MP0 & Input Sdata\_in0 & audio from Si4684 (radio) \\ MP0 & Input Sdata\_in0 & audio from Si4684 (radio) \\
@@ -107,7 +107,7 @@ digital outputs that feed the Bluetooth module.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\small \small
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
\drhead Stage & Block & Role \\ \drhead Stage & Block & Role \\
\midrule \midrule
Input & Input (ch. 2--5) & radio L/R, ESP32 L/R \\ Input & Input (ch. 2--5) & radio L/R, ESP32 L/R \\
@@ -144,10 +144,11 @@ firmware.
\begin{table}[htbp] \begin{table}[htbp]
\centering \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 \\ \drhead Band & Type & Frequency & Gain & Q \\
\midrule \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 \\ 2 & Peaking & 100\,Hz & 0\,dB & 1.0 \\
3 & Peaking & 400\,Hz & 0\,dB & 1.0 \\ 3 & Peaking & 400\,Hz & 0\,dB & 1.0 \\
4 & Peaking & 1\,kHz & 0\,dB & 1.0 \\ 4 & Peaking & 1\,kHz & 0\,dB & 1.0 \\
@@ -177,7 +178,7 @@ Table~\ref{tab:ss-lim}.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}ll@{}} \begin{tabular}{@{}L{4.2cm}L{9.2cm}@{}}
\drhead Parameter & Value \\ \drhead Parameter & Value \\
\midrule \midrule
RMS TC & 50\,dB/s \\ RMS TC & 50\,dB/s \\
@@ -199,7 +200,7 @@ SigmaStudio export (Section~\ref{sec:ss-export}).
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \begin{tabular}{@{}L{2.4cm}L{3.6cm}L{7.2cm}@{}}
\drhead Control & Block & Runtime-adjustable \\ \drhead Control & Block & Runtime-adjustable \\
\midrule \midrule
Source levels (2) & Si4674 / ESP32 faders & yes \\ Source levels (2) & Si4674 / ESP32 faders & yes \\
+15
View File
@@ -23,10 +23,16 @@
\RequirePackage{titlesec} \RequirePackage{titlesec}
\RequirePackage{booktabs} \RequirePackage{booktabs}
\RequirePackage{array} \RequirePackage{array}
\RequirePackage{ragged2e}
\RequirePackage{tabularx}
\RequirePackage{enumitem} \RequirePackage{enumitem}
\RequirePackage[most]{tcolorbox} \RequirePackage[most]{tcolorbox}
\RequirePackage{graphicx} \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) --------------------------------------- % ---------- Fonts (engine-aware) ---------------------------------------
\ifPDFTeX \ifPDFTeX
\RequirePackage[T1]{fontenc} \RequirePackage[T1]{fontenc}
@@ -72,6 +78,7 @@
\setlength{\parindent}{0pt} \setlength{\parindent}{0pt}
% ---------- Links ------------------------------------------------------- % ---------- Links -------------------------------------------------------
\RequirePackage{xurl}
\RequirePackage{hyperref} \RequirePackage{hyperref}
\hypersetup{colorlinks=true, linkcolor=drPetrol, urlcolor=drAmber, \hypersetup{colorlinks=true, linkcolor=drPetrol, urlcolor=drAmber,
citecolor=drTeal} citecolor=drTeal}
@@ -119,6 +126,7 @@
boxed title style={boxrule=0pt, arc=0.8mm, boxed title style={boxrule=0pt, arc=0.8mm,
left=2.2mm, right=2.2mm, top=0.6mm, bottom=0.6mm}, left=2.2mm, right=2.2mm, top=0.6mm, bottom=0.6mm},
before skip=8pt, after skip=8pt, before skip=8pt, after skip=8pt,
before upper={\RaggedRight},
}} }}
\newtcolorbox{drnote}[1][Note]{dr@base, \newtcolorbox{drnote}[1][Note]{dr@base,
@@ -174,5 +182,12 @@
} }
% inline code: \drcode|std::expected<T,E>| % inline code: \drcode|std::expected<T,E>|
\newcommand{\code}[1]{{\ttfamily\color{drPetrol}#1}} \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 \endinput