diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2025-12-07 00:48:44 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2025-12-07 00:48:44 -0700 |
| commit | 3f8b6e6f34275bdba501e3b1cddab43331b6f569 (patch) | |
| tree | 240abbebd3ed62565325626ad47887a9d78ee96d | |
| parent | 8c6fd7fd39a17216b1a12601a1ec943d557040c2 (diff) | |
| download | esp32-ws2812b-3f8b6e6f34275bdba501e3b1cddab43331b6f569.tar.gz esp32-ws2812b-3f8b6e6f34275bdba501e3b1cddab43331b6f569.tar.bz2 esp32-ws2812b-3f8b6e6f34275bdba501e3b1cddab43331b6f569.zip | |
Add persistence to keep the state params the same across reboots.
| -rw-r--r-- | include/ws2812b_writer.h | 3 | ||||
| -rw-r--r-- | main/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | main/http_server.c | 1 | ||||
| -rw-r--r-- | main/main.c | 11 | ||||
| -rw-r--r-- | main/state_store.c | 59 | ||||
| -rw-r--r-- | main/state_version.h.in | 3 | ||||
| -rw-r--r-- | main/tcp_server.c | 2 | ||||
| -rw-r--r-- | main/ws2812b_writer.c | 1 |
8 files changed, 90 insertions, 2 deletions
diff --git a/include/ws2812b_writer.h b/include/ws2812b_writer.h index ac4eb05..b750da6 100644 --- a/include/ws2812b_writer.h +++ b/include/ws2812b_writer.h @@ -3,6 +3,7 @@ #define WS2812B_WRITER_H_ #include "drv/ws2812b.h" +#include "esp_err.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/task.h" @@ -24,6 +25,8 @@ typedef struct { } ws_params_t; void reset_parameters(ws_params_t* params); +esp_err_t ws_state_save(const ws_state_t* state); +esp_err_t ws_state_load(ws_state_t* state); portTASK_FUNCTION_PROTO(ws2812b_write_task, params); diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index c595f30..4f7b302 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,7 +3,17 @@ file(GLOB_RECURSE MAIN_SRCS "${CMAKE_CURRENT_LIST_DIR}/*.c") # CMakeLists and registration. list(FILTER MAIN_SRCS EXCLUDE REGEX ".*/drv/.*") +# Derive a schema hash from the parameter definition so persisted state +# automatically invalidates when the schema changes. +set(STATE_PARAMS_FILE "${CMAKE_CURRENT_LIST_DIR}/../include/state_params.i") +file(SHA1 "${STATE_PARAMS_FILE}" STATE_SCHEMA_SHA1) +string(SUBSTRING "${STATE_SCHEMA_SHA1}" 0 8 STATE_SCHEMA_HASH) +configure_file( + "${CMAKE_CURRENT_LIST_DIR}/state_version.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/state_version.h" + @ONLY) + idf_component_register( SRCS ${MAIN_SRCS} - INCLUDE_DIRS "../include" + INCLUDE_DIRS "../include" "${CMAKE_CURRENT_BINARY_DIR}" REQUIRES esp_driver_spi spi_flash esp_http_server esp_wifi nvs_flash) diff --git a/main/http_server.c b/main/http_server.c index aabd9fb..ec8a8aa 100644 --- a/main/http_server.c +++ b/main/http_server.c @@ -145,6 +145,7 @@ static void handle_set_color_int_t(httpd_req_t* req, color_int_t* val) return ESP_FAIL; \ } \ handle_set_##typ(req, ¶ms->state.attr); \ + ws_state_save(¶ms->state); \ xSemaphoreGive(params->state_lock); \ httpd_resp_send(req, NULL, 0); \ return ESP_OK; \ diff --git a/main/main.c b/main/main.c index 88f6994..c57c414 100644 --- a/main/main.c +++ b/main/main.c @@ -108,6 +108,7 @@ void app_main(void) ws_params.drv = ws2812b_init(spi); ws_params.state_lock = xSemaphoreCreateMutex(); configASSERT(ws_params.state_lock != NULL); + reset_parameters(&ws_params); printf("Configuration complete!!\n"); @@ -115,6 +116,16 @@ void app_main(void) wifi_init_station("Wort", "JoshIsBau5"); ESP_LOGI("main", "Complete!"); + if (xSemaphoreTake(ws_params.state_lock, portMAX_DELAY) == pdTRUE) { + esp_err_t load_err = ws_state_load(&ws_params.state); + if (load_err == ESP_OK) { + ESP_LOGI("main", "Restored state from NVS"); + } else { + ESP_LOGI("main", "No saved state (%d); using defaults", load_err); + } + xSemaphoreGive(ws_params.state_lock); + } + xTaskCreate( time_keeper, "time_keeper", diff --git a/main/state_store.c b/main/state_store.c new file mode 100644 index 0000000..c764e19 --- /dev/null +++ b/main/state_store.c @@ -0,0 +1,59 @@ +#include "ws2812b_writer.h" + +#include "esp_log.h" +#include "nvs_flash.h" +#include "state_version.h" + +static const char* TAG = "state_store"; +static const char* NAMESPACE = "ws"; +static const char* KEY = "state"; + +typedef struct { + uint32_t version; + ws_state_t state; +} ws_state_blob_t; + +esp_err_t ws_state_save(const ws_state_t* state) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(NAMESPACE, NVS_READWRITE, &h); + if (err != ESP_OK) { + ESP_LOGE(TAG, "nvs_open failed: %d", err); + return err; + } + + ws_state_blob_t blob = {.version = WS_STATE_SCHEMA_HASH, .state = *state}; + err = nvs_set_blob(h, KEY, &blob, sizeof(blob)); + if (err == ESP_OK) { + err = nvs_commit(h); + } + nvs_close(h); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "nvs_set_blob/commit failed: %d", err); + } + return err; +} + +esp_err_t ws_state_load(ws_state_t* out_state) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(NAMESPACE, NVS_READONLY, &h); + if (err != ESP_OK) { + return err; + } + + ws_state_blob_t blob; + size_t len = sizeof(blob); + err = nvs_get_blob(h, KEY, &blob, &len); + nvs_close(h); + if (err != ESP_OK) { + return err; + } + if (len != sizeof(blob) || blob.version != WS_STATE_SCHEMA_HASH) { + return ESP_ERR_INVALID_VERSION; + } + + *out_state = blob.state; + return ESP_OK; +} diff --git a/main/state_version.h.in b/main/state_version.h.in new file mode 100644 index 0000000..42e0874 --- /dev/null +++ b/main/state_version.h.in @@ -0,0 +1,3 @@ +#pragma once +// Generated at build time from include/state_params.i +#define WS_STATE_SCHEMA_HASH 0x@STATE_SCHEMA_HASH@u diff --git a/main/tcp_server.c b/main/tcp_server.c index 237ed97..a8c4db9 100644 --- a/main/tcp_server.c +++ b/main/tcp_server.c @@ -164,6 +164,8 @@ static void handle_set_cmd( sockbuf_write(sockbuf, "Unknown attribute: '"); sockbuf_write(sockbuf, key); sockbuf_write(sockbuf, "'\n"); + } else { + ws_state_save(&ws_params->state); } xSemaphoreGive(ws_params->state_lock); diff --git a/main/ws2812b_writer.c b/main/ws2812b_writer.c index 8bf0d91..50d89b5 100644 --- a/main/ws2812b_writer.c +++ b/main/ws2812b_writer.c @@ -122,7 +122,6 @@ void calculate_colors(const ws_state_t* state, ws2812b_buffer_t* buffer) portTASK_FUNCTION(ws2812b_write_task, params) { ws_params_t* ws_params = (ws_params_t*)params; - reset_parameters(ws_params); ws2812b_buffer_t* buffer = ws2812b_new_buffer(SIZE); |