Files
DigiRadio/Software/docs/cursor-app-sync-2026-08-24.md
T
micheleandClaude Sonnet 5 a7a5311c2c Persist Si4684 crystal calibration (ibias/ctun/xtalFreqHz) to EEPROM
Extends the existing FM/DAB ANTCAP EEPROM persistence pattern
(Eeprom24aa::writeFmAntCap/writeDabAntCap) to the crystal trim found by
POST /api/tuner/xtal-calibrate, which previously only applied live and
was lost on every reboot.

- Eeprom24aa gains readXtalCalibration()/writeXtalCalibration() at word
  addresses 0x02 (ibias), 0x03 (ctun), 0x04-0x07 (xtalFreqHz,
  big-endian), right after the existing FM/DAB ANTCAP bytes.
- HardwareBootstrap::boot() now boots ADAU1701 before Si4684 (needed so
  the EEPROM read, which borrows ADAU1701's I2C bus, can happen before
  Si4684's boot() call, which takes the crystal trim as an argument),
  loads the saved trim if present, and falls back to the compiled-in
  defaults (ibias=72, ctun=0, xtalFreqHz=19199750) otherwise.
- POST /api/tuner/xtal-calibrate now persists every successful live
  recalibration automatically ("persisted":true/false in the response)
  via a new saveXtalCalibration()/net::AntennaCalibration::saveXtal
  bridge, mirroring the ANTCAP save pattern.

Verified live: boot log confirms "Xtal not calibrated" before the first
save, "Xtal calibration loaded: ibias=72 ctun=0 xtal_freq_hz=19199750"
after, surviving a reboot; DAB/FM tuning unaffected (DAB CNR 17-19dB,
locked).

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

4.9 KiB

Note per l'app companion (igiRadio) — sync 2026-08-24

Riepilogo dei cambi firmware di oggi rilevanti per l'app iOS. Incollare in Cursor come contesto.

1. Nuovo endpoint: codec A2DP Bluetooth

GET  /api/bluetooth/a2dp-codec
POST /api/bluetooth/a2dp-codec   body: {"codec_mask": <0-63>}
  • GET risponde {"codec":"sbc"} (valori possibili: sbc, aptx, aptx-hd, aptx-ll, aptx-adaptive; se il modulo BT1035 negozia AAC la risposta può non essere interpretabile — il datasheet Feasycom non documenta un codice di ritorno per AAC, quindi in quel caso l'app deve gestire un valore/errore sconosciuto senza andare in crash).
  • POST con codec_mask è una bitmask: BIT0=AAC, BIT1=aptX, BIT2=aptX-LL, BIT3=aptX-HD, BIT4=aptX-Adaptive, BIT5=LDAC. 0 forza solo SBC (baseline obbligatorio). Risposta {"status":"saved"} o {"status":"error","reason":"..."}.
  • Importante: il cambio vale solo per la prossima negoziazione — se un dispositivo Bluetooth è già connesso, serve chiamare POST /api/bluetooth/disconnect e far riconnettere il device (dal lato telefono/speaker) perché il nuovo codec venga effettivamente usato. Se l'app espone questa funzione in UI, considerare di mostrare un messaggio tipo "riconnetti il dispositivo Bluetooth per applicare".

2. Fix: salvataggio profilo audio (EQ/mixer) ora persiste davvero

Prima di oggi, PUT /api/audio/profile applicava le modifiche dal vivo ma falliva sempre silenziosamente nel salvataggio permanente (bug: nome chiave NVS troppo lungo). L'app probabilmente vedeva errori intermittenti o impostazioni che sparivano al riavvio della scheda. Ora è risolto e verificato: le modifiche sopravvivono a un riavvio. Nessun cambio di formato richiesto lato app — stesso schema JSON di sempre.

3. Fix: il parser JSON del firmware ora tollera JSON non-compatto

Prima di oggi il parser lato firmware richiedeva JSON strettamente compatto ({"key":"value"}, nessuno spazio dopo i due punti) — un JSONEncoder Swift in modalità non-compatta (es. con .prettyPrinted, o formattazione di default in alcune configurazioni) poteva produrre "key": "value" e far fallire il parsing lato server con invalid_json o missing_field.

Questo è ora risolto per tutti gli endpoint (tuner, audio profile, stazioni, bluetooth, wifi, streaming, DSP param). Se nell'app c'era un workaround per forzare JSON compatto (es. JSONEncoder().outputFormatting impostato esplicitamente senza spazi, o costruzione manuale di stringhe JSON), non è più necessario ma può restare — è comunque compatibile.

4. Nomi campi corretti (promemoria, riscontrati oggi durante i test manuali)

Attenzione a questi nomi campo esatti attesi dal firmware — un nome sbagliato produce missing_field, non necessariamente un errore chiaro:

  • POST /api/tuner/tune per DAB: {"band":"dab","freq_index":<0-37>}non "frequency".
  • POST /api/tuner/tune per FM: {"band":"fm","frequency_khz":<khz>}.
  • POST /api/stations per una stazione FM: {"name":"...","band":"fm","fm_frequency_khz":<khz>}non "frequency_khz" a livello radice.
  • POST /api/stations per una stazione DAB: {"name":"...","band":"dab","dab_freq_index":<0-37>} (opzionali dab_service_id, dab_component_id).
  • POST /api/stations/remove: {"index":<n>}non {"name":"..."}.

Se l'app usa nomi diversi da questi in qualche punto, verificare contro components/core/src/StationListJson.cpp e components/core/src/TunerJson.cpp nel repo firmware (fonte di verità).

5. Nessun cambio di schema per mixer/EQ

Lo schema di GET|PUT /api/audio/profile è invariato:

{
  "mixer": {
    "si4684_left_db": 0, "si4684_right_db": 0,
    "esp32_left_db": -96, "esp32_right_db": -96,
    "mix_left_db": 0, "mix_right_db": -96
  },
  "master": {"left_db": 0, "right_db": 0},
  "eq": [
    {"gain_db": 0, "center_hz": 20, "q": 1.414},
    {"gain_db": 0, "center_hz": 100, "q": 1},
    {"gain_db": 0, "center_hz": 400, "q": 1},
    {"gain_db": 0, "center_hz": 1000, "q": 1},
    {"gain_db": 0, "center_hz": 3000, "q": 1},
    {"gain_db": 0, "center_hz": 8000, "q": 1}
  ],
  "enhancements": {"stereo_level": 0, "bass_level": 0}
}

Nota: esp32_left_db/esp32_right_db/mix_right_db a -96 = leg ESP32 (streaming web radio) mutato, si4684_*/mix_left_db a 0 = leg radio (FM/DAB) aperto — è il default "radio-first" di fabbrica. Se l'app vuole passare a streaming web-radio senza sentire anche la radio in sovrapposizione, deve invertire questi gain (radio a -96, esp32 a 0) — non è automatico solo abilitando POST /api/streaming.

6. Bug noto, non ancora risolto

  • PUT /api/audio/profile con enhancements (stereo/bass) diverso da zero sovrascrive eventuali modifiche manuali dell'EQ — bug già tracciato, non toccato oggi.
  • La banda EQ indice 0 (20 Hz) è in realtà un filtro passa-alto fisso non modificabile dal DSP — il valore gain_db mostrato/inviato per quella banda è cosmetico, non ha effetto reale sul suono.