Fix root cause of audio profile never persisting; document ADAU1701 registers

Root cause (found via SigmaStudio firmware analysis requested this
session): NVS was initialized AFTER HardwareBootstrap::boot(), which
internally calls AudioService::loadAndApply() to restore the saved
mixer/EQ/master-volume profile. Every nvs_open() inside
NvsAudioProfileStore::hasProfile()/loadProfile() failed with
ESP_ERR_NVS_NOT_INITIALIZED (0x1101), silently swallowed as "no saved
profile" -- the audio profile was never actually restored on any boot,
regardless of how many times it was saved via PUT /api/audio/profile.
Fixed by moving secure_store::initEncryptedStorage() to the top of
app_main(), before HardwareBootstrap::boot() (nvs_flash_init() has no
hardware dependency, so this is safe).

Second, related bug: HardwareBootstrap::boot() called
AudioService::applyRadioFirstMix() unconditionally right after
loadAndApply(), discarding any just-restored mixer/master values on
every boot. loadAndApply() now returns whether it actually restored a
profile from NVS; the radio-first fallback only applies when nothing
was saved.

Verified live: a distinct mixer+master+5-EQ-band test pattern now
survives a full reboot exactly as saved (previously always reset to
factory default). DAB/FM/BT unaffected.

Also: added a "locked" flag per EQ band in the audio profile JSON --
band 0 is always locked (fixed high-pass, Adau1701Driver::applyEq()
never safeloads it) and bands 1-2/3-5 are locked whenever
bass_level/stereo_level is active (core::applyEnhancementsToEq()
overwrites them with formula-derived values). This was previously
undiscoverable from the API -- GET echoed back the stored, inert value
with no indication it wasn't what was actually playing.

Full register-by-register analysis of the compiled SigmaStudio program
(signal chain, all 74 Parameter RAM addresses grouped by function, HTTP
API mapping, every endpoint tested live) in
docs/adau1701-sigmastudio-analysis.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 15:52:38 +02:00
co-authored by Claude Sonnet 5
parent a7a5311c2c
commit af51948912
7 changed files with 287 additions and 18 deletions
@@ -37,7 +37,14 @@ constexpr char kProfileKey[] = "audio_profile";
bool NvsAudioProfileStore::hasProfile() const
{
nvs_handle_t handle = 0;
if (nvs_open(kNamespace, NVS_READONLY, &handle) != ESP_OK) {
const esp_err_t openErr = nvs_open(kNamespace, NVS_READONLY, &handle);
if (openErr != ESP_OK) {
// ESP_ERR_NVS_NOT_INITIALIZED (0x1101) here means this was called
// before secure_store::initEncryptedStorage() -- see 2026-08-24 fix
// in main.cpp's app_main() boot order (NVS must init before
// AudioService::loadAndApply(), which calls this).
ESP_LOGW(kTag, "hasProfile: nvs_open failed (0x%x)",
static_cast<unsigned>(openErr));
return false;
}