Files
DigiRadio/Software/instructions.md
T
micheleandCursor 82c9f401da Add BT1035 pairing and station presets (fw 0.7.0).
Expose discoverable mode and A2DP control over REST, add persisted
DAB/FM preset list with web UI, and document gaps in docs/TODO.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 17:42:11 +02:00

6.5 KiB
Raw Blame History

instructions.md — DigiRadio firmware, agent kickoff

Read this together with AGENTS.md and everything under .cursor/rules/. Those define how to write code; this file defines what we are building and what to do first.

What DigiRadio is

An open-source Hi-Fi DAB+/FM digital radio board. Firmware runs on an ESP32-S3 and coordinates three companion chips:

  • Si4684 — DAB+/FM tuner (delivers the audio stream).
  • ADAU1701 — SigmaDSP: equaliser + input mixer between the Si4684 and the ESP32 audio path. Program is written to DSP RAM at every boot (no self-boot EEPROM).
  • FSC-BT1035 (QCC3056) — Bluetooth 5.2 out with aptX Adaptive, controlled by AT commands over UART.

Plus: an elegant, essential web UI for network configuration; encrypted storage for Wi-Fi and user credentials and the station list.

Repository: https://github.com/manvalan/DigiRadio

Confirmed technical decisions (do not re-litigate)

Area Decision
Framework ESP-IDF v5.5.x (native, not Arduino)
Language C++23, pinned -std=gnu++23
Errors std::expected<T, Error> (native); exceptions OFF
DSP boot ESP32 writes ADAU1701 RAM at every boot (no EEPROM)
Architecture Functional core (pure, host-tested) + imperative shell
Docs Doxygen, build must exit 0 (enforced)
HW licence CERN-OHL-S v2 · FW licence: Apache-2.0

Working agreement

  • Confirm understanding before writing code. On kickoff, summarise the plan and list any blockers or unclear hardware invariants first.
  • Blockers first, always. State risks before solutions.
  • One vertical slice at a time. main always builds and runs.
  • Every file gets the Apache header; every class/method its doc block; doxygen Doxyfile stays green. Small commits, 50/72 messages.
  • Never invent a register/opcode/boot step — cite the datasheet or stop.

Roadmap (slices, in order)

  1. Walking skeleton — done (Slice 1).
  2. Secure store + Wi-Fi provisioning — done (Slice 2).
  3. Companion-chip boot — done (Slice 3): Si4684 DAB + ADAU1701 RAM load.
  4. Station/frequency list model + persistence + UI — done (fw 0.7.0): Station/StationList, NVS key station_list, /api/stations/*, Presets UI.
  5. Si4684 tuning: RSQ, station list, DAB properties.
  6. ADAU1701 runtime — done (Slice 5): safeload EQ + input mixer + HTTP.
  7. FSC-BT1035 driver — init + pairing (AT+PAIR, A2DP stat/disconnect) done; name/plist/reconnect AT still open.
  8. Integration: TunerService + AudioService end to end.

Slice 1 — Walking skeleton (complete)

Goal: exercise the whole toolchain end to end with zero chip hardware, so every later slice drops into a working frame.

Build:

  • Top-level ESP-IDF project targeting esp32s3.
  • sdkconfig.defaults sets C++23, exceptions off, and documents flash/NVS encryption options (not hard-enabled until production).
  • The components/core component compiles both under ESP-IDF and standalone on the host.

Behaviour:

  • app_main starts a FreeRTOS task that logs a heartbeat on a timer.
  • Bring up SoftAP with a known SSID (e.g. DigiRadio-setup).
  • Start an HTTP server serving one minimal gzipped page from flash.
  • Expose GET /api/health returning a typed DTO serialised by the pure core, e.g. {"status":"ok","fw":"0.3.0"}.

Documentation (required):

  • Doxygen doc blocks on every class/method; doxygen Doxyfile green.
  • Manual: class sections in docs/manual/ch-classes.tex; HTTP API in docs/manual/ch-api.tex.
  • python3 tools/check-manual-sync.py green.

Slice 2 — Secure store + Wi-Fi STA (complete)

Goal: persist Wi-Fi credentials and join the configured network after provisioning; fall back to SoftAP when no credentials or join fails.

Build on Slice 1:

  • core::ISecureStore interface + secure_store::NvsSecureStore (NVS).
  • core::Secret, WifiSsid, WifiCredentials, parseWifiProvisionJson.
  • net::StaClient, NetBootstrap::start(store) state machine.
  • POST /api/wifi + provisioning form in the web UI; reboot after save.

Acceptance criteria:

  • Provisioning via SoftAP saves credentials and reboots; next boot joins STA.
  • Host tests for health JSON and Wi-Fi provision parse/serialise.
  • Doxygen green; manual sync green; ch-api.tex documents endpoints.
  • No ESP-IDF headers in components/core.

Out of scope: station list, user credentials, NVS encryption enablement (production), chip drivers.

Slice 3 — Companion-chip boot (complete)

Goal: load Si4684 DAB firmware and ADAU1701 SigmaStudio program from Firmware/ on every boot, before network bring-up.

Build:

  • Firmware/Si4684-Firmware/rom_patch_016.bin, dab_firmware.bin, fm_firmware.bin (FM via tools/fetch_si4684_firmware.py --si46xx-dir).
  • Firmware/ADAU1701-Firmware/ — SigmaStudio export (DigiRadio_IC_1.h, …).
  • core::IFirmwareBlobReader + EmbeddedBlobReader for chunked HOST_LOAD.
  • si4684::Si4684Driver, adau1701::Adau1701Driver, HardwareBootstrap.

Behaviour:

  • app_main calls HardwareBootstrap::boot() first (Si4684, then ADAU1701).
  • On failure, firmware logs and halts before Wi-Fi.

Acceptance criteria:

  • AN649 boot sequence with streaming blobs (no full image on heap).
  • ADAU1701 reset + I2C + default_download_IC_1() replay.
  • Host test for EmbeddedBlobReader; manual sync green.
  • Device flash verified (requires ESP-IDF toolchain on build host).

Slice 5 — ADAU1701 runtime + audio API (complete)

Goal: safeload mixer/EQ/master on the ADAU1701 at runtime; persist user profiles in NVS; expose REST and web UI controls.

Build on Slice 34:

  • Pure core: GainDb, EqProfile, AudioProfile, IDsp, biquad design, parseAudioProfileJson / serializeAudioProfileJson.
  • Driver: sigma_safeload_*, extended Adau1701Driver, Adau1701Dsp.
  • Service: audio::AudioService, secure_store::NvsAudioProfileStore.
  • HTTP: GET/PUT /api/audio/profile, POST /api/audio/reset; Audio section in the web UI. Firmware 0.5.0.

Acceptance criteria:

  • Safeload volume/mixer/EQ without direct param RAM writes during audio.
  • Profile load/apply after ADAU boot; NVS round-trip via JSON.
  • Host tests for biquad fixpoint and audio profile JSON.
  • Doxygen green; manual sync green; ch-api.tex documents audio routes.
  • Device flash verified on hardware.