Files
DigiRadio/Software/docs/audio-bringup-handoff.md
micheleandClaude Sonnet 5 6f7b6dd12c Add internet radio streaming with runtime API, modernize web UI, remove auto-tune/beep at boot
Streaming (main feature this session):
- New WebRadioConfig/WebRadioJson core types, ISecureStore-backed persistence
- New webradio::WebRadioService (thread-safe live config) + GET/POST /api/streaming
- web_radio_stream task now runtime-toggleable (no reboot), no hardcoded URL
- Content-Type diagnostic: warns clearly when a URL is a webpage, not an audio stream

Boot cleanup:
- Removed boot-time auto FM/DAB tune, auto-beep, and the (now-concluded) Si4684
  crystal IBIAS/CTUN empirical sweep from main.cpp — tuning/beep are on-demand
  via the existing REST API only

Web UI:
- Modernized styling (cards, gradients, toggle switches, light/dark theme)
- New Stream tab wired to /api/streaming

Fixes found via real idf.py build (not just clangd):
- Restored wrongly-removed si4684/Si4684Tuner.hpp include in main.cpp
- Fixed MP3Decode() argument types in web_radio_stream.cpp (unsigned char**/int*)

Quality-gate fixes:
- Host-test stub headers (esp_log.h, freertos/*) so TunerService.cpp's
  scanForStation logging/pacing compiles for station_service_test /
  integration_service_test instead of running stale binaries
- Added WifiScanner and WebRadioService manual sections; filled in missing
  Doxygen docs on BluetoothService, i2s_sdata_probe, test_firmware, Bt1035At
- Ignore clangd's .cache/ index directory

Also includes prior uncommitted work carried in the tree: Wi-Fi/Bluetooth
device scan REST API and UI (WifiScanner, BT scan), SigmaStudio TCP bridge,
and the current ADAU1701 SigmaStudio DSP program export.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-08 21:15:22 +02:00

12 KiB
Raw Permalink Blame History

Audio bring-up — handoff per Claude Code

RISOLTO (2026-08-07): audio confermato funzionante end-to-end su Bose (Si4684/ESP32 → ADAU1701 → BT1035 → A2DP). Causa finale del silenzio: la cella DSP "Beep - variable gain" (toolbox ADI Sound Generation) usata come tono di test richiede sia ENABLE sia KICK (il parametro trigger) per avviare davvero la generazione — scrivere solo ENABLE lasciava il generatore silenzioso nonostante tutto il resto della catena (clock I2S, AT+I2SCFG=35 a 24-bit, AT+A2DPAUDIO, encoder SBC attivo) fosse già corretto. Vedi Adau1701Driver::setBeepEnabled().

Il tono di test 440 Hz ora è generato dall'oscillatore interno del DSP ADAU1701 (programma SigmaStudio), non più dall'ESP32. Il codice esp32_i2s_tone e CONFIG_ESP32_I2S_TONE_TEST descritti in questo documento sono stati rimossi dal firmware; il resto del documento resta come riferimento storico del bring-up.

Data: 2026-08-05
Contesto: bring-up hardware DigiRadio su scheda reale (ESP32-S3 + Si4684 + ADAU1701 + FSC-BT1035 → Bose Solo II).
Problema utente: non si sente nulla sul Bose nonostante connessione Bluetooth.
Stato: fix A2DP streaming applicati e verificati parzialmente; test tono ESP32 ancora da confermare a orecchio; FM debole senza antenna.


Setup laboratorio

Parametro Valore
Serial /dev/cu.usbmodem1101
WiFi STA MikiLab
IP / mDNS ~192.168.1.56, digiradio-CC4DB4.local
Speaker BT Bose Solo II, MAC BC87FAE69D6E
Area FM test Massa (MS) — RTL 100.9 MHz, RAI1 95.5, Club FM 97.3
Working dir build Software/

Catena audio (SigmaStudio / hardware)

Si4684 I2S (slave)  → ADAU1701 MP0 (fader Si4674) ─┐
ESP32 I2S (slave)   → ADAU1701 MP1 (fader ESP32)  ─┤→ St Mixer1 → EQ → master → MP6 out
                                                     └→ BT1035 I2S slave (AUXCFG=3) → A2DP → Bose
  • ADAU1701 = I2S master @ 48 kHz
  • ESP32 / BT1035 / Si4684 = I2S slave
  • GPIO I2S ESP32: BCLK=6, LRCLK/WS=7, DOUT=16 → ADAU MP1

Modifiche effettuate (non committate)

Tutte le modifiche sono su branch main, working tree dirty (~48 file toccati in totale, molti pre-esistenti + sessione audio).

1. Bluetooth — A2DP streaming (causa principale del silenzio)

Problema: il BT1035 restava su +A2DPSTAT=3 (Connected) senza passare a 4 (Streaming). Senza streaming il modulo non invia audio I2S→A2DP al Bose.

Fix Feasycom §5.3.6: dopo la connessione serve AT+A2DPAUDIO=1.

File Modifica
components/core/include/core/Bt1035At.hpp Doc + buildBt1035A2dpAudioLine()
components/core/src/Bt1035At.cpp AT+A2DPAUDIO=1/0
components/core/test/bt1035_at_test.cpp Test linee A2DPAUDIO
components/drivers/bt1035/include/bt1035/Bt1035Driver.hpp startA2dpAudio(), waitForA2dpStreaming()
components/drivers/bt1035/src/Bt1035Driver.cpp Poll A2DPSTAT; invia A2DPAUDIO=1 se bloccato su Connected; non uscire subito se query fallisce (retry fino a timeout)
components/services/bluetooth/src/BluetoothService.cpp ensureA2dpStreaming() dopo connect/reconnect; boot reconnect attende STAT=4

Verifica log (OK):

I (Bt1035) A2DP audio start (AT+A2DPAUDIO=1)
I (Bt1035) stream wait: A2DPSTAT=4
I (BluetoothSvc) A2DP streaming OK

2. ADAU1701 — routing mixer boot

File Modifica
components/core/src/MixerState.cpp radioFirst() / esp32First() — selezione sorgente ST0/ST1
components/services/audio/src/AudioService.cpp applyRadioFirstMix() / applyEsp32FirstMix()
main/hardware_bootstrap.cpp Dopo loadAndApply(): mix in base a Kconfig

Con CONFIG_ESP32_I2S_TONE_TEST=y:

I (hw_boot) ADAU1701 ESP32 I2S input routed (esp32-first mix)

Senza tone test (FM):

I (hw_boot) ADAU1701 Si4684 input routed (radio-first mix)

3. Si4684 FM — I2S out + tune/scan

File Modifica
components/drivers/si4684/src/Si4684Driver.cpp AUDIO_OUTPUT_CONFIG bit I2SOUTEN @ boot; unmute; volume max; offset RSQ AN649; tune con fallback STC; band FM 87500107900 kHz
components/drivers/si4684/src/Si4684Tuner.cpp Volume default 63; readStatus() non sovrascrive freq con READFREQ stale
components/services/tuner/src/TunerService.cpp Scan FM step +100 kHz; filtro SNR; fmChipReadFrequency in status
components/core/include/core/TunerStatus.hpp Campo fmChipReadFrequency

Nota: con filo antenna corto, rssi=0 su 100.9 MHz è normale — non indica per forza bug software.

4. Test tono ESP32 → ADAU → BT (isolamento path)

File Modifica
main/Kconfig.projbuild ESP32_I2S_TONE_TEST (default y in Kconfig, disabilitare in produzione)
main/esp32_i2s_tone.cpp Sinusoide 440 Hz, 48 kHz, sample 24-bit MSB in slot 32-bit, amp 0.5
main/esp32_i2s_tone.hpp API start()
main/main.cpp Task esp32_tone: delay 15 s (lascia finire boot reconnect), poi waitForA2DPStreaming, poi I2S
main/CMakeLists.txt Compila esp32_i2s_tone.cpp se Kconfig attivo
sdkconfig.defaults CONFIG_ESP32_I2S_TONE_TEST=y
sdkconfig CONFIG_ESP32_I2S_TONE_TEST=y (abilitato manualmente — prima era # is not set e il tone test non veniva compilato)

5. FM probe boot (alternativa al tone test)

File Modifica
main/main.cpp fm_probe task stack 16384 (era 4096 → stack overflow); tune 100.9 MHz, volume 63

Attivo solo se CONFIG_ESP32_I2S_TONE_TEST è disabilitato.


Build e flash

cd Software

# Tone test ON (bring-up attuale)
idf.py build
idf.py -p /dev/cu.usbmodem1101 flash monitor

# FM probe al posto del tone test
idf.py -DCONFIG_ESP32_I2S_TONE_TEST=n fullclean reconfigure build flash

Attenzione: -DCONFIG_ESP32_I2S_TONE_TEST=y da riga di comando non basta se sdkconfig esistente ha # CONFIG_ESP32_I2S_TONE_TEST is not set. Verificare:

rg CONFIG_ESP32_I2S_TONE_TEST build/config/sdkconfig.h
# deve mostrare: #define CONFIG_ESP32_I2S_TONE_TEST 1

Ultimo build riuscito: digiradio.bin ~0x237fe0 bytes.


Log osservati (sessione 2026-08-05 sera)

A2DP — OK dopo fix

I (BluetoothSvc) reconnect saved speaker BC87FAE69D6E (BOSE SOLO 2)
I (Bt1035) A2DP audio start (AT+A2DPAUDIO=1)
I (Bt1035) stream wait: A2DPSTAT=4
I (BluetoothSvc) A2DP streaming OK

A volte compare brevemente A2DPSTAT=5 prima del 4.

Tone test — problemi I2S (in corso)

Primo flash (tone test non compilato): partiva fm_probe, mix radio-first, nessun log esp32_i2s.

Secondo flash (tone test compilato):

  1. Race: tone task partiva insieme al reconnect → waitForA2dpStreaming usciva subito (query fallita) → tono partiva prima dello streaming.
  2. I2S init falliva:
    E (i2s_std) i2s_std_calculate_clock(68): sample rate is too large
    E (esp32_i2s) i2s_channel_init_std_mode failed
    
    Causa: I2S_CLK_SRC_EXTERNAL senza ext_clk_freq_hz coerente con bclk_div.

Fix applicati (post Fix no audio path):

  • Rimosso I2S_CLK_SRC_EXTERNAL; slave usa BCLK/LRCLK da ADAU con clk_src default.
  • waitForA2dpStreaming: continua a pollare se query fallisce (no early exit).
  • Tone task: delay 15 s prima di attendere A2DP (evita race con boot reconnect).
  • Re-apply applyEsp32FirstMix() + startA2dpAudio() subito prima del tono (NVS/integration sovrascriveva il mix al boot).
  • I2S 24-bit Philips + mclk_multiple=384; ampiezza tono 0.85.
  • sdkconfig: CONFIG_ESP32_I2S_TONE_TEST=y obbligatorio (altrimenti tone test non compilato).

Log verificati su serial (2026-08-05 ~20:15, I2S OK ma Bose silenzioso):

I (Bt1035) stream wait: A2DPSTAT=4
I (BluetoothSvc) A2DP streaming OK
I (digiradio) A2DP streaming — starting I2S tone
I (digiradio) ADAU esp32-first mix re-applied before tone
I (esp32_i2s) I2S slave TX started (BCLK=6 WS=7 DOUT=16)
I (esp32_i2s) tone task: 440 Hz sine, 48000 Hz, ADAU I2S slave TX
I (esp32_i2s) i2s streaming 2048 bytes/frame to ADAU MP1

FM (senza tone test)

I (digiradio) FM audio probe OK: 100900 kHz rssi=0 dBuV snr=0 dB locked=0

Segnale assente/ debole — serve antenna.


Dove siamo arrivati

Componente Stato
Boot ADAU + profilo NVS OK
BT1035 I2S slave (AUXCFG=3, I2SCFG=67) OK
Reconnect Bose saved speaker OK
A2DP Streaming (STAT=4) OK — fix AT+A2DPAUDIO=1 (Fix no audio path)
Mix ADAU esp32-first / radio-first OK; re-apply prima del tono necessario (NVS)
Test tono 440 Hz — firmware OK (I2S init + write verificati in log)
Test tono 440 Hz — Bose Silenzio — probabile hardware ADAU MP6 → BT1035 o sorgente BT Bose
FM audio su Bose Non testabile finché tono non si sente o RSSI > 0
Utente «no nulla» — silenzio persistente nonostante log software OK

Prossimi passi consigliati (priorità)

  1. Se log mostrano A2DPSTAT=4 + i2s streaming … bytes/frame ma Bose muto → debug hardware:

    • Oscilloscopio: BCLK/LRCLK GPIO 6/7; dati MP6 ADAU → BT1035; dati GPIO 16 → ADAU MP1.
    • Bose: sorgente BT = DigiRadio, telefono scollegato, volume alto.
    • Verificare saldature/cavi I2S tra ADAU e BT1035 (path dopo DSP).
  2. Se I2S init fallisce ancora

    • Provare I2S_DATA_BIT_WIDTH_24BIT + slot 32-bit (allineamento ADAU MP1).
    • Provare bclk_div 4 o 12 (vedi test ESP-IDF i2s_multi_dev slave).
    • Verificare con oscilloscopio BCLK/LRCLK su GPIO 6/7 quando ADAU è bootato (ADAU deve essere master attivo prima di i2s_channel_enable).
  3. Se tono OK ma FM no

    • Tornare a build senza tone test (CONFIG_ESP32_I2S_TONE_TEST=n).
    • Antenna FM; verificare I2SOUTEN Si4684 e applyRadioFirstMix.
    • Cercare rssi>15, locked=1.
  4. Se A2DPSTAT=4 ma silenzio totale

    • Hardware: MP6 ADAU → pin I2S BT1035; alimentazione Bose.
    • Verificare master volume / mute ADAU (safeload profilo — non dovrebbe essere a −∞).
  5. Commit — non richiesto dall'utente finora; quando pronto, separare almeno:

    • BT A2DPAUDIO / streaming
    • Si4684 I2SOUTEN + scan/tune
    • Tone test Kconfig (dev-only)

File chiave (quick reference)

main/main.cpp                    — fm_probe vs esp32_tone task
main/hardware_bootstrap.cpp      — mix ADAU al boot
main/esp32_i2s_tone.cpp          — generatore tono I2S slave
main/Kconfig.projbuild           — ESP32_I2S_TONE_TEST
sdkconfig / sdkconfig.defaults   — Kconfig effettivo

components/drivers/bt1035/       — A2DPAUDIO, waitForA2dpStreaming
components/services/bluetooth/   — ensureA2dpStreaming al reconnect
components/services/audio/       — applyRadioFirstMix / applyEsp32FirstMix
components/core/MixerState.cpp   — preset mixer ST0/ST1
components/drivers/si4684/       — I2SOUTEN, tune, RSQ
components/services/tuner/       — FM scan step tune

Note per Claude Code

  • Leggere AGENTS.md e .cursor/rules/ prima di modifiche.
  • Non committare salvo richiesta esplicita utente.
  • Il tone test è solo bring-up — disabilitare per produzione (sdkconfig.defaults.production o CONFIG_ESP32_I2S_TONE_TEST=n).
  • Due task competono sulla UART BT1035 (reconnect + tone wait): il delay 15 s mitiga ma non elimina del tutto la contesa; alternativa migliore: avviare il tone dal callback post-boot reconnect OK in BluetoothService.
  • Transcript conversazione Cursor: thread audio/FM, ID d10654e5-d27a-4999-812e-f371dc48567a.

Comandi utili debug

# Monitor filtrato
idf.py -p /dev/cu.usbmodem1101 monitor | rg -i 'A2DP|esp32_i2s|hw_boot|tone|streaming|error'

# Verifica config tone test nel binario
rg CONFIG_ESP32_I2S_TONE_TEST build/config/sdkconfig.h

# Reset + cattura serial (python)
python3 -c "
import serial, time
s=serial.Serial('/dev/cu.usbmodem1101',115200,timeout=0.2)
s.dtr=False; s.rts=True; time.sleep(0.1); s.rts=False
t=time.time()
while time.time()-t<90:
    l=s.readline()
    if l: print(l.decode(errors='replace'), end='')
"