/* * Copyright 2023 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #include "nvs.hpp" #include #include #include #include #include "bluetooth.hpp" #include "bluetooth_types.hpp" #include "esp_log.h" #include "nvs.h" #include "nvs_flash.h" #include "tasks.hpp" #include "wm8523.hpp" namespace drivers { static constexpr char kTag[] = "nvm"; static constexpr uint8_t kSchemaVersion = 1; static constexpr char kKeyVersion[] = "ver"; static constexpr char kKeyBluetooth[] = "bt"; static constexpr char kKeyOutput[] = "out"; static constexpr char kKeyBrightness[] = "bright"; static constexpr char kKeyAmpMaxVolume[] = "hp_vol_max"; static constexpr char kKeyAmpCurrentVolume[] = "hp_vol"; static constexpr char kKeyOnboarded[] = "intro"; auto NvsStorage::OpenSync() -> NvsStorage* { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES) { ESP_LOGW(kTag, "partition needs initialisation"); nvs_flash_erase(); err = nvs_flash_init(); } if (err != ESP_OK) { ESP_LOGE(kTag, "failed to init nvm"); return nullptr; } nvs_handle_t handle; if ((err = nvs_open("tangara", NVS_READWRITE, &handle)) != ESP_OK) { ESP_LOGE(kTag, "failed to open nvs namespace"); return nullptr; } std::unique_ptr instance = std::make_unique( std::unique_ptr( tasks::Worker::Start()), handle); if (instance->SchemaVersionSync() < kSchemaVersion && !instance->DowngradeSchemaSync()) { ESP_LOGW(kTag, "failed to init namespace"); return nullptr; } ESP_LOGI(kTag, "nvm storage initialised okay"); return instance.release(); } NvsStorage::NvsStorage(std::unique_ptr worker, nvs_handle_t handle) : writer_(std::move(worker)), handle_(handle) {} NvsStorage::~NvsStorage() { nvs_close(handle_); nvs_flash_deinit(); } auto NvsStorage::DowngradeSchemaSync() -> bool { ESP_LOGW(kTag, "namespace needs downgrading"); return writer_ ->Dispatch([&]() -> bool { nvs_erase_all(handle_); nvs_set_u8(handle_, kKeyVersion, kSchemaVersion); return nvs_commit(handle_); }) .get() == ESP_OK; } auto NvsStorage::SchemaVersionSync() -> uint8_t { return writer_ ->Dispatch([&]() -> uint8_t { uint8_t ret; if (nvs_get_u8(handle_, kKeyVersion, &ret) != ESP_OK) { return UINT8_MAX; } return ret; }) .get(); } auto NvsStorage::PreferredBluetoothDevice() -> std::future> { return writer_->Dispatch>( [&]() -> std::optional { bluetooth::mac_addr_t out{0}; size_t size = out.size(); if (nvs_get_blob(handle_, kKeyBluetooth, out.data(), &size) != ESP_OK) { return {}; } return out; }); } auto NvsStorage::PreferredBluetoothDevice( std::optional addr) -> std::future { return writer_->Dispatch([&]() { if (!addr) { nvs_erase_key(handle_, kKeyBluetooth); } else { nvs_set_blob(handle_, kKeyBluetooth, addr.value().data(), addr.value().size()); } return nvs_commit(handle_) == ESP_OK; }); } auto NvsStorage::OutputMode() -> std::future { return writer_->Dispatch([&]() -> Output { uint8_t out = 0; nvs_get_u8(handle_, kKeyOutput, &out); switch (out) { case static_cast(Output::kBluetooth): return Output::kBluetooth; case static_cast(Output::kHeadphones): default: return Output::kHeadphones; } }); } auto NvsStorage::OutputMode(Output out) -> std::future { return writer_->Dispatch([&]() { uint8_t as_int = static_cast(out); nvs_set_u8(handle_, kKeyOutput, as_int); return nvs_commit(handle_) == ESP_OK; }); } auto NvsStorage::ScreenBrightness() -> std::future { return writer_->Dispatch([&]() -> uint_fast8_t { uint8_t out = 50; nvs_get_u8(handle_, kKeyBrightness, &out); return out; }); } auto NvsStorage::ScreenBrightness(uint_fast8_t val) -> std::future { return writer_->Dispatch([&]() { nvs_set_u8(handle_, kKeyBrightness, val); return nvs_commit(handle_) == ESP_OK; }); } auto NvsStorage::AmpMaxVolume() -> std::future { return writer_->Dispatch([&]() -> uint16_t { uint16_t out = wm8523::kDefaultMaxVolume; nvs_get_u16(handle_, kKeyAmpMaxVolume, &out); return out; }); } auto NvsStorage::AmpMaxVolume(uint16_t val) -> std::future { return writer_->Dispatch([&]() { nvs_set_u16(handle_, kKeyAmpMaxVolume, val); return nvs_commit(handle_) == ESP_OK; }); } auto NvsStorage::AmpCurrentVolume() -> std::future { return writer_->Dispatch([&]() -> uint16_t { uint16_t out = wm8523::kDefaultVolume; nvs_get_u16(handle_, kKeyAmpCurrentVolume, &out); return out; }); } auto NvsStorage::AmpCurrentVolume(uint16_t val) -> std::future { return writer_->Dispatch([&]() { nvs_set_u16(handle_, kKeyAmpCurrentVolume, val); return nvs_commit(handle_) == ESP_OK; }); } auto NvsStorage::HasShownOnboarding() -> std::future { return writer_->Dispatch([&]() -> bool { uint8_t out = false; nvs_get_u8(handle_, kKeyOnboarded, &out); return out; }); } auto NvsStorage::HasShownOnboarding(bool val) -> std::future { return writer_->Dispatch([&]() { nvs_set_u8(handle_, kKeyOnboarded, val); return nvs_commit(handle_) == ESP_OK; }); } } // namespace drivers