Firmware review pass: BT1035 boot retry, BluetoothJson tests, doc catch-up
BT1035Driver::boot() had zero retry on the reset+AT-init sequence — a
single hardware RESET# pulse followed immediately by AT commands,
with no second attempt if the module didn't come up in time. This is
the most plausible explanation for the intermittent "no spontaneous
UART bytes after hardware reset" / "AT init failed" boot failures
logged in docs/si4684-rf-investigation-report.md and observed again
live this morning on otherwise-identical hardware/wiring — classic
power-up timing jitter, not a permanent fault. Extracted the reset+
init sequence into resetAndInitOnce() and wrapped it in a 3-attempt
retry loop with a short delay between attempts; the one-time GPIO
config and UART driver install stay outside the loop since they don't
need repeating. Root cause of the underlying jitter is still open.
BluetoothJson.hpp was the only *Json.hpp module in the core with zero
host test coverage (status/scan/paired serialisation, auto-reconnect/
connect/speaker parsing) — every sibling module already has one.
Added bluetooth_json_test.cpp following the existing tuner_json_test
pattern; ctest now covers 20 suites instead of 19.
Documentation catch-up, found doing a full firmware re-review at the
user's request:
- POST /api/tuner/calibrate-antenna and the antcap field on
POST /api/tuner/tune (added in a previous commit, never documented)
are now in ch-api.tex.
- kFirmwareVersion was still hardcoded "0.8.5" despite the RF fixes,
BLE provisioning, phone streaming, antenna calibration, and generic
DSP param API landed since that version's actual release commit
(0a1188a). Bumped to 0.9.0 everywhere it's mentioned (health JSON,
the manual's title page, intro, classes, and API chapters).
- instructions.md and docs/TODO.md still described the firmware as
frozen at 0.8.5 awaiting hardware-in-the-loop testing that has since
happened extensively; docs/TODO.md's H5 verdict specifically still
said "suspect U6 RF ground (re-open PCBWay)" for a bug that turned
out to be firmware, not hardware — actively misleading, corrected.
Both files now summarise the post-0.8.5 HIL findings and current
open items (BT1035 root cause, intermittent HTTP unresponsiveness
under load, antenna-limited signal quality, possibly-undersized 24 KB
nvs partition).
Verified: idf.py build, doxygen (0 warnings), check-manual-sync,
check_si4684_blobs, ctest (20/20), two-pass xelatex manual build all
green. Flashed and confirmed live: fw reports 0.9.0, BT1035 booted on
the first attempt post-flash.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR
This commit is contained in:
+43
-7
@@ -3,9 +3,13 @@
|
||||
Agent task list and hardware-in-the-loop backlog. Working directory for all
|
||||
commands is `Software/`.
|
||||
|
||||
**Current firmware:** `0.8.5` — BT1035 I2S slave boot init, dual OTA + DSP blob updates, EEPROM identity,
|
||||
NVS + flash encryption (dev mode), tabbed Web UI with System uploads, CI gate
|
||||
(4 jobs).
|
||||
**Current firmware:** `0.9.0` — everything in 0.8.5, plus: Si4684 RF
|
||||
blackout root-caused and fixed (real FM/DAB lock and audio on real
|
||||
hardware), DAB service list fixed (two rounds), FM ANTCAP antenna
|
||||
calibration persisted to EEPROM, generic ADAU1701 parameter API, phone PCM
|
||||
streaming, BLE Wi-Fi provisioning, full FM band scan, BT1035 boot retry.
|
||||
See "Post-0.8.5 hardware-in-the-loop findings" below and
|
||||
`docs/si4684-rf-investigation-report.md` for the full story.
|
||||
|
||||
**Before writing code, read `AGENTS.md`, `.cursor/rules/`, and
|
||||
`instructions.md`.** Definition of Done: Apache header, doc blocks,
|
||||
@@ -62,10 +66,42 @@ verify ADAU replay after reboot.
|
||||
After H1 passes, trial build with `sdkconfig.defaults.production` overlay on
|
||||
a sacrificial unit; confirm RELEASE mode policy before shipping.
|
||||
|
||||
### H5. Si4684 FM/DAB no-lock — blob integrity checked, verdict: hardware
|
||||
**Verdict (2026-08-13): blob OK → suspect U6 RF ground (re-open PCBWay)**, not
|
||||
a firmware/blob defect. Full investigation, evidence, and the two byte-offset
|
||||
bugs found/fixed while verifying this: [`docs/si4684-rf-investigation-report.md`](si4684-rf-investigation-report.md).
|
||||
### H5. Si4684 FM/DAB no-lock — RESOLVED, was firmware after all
|
||||
**Superseded verdict (2026-08-13): blob OK → suspected U6 RF ground, PCBWay
|
||||
dispute opened.** That verdict was wrong. The actual cause was
|
||||
`writeCommand()`'s ARG1 byte being mis-offset across FM/DAB tune, seek, and
|
||||
several status/ack commands — the chip always answered correctly, so every
|
||||
signal pointed at hardware, but it never actually tuned. Fixed; real FM
|
||||
lock, real DAB ensemble lock, real audio confirmed live on the same board.
|
||||
No PCB rework was needed. Full investigation, the wrong initial verdict,
|
||||
and the eventual root cause: [`docs/si4684-rf-investigation-report.md`](si4684-rf-investigation-report.md).
|
||||
|
||||
---
|
||||
|
||||
## Post-0.8.5 hardware-in-the-loop findings
|
||||
|
||||
The board arrived and testing against it (not just host tests) found real
|
||||
bugs the host-testable core couldn't catch, since they live in
|
||||
ESP-IDF-only drivers. Full detail and evidence in
|
||||
[`docs/si4684-rf-investigation-report.md`](si4684-rf-investigation-report.md).
|
||||
Short version:
|
||||
|
||||
- Si4684 total RF blackout (H5 above) — firmware bug, fixed.
|
||||
- Si4684→ADAU1701 digital audio silence — `PIN_CONFIG_ENABLE` mutual
|
||||
exclusion + `SerialInputRegister` polarity, fixed.
|
||||
- DAB service list empty/garbled — response-parsing offset bugs (two
|
||||
rounds) plus `DAB_EVENT_INTERRUPT_SOURCE` (0xB300) never configured,
|
||||
fixed.
|
||||
- FM front-end auto-tune measurably suboptimal on this board's actual
|
||||
matching network — ANTCAP calibration swept and persisted to EEPROM,
|
||||
`POST /api/tuner/calibrate-antenna`.
|
||||
- BT1035 intermittent boot failure — root cause still unknown, but a
|
||||
reset+init retry loop (up to 3 attempts) was added since the failure
|
||||
looked like power-up timing jitter, not a permanent fault.
|
||||
- **Still open**: BT1035 root cause; intermittent multi-second HTTP
|
||||
unresponsiveness under load; DAB signal quality still antenna-limited;
|
||||
24 KB `nvs` partition may be undersized (`saveProfile()` `store_failed`
|
||||
seen intermittently, error code never captured).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ implemented in \texttt{SetupWebServer}. Request bodies are parsed into
|
||||
domain types in the pure core (\texttt{components/core}) before any
|
||||
persistence or driver call. Exact C++ signatures live in the generated
|
||||
Doxygen output under \texttt{docs/api/}; this chapter documents the
|
||||
wire protocol and behaviour as shipped in firmware~0.8.5.
|
||||
wire protocol and behaviour as shipped in firmware~0.9.0.
|
||||
|
||||
\section{Transport and reachability}
|
||||
|
||||
@@ -36,7 +36,7 @@ Returns a health-check DTO serialised by
|
||||
|
||||
\begin{drnote}[Response schema]
|
||||
\begin{drcode}[JSON]
|
||||
{"status":"ok","fw":"0.8.5","serialNumber":"0004A3123456",
|
||||
{"status":"ok","fw":"0.9.0","serialNumber":"0004A3123456",
|
||||
"chips":{"si4684":true,"adau1701":true,"bt1035":true}}
|
||||
\end{drcode}
|
||||
\begin{itemize}
|
||||
@@ -172,7 +172,13 @@ or
|
||||
{"band":"fm","frequency_khz":101500}
|
||||
\end{drcode}
|
||||
DAB \texttt{freq\_index} is 0--37; FM \texttt{frequency\_khz} is
|
||||
64\,000--108\,000.
|
||||
64\,000--108\,000. FM accepts an optional \texttt{antcap} (0--128):
|
||||
overrides the front-end antenna varactor for this one tune, e.g. while
|
||||
running a calibration sweep. Omit it (the normal case) to use the board's
|
||||
saved calibration --- see
|
||||
\texttt{POST /api/tuner/calibrate-antenna}
|
||||
(Section~\ref{sec:api-tuner-calibrate-antenna}) --- or hardware auto-tune
|
||||
if never calibrated. Ignored for \texttt{"dab"}.
|
||||
\end{drnote}
|
||||
|
||||
On success returns the updated status JSON (same shape as
|
||||
@@ -267,6 +273,33 @@ per-station poll budget ran out.
|
||||
HTTP status: \textbf{200 OK}; \textbf{409} on a hardware/driver failure
|
||||
mid-sweep; \textbf{503} when the tuner service is unavailable.
|
||||
|
||||
\apiendpoint{POST}{/api/tuner/calibrate-antenna}
|
||||
\label{sec:api-tuner-calibrate-antenna}
|
||||
|
||||
Commits an FM ANTCAP value (AN851 Appendix A front-end calibration) as the
|
||||
board's permanent default, found by sweeping \texttt{antcap} on
|
||||
\texttt{POST /api/tuner/tune} (Section~\ref{sec:api-tuner-tune}) across
|
||||
0--128 and comparing \texttt{rssi\_dbuv}/\texttt{snr\_db}. Persists to the
|
||||
24AA025E48 EEPROM's user-writable region (separate from the factory-locked
|
||||
EUI-48) and takes effect immediately on the live tuner --- no reboot
|
||||
required, though it also survives one since \texttt{HardwareBootstrap::boot()}
|
||||
reloads it at every boot. Once saved, every ordinary FM tune (seek, scan,
|
||||
station recall, live UI) uses this value automatically instead of the
|
||||
chip's own front-end auto-tune, unless a request explicitly overrides
|
||||
\texttt{antcap} for that one call.
|
||||
|
||||
\begin{drnote}[Request schema]
|
||||
\begin{drcode}[JSON]
|
||||
{"antcap":102}
|
||||
\end{drcode}
|
||||
\texttt{antcap} is required, 0--128.
|
||||
\end{drnote}
|
||||
|
||||
Success response: \texttt{\{"status":"saved","antcap":102\}}. HTTP status:
|
||||
\textbf{200 OK}; \textbf{400} for invalid/missing \texttt{antcap};
|
||||
\textbf{500} on an EEPROM write failure; \textbf{503} when the tuner
|
||||
service is unavailable.
|
||||
|
||||
\apiendpoint{GET}{/api/audio/profile}
|
||||
\label{sec:api-audio-profile-get}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ added in the same change that introduces the class. A tooling check keeps
|
||||
this chapter in step with the code, so it is always current.
|
||||
\end{drnote}
|
||||
|
||||
The class reference tracks firmware~0.8.5 on \texttt{main}. Public classes
|
||||
The class reference tracks firmware~0.9.0 on \texttt{main}. Public classes
|
||||
are grouped by layer: domain core, application services, and hardware drivers.
|
||||
|
||||
% ------------------------------------------------------------------
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
DigiRadio is an open-source, high-fidelity digital radio receiver. It
|
||||
receives DAB+ and FM broadcasts, processes the audio through a dedicated
|
||||
signal processor, and streams the result over Bluetooth using a
|
||||
high-resolution codec. Firmware~0.8.5 on \texttt{main} provides encrypted
|
||||
high-resolution codec. Firmware~0.9.0 on \texttt{main} provides encrypted
|
||||
storage, a tabbed configuration web UI, and the full REST API documented
|
||||
in Chapter~\ref{ch:api}. The whole project --- hardware and firmware --- is
|
||||
released as open source for the maker and audio community to study,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
\vfill
|
||||
{\color{drInk}\large Michele Bigi\par}
|
||||
\vspace{2mm}
|
||||
{\color{drGray}Firmware 0.8.5 \quad\textbullet\quad 2026\par}
|
||||
{\color{drGray}Firmware 0.9.0 \quad\textbullet\quad 2026\par}
|
||||
\vspace{2mm}
|
||||
{\color{drGray}Hardware: CERN-OHL-S v2 \quad\textbullet\quad Firmware: Apache-2.0\par}
|
||||
\vspace{2mm}
|
||||
|
||||
Reference in New Issue
Block a user