Detect under-voltage on GPIO1/11, persist UV state in NVS, enter a minimal power mode without ESP-NOW, and recover after charge; expose LED mode 6 battery-low for host testing via goTool. Co-authored-by: Cursor <cursoragent@cursor.com>
162 lines
3.7 KiB
C
162 lines
3.7 KiB
C
#include "pod_settings.h"
|
|
#include "bosch456.h"
|
|
#include "esp_log.h"
|
|
#include "nvs.h"
|
|
#include "nvs_flash.h"
|
|
|
|
static const char *TAG = "[SETTINGS]";
|
|
static const char *NS = "powerpod";
|
|
static const char *KEY_ACCEL_DZ = "accel_dz";
|
|
static const char *KEY_UV_LATCH = "uv_latch";
|
|
|
|
#define ACCEL_DEADZONE_MAX 4095u
|
|
|
|
static bool s_nvs_ready;
|
|
|
|
static esp_err_t ensure_nvs(void) {
|
|
if (s_nvs_ready) {
|
|
return ESP_OK;
|
|
}
|
|
return pod_settings_init();
|
|
}
|
|
|
|
esp_err_t pod_settings_init(void) {
|
|
if (s_nvs_ready) {
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t err = nvs_flash_init();
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
|
|
err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
ESP_LOGW(TAG, "NVS erase and re-init");
|
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
err = nvs_flash_init();
|
|
}
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "nvs_flash_init failed: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
s_nvs_ready = true;
|
|
ESP_LOGI(TAG, "NVS ready, accel deadzone %lu LSB (stored)",
|
|
(unsigned long)pod_settings_load_accel_deadzone());
|
|
return ESP_OK;
|
|
}
|
|
|
|
uint32_t pod_settings_load_accel_deadzone(void) {
|
|
if (!s_nvs_ready) {
|
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
}
|
|
|
|
nvs_handle_t handle;
|
|
esp_err_t err = nvs_open(NS, NVS_READONLY, &handle);
|
|
if (err != ESP_OK) {
|
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
}
|
|
|
|
uint32_t value = BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
err = nvs_get_u32(handle, KEY_ACCEL_DZ, &value);
|
|
nvs_close(handle);
|
|
|
|
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
}
|
|
if (err != ESP_OK) {
|
|
ESP_LOGW(TAG, "read accel_dz failed: %s", esp_err_to_name(err));
|
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
}
|
|
if (value > ACCEL_DEADZONE_MAX) {
|
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
esp_err_t pod_settings_save_accel_deadzone(uint32_t deadzone_lsb) {
|
|
if (deadzone_lsb > ACCEL_DEADZONE_MAX) {
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
esp_err_t err = ensure_nvs();
|
|
if (err != ESP_OK) {
|
|
return err;
|
|
}
|
|
|
|
nvs_handle_t handle;
|
|
err = nvs_open(NS, NVS_READWRITE, &handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "nvs_open failed: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
err = nvs_set_u32(handle, KEY_ACCEL_DZ, deadzone_lsb);
|
|
if (err == ESP_OK) {
|
|
err = nvs_commit(handle);
|
|
}
|
|
nvs_close(handle);
|
|
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "save accel_dz failed: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "saved accel deadzone %lu LSB", (unsigned long)deadzone_lsb);
|
|
return ESP_OK;
|
|
}
|
|
|
|
void pod_settings_apply_accel_deadzone(void) {
|
|
uint32_t deadzone = pod_settings_load_accel_deadzone();
|
|
if (bma456_is_ready()) {
|
|
bma456_set_accel_deadzone(deadzone);
|
|
}
|
|
}
|
|
|
|
bool pod_settings_is_uv_latched(void) {
|
|
if (!s_nvs_ready) {
|
|
return false;
|
|
}
|
|
|
|
nvs_handle_t handle;
|
|
esp_err_t err = nvs_open(NS, NVS_READONLY, &handle);
|
|
if (err != ESP_OK) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t value = 0;
|
|
err = nvs_get_u8(handle, KEY_UV_LATCH, &value);
|
|
nvs_close(handle);
|
|
|
|
return err == ESP_OK && value != 0;
|
|
}
|
|
|
|
esp_err_t pod_settings_set_uv_latched(bool latched) {
|
|
esp_err_t err = ensure_nvs();
|
|
if (err != ESP_OK) {
|
|
return err;
|
|
}
|
|
|
|
nvs_handle_t handle;
|
|
err = nvs_open(NS, NVS_READWRITE, &handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "nvs_open failed: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
err = nvs_set_u8(handle, KEY_UV_LATCH, latched ? 1u : 0u);
|
|
if (err == ESP_OK) {
|
|
err = nvs_commit(handle);
|
|
}
|
|
nvs_close(handle);
|
|
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "save uv_latch failed: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "UV latch %s", latched ? "set" : "cleared");
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t pod_settings_clear_uv_latched(void) {
|
|
return pod_settings_set_uv_latched(false);
|
|
}
|