Si4684Driver::getPartInfo()/getSysState() existed but were never called, so their byte-offset bugs never surfaced. Wired them into a boot-time diagnostic log (part number, firmware revision, active image, streamed blob byte counts) to check whether the loaded DAB/FM firmware images are genuine and intact, as an alternative explanation to the QFN exposed-pad hardware hypothesis. Fixed two rounds of off-by-one bugs found while doing this: the fields were initially read one byte too far right (e.g. firmwareBuild was reading a flag byte, not a version number); the first fix undershot in the other direction by not accounting for readRaw()'s one-byte SPI lead-in before STATUS0 (already documented and confirmed elsewhere in this file, in pollStc()) -- caught because the "fixed" GET_SYS_STATE reported image=192 (0xC0), the exact signature of STATUS3 with PUP_STATE=3 seen throughout this investigation. All three response buffers were already sized for the lead-in byte, which confirmed the correct fix. Verdict, captured live: blob streamed bytes match local file sizes exactly (no truncation), GET_SYS_STATE reports image=2 (DAB active, correct), GET_PART_INFO reports part=4684 (matches expected Si4684 part number) with a plausible firmware revision -- the loaded DAB firmware is genuine and intact. This closes the last plausible firmware-side explanation for the FM/DAB no-lock symptom; docs/si4684-rf-investigation-report.md and docs/TODO.md (P4/H5) updated with the full record and verdict. Also noted, not yet fixed: BT1035 AT-init now fails deterministically on every boot (was a one-off earlier this session) -- see report's Open Items. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.3 KiB
TODO — DigiRadio firmware
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).
Before writing code, read AGENTS.md, .cursor/rules/, and
instructions.md. Definition of Done: Apache header, doc blocks,
doxygen Doxyfile exits 0, host tests pass, check-manual-sync.py and
check_si4684_blobs.py pass, no plaintext secrets.
Completed agent tasks (T1–T12, fw 0.7.1–0.8.5)
| Task | Version | Summary |
|---|---|---|
| T1 | 0.7.1 | Doxygen warnings cleared |
| T2 | 0.7.1 | CI workflow (host tests, Doxygen, manual sync) |
| T3 | 0.7.2 | Preset reorder API/UI, DAB playing ids in status |
| T4 | 0.8.0 | RDS/DLS broadcast metadata |
| T5 | 0.8.1 | IntegrationService — startup, preset recall, last-preset NVS |
| T6 | 0.8.2 | Tabbed configuration Web UI (REST coverage) |
| T7 | 0.8.2 | Si4684 blob policy — gitignore, docs, check_si4684_blobs.py |
| T8 | 0.8.3 | NVS + flash encryption — initEncryptedStorage, security docs |
| T9 | 0.8.4 | Dual-OTA partition table + dsp blob slot, rollback Kconfig |
| T10 | 0.8.4 | EEPROM EUI-48 identity — SoftAP/BT/hostname/serial |
| T11 | 0.8.4 | Updatable ADAU1701 program — POST /api/dsp/program, DRAD blob |
| T12 | 0.8.4 | ESP32 OTA — POST /api/system/ota, rollback confirm on boot |
0.8.5 (hardware/doc alignment): BT1035 boot uses AT+AUXCFG=3 +
AT+I2SCFG=67 (I2S from ADAU1701, not Line-In); I2C pull-ups R1/R16
confirmed 2,kΩ; Hardware/DATASHEET/ bundle + manual cross-refs.
Also landed (not numbered): BT1035 pairing (BluetoothService), station presets
(fw 0.7.0), companion-chip boot (Slice 3), ADAU1701 runtime (Slice 5).
P4 — Hardware-in-the-loop (when PCB arrives)
Manual validation only — does not block host CI.
H1. Encrypted NVS boot path
Follow docs/security-flash-nvs.md: first flash with
idf.py erase-flash flash, verify boot logs, Wi-Fi provisioning survives
reboot, presets and last_preset survive power cycle.
H2. End-to-end listening
Si4684 DAB/FM tune, ADAU1701 profile apply, BT1035 A2DP to headphones,
now-playing metadata in UI and /api/tuner/status.
H3. OTA and DSP program update (on hardware)
Push a known-good .bin via POST /api/system/ota, confirm rollback after a
deliberately bad image. Upload a DRAD blob via POST /api/dsp/program and
verify ADAU replay after reboot.
H4. Production flash encryption (optional)
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.
Open firmware polish (non-blocking)
Done in fw 0.8.5 unless noted:
- BT1035 boot — I2S slave init (
AT+AUXCFG=3,AT+I2SCFG=67) per PCB routing (0.8.5). - FM seek down —
POST /api/tuner/seekwith{"direction":"down"}(0.8.4). - BT1035 — query/set name, paired list (
AT+PLIST), auto-reconnect (AT+AUTOCONN) per Feasycom BT1035 manual (0.8.4). - Si4684 —
STOP_DIGITAL_SERVICE(0x82) before FM band switch when DAB audio is active; ensemble metrics remain viaDAB_DIGRAD_STATUSin status (0.8.4).
Quality gates (run from Software/ before merge)
cmake -S components/core/test -B build-host && cmake --build build-host
ctest --test-dir build-host --output-on-failure
doxygen Doxyfile
python3 tools/check-manual-sync.py
python3 tools/check_si4684_blobs.py
After editing the web UI: tools/gzip-www.sh.
Notes for the agent
- Extend existing patterns (
AudioProfile/IAudioProfileStoreshape). - Never invent Si4684 opcodes — cite AN649.
- Never invent BT1035 AT strings — cite Feasycom BT1035 programming guide.
- One logical change per commit; 50/72 messages.
- Update
ch-classes.tex/ch-api.texwhen public API or HTTP changes.