Files
DigiRadio/Software
micheleandClaude Sonnet 5 736db623b3 Fix total-audio-silence-on-any-EQ-change: negate ADAU1701 feedback coeffs
designPeakingEq() mapped the RBJ cookbook's a1/a2 straight into the
ADAU1701 Param EQ cell's A0/A1 registers. The cookbook's difference
equation subtracts the feedback terms; the ADAU1701 cell adds them. Any
nonzero band gain therefore applied positive instead of negative
feedback at the target frequency, so the biquad's state diverged and
railed to a constant (inaudible DC) value -- the "any EQ/enhancement
change goes completely silent, even the beep test tone" bug.

Confirmed live: SigmaStudio's own direct safeload writes to the same
registers (correctly signed by its own tool) only distorted, never
silenced, which pointed at this driver's own coefficient math rather
than the DSP chain or the safeload mechanism itself.

Adds a host test asserting Jury stability for the ADD-convention
denominator across the actual bass/stereo-enhance gain values and the
GainDb range extremes, so a regression trips ctest instead of requiring
a live listening test to notice.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 18:33:47 +02:00
..
2026-07-06 01:12:37 +02:00
2026-07-06 01:12:37 +02:00

DigiRadio Firmware

Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3.

Status: fw 0.8.5 on main — BT1035 I2S slave boot init, dual OTA + DSP blob updates, EEPROM identity, NVS + flash encryption (development mode), tabbed Web UI with System uploads, 15 host tests, 4 CI jobs. Agent tasks T1T12 complete; device HIL pending first PCB.

Area Shipped in 0.8.5
Boot Si4684 HOST_LOAD, ADAU1701 RAM program, BT1035 I2S slave init (AUXCFG=3, I2SCFG=67)
Tuner FM/DAB tune, seek up/down, RSQ, RDS, DAB services + DLS
Audio 6-band EQ, mixer, stereo/bass enhance, NVS profile
Updates ESP32 dual-OTA, ADAU1701 dsp partition blob replay
Identity 24AA025E48 EUI-48 → serial, SoftAP/BT name suffix
Presets CRUD, reorder, integrated recall + last-preset at boot
Network SoftAP/STA, tabbed gzipped SPA, typed JSON REST API
Security initEncryptedStorage() — see docs/security-flash-nvs.md
Quality Doxygen, manual sync, Si4684 blob policy check

Architecture: functional core (components/core, host-tested, no ESP-IDF) + imperative shell (drivers, services, net, secure_store). Rules: AGENTS.md · backlog: docs/TODO.md

Prerequisites

Si4684 blobs (proprietary, local only — not in git):

python3 tools/fetch_si4684_firmware.py --dab-only
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware
python3 tools/check_si4684_blobs.py

See Firmware/Si4684-Firmware/README.md.

ESP-IDF v5.5.x, target esp32s3.

Quick start

Open this directory (Software/) as the Cursor project so AGENTS.md and .cursor/rules/ load automatically.

idf.py set-target esp32s3
idf.py build
idf.py erase-flash flash   # once when first enabling encryption (0.8.3+)
idf.py -p <port> monitor

Production flash-encryption release mode: overlay sdkconfig.defaults.production (see security doc — irreversible on chip).

Host tests

Pure core, no hardware (needs C++23 compiler on macOS — Homebrew llvm or GCC 14):

cmake -S components/core/test -B build-host \
      -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++"
cmake --build build-host
ctest --test-dir build-host --output-on-failure

Quality gates (CI on every push to main)

Run from Software/:

doxygen Doxyfile
python3 tools/check-manual-sync.py
python3 tools/check_si4684_blobs.py
tools/gzip-www.sh   # after editing components/net/www/index.html

CI jobs: host-tests, doxygen, manual-sync, si4684-blobs (.github/workflows/ci.yml).

Web UI

Gzipped single-page app at / — tabs: Now (RDS/DLS), Radio, Presets, Audio (6-band EQ), BT, WiFi, System (firmware OTA + DSP upload). Header shows EEPROM serial from /api/health. Source: components/net/www/index.html · regenerate embed: tools/gzip-www.sh.

HTTP API (fw 0.8.5)

Method Path Purpose
GET /api/health Status, firmware version, serial, companion-chip flags
POST /api/wifi Provision STA credentials; reboot on success
GET /api/tuner/status Tuner snapshot (DAB/FM, RDS/DLS metadata)
GET /api/tuner/services DAB service list for current ensemble
POST /api/tuner/tune Tune DAB ensemble or FM frequency
POST /api/tuner/play Start DAB service playback
POST /api/tuner/seek FM seek up or down ({"direction":"up|down"})
GET/PUT /api/audio/profile Read/apply ADAU1701 mixer + 6-band EQ
POST /api/audio/reset Factory-flat audio profile
POST /api/audio/stereo-enhance Stereo depth overlay (0100)
POST /api/audio/bass-enhance Bass enhance overlay (0100)
POST /api/dsp/program Upload ADAU1701 DRAD blob (raw bytes, reboot)
POST /api/system/ota Upload ESP32 firmware image (raw bytes, reboot)
GET /api/bluetooth/status BT1035 boot, pairing, A2DP, name, auto-reconnect
GET /api/bluetooth/paired Paired-device list from module
POST /api/bluetooth/pair Enter discoverable mode
POST /api/bluetooth/pair/stop Leave discoverable mode
POST /api/bluetooth/disconnect Release A2DP session
POST /api/bluetooth/auto-reconnect Set auto-reconnect count (015)
GET /api/stations List saved presets
POST /api/stations Add preset
POST /api/stations/remove Remove preset by index
POST /api/stations/reorder Move preset (from/to indices)
POST /api/stations/tune Recall preset (tuner + audio profile + NVS)

Wire schemas: docs/manual/ch-api.tex · C++ API: doxygen Doxyfiledocs/api/html/index.html.

Layout

Path Role
Firmware/ Si4684 .bin (local) + ADAU1701 SigmaStudio export
components/core/ Pure domain (host-tested)
components/drivers/ Si4684, ADAU1701, BT1035
components/services/ Tuner, audio, Bluetooth, station, integration
components/secure_store/ Encrypted NVS: credentials, profiles, presets
components/net/ Wi-Fi, HTTP server, gzipped web UI
sdkconfig.defaults C++23, NVS + flash encryption (dev mode)
partitions.csv nvs, otadata, dual OTA (ota_0/ota_1), dsp blob, nvs_keys
docs/manual/ LaTeX technical manual
docs/security-flash-nvs.md Encryption + device HIL checklist
docs/TODO.md Completed tasks + HIL backlog
tools/ Blob fetch, CI policy checks, UI gzip

Manual PDF: cd docs/manual && latexmk -lualatex manual.tex

Licence

Apache-2.0 — see LICENSE.