8#define LOG_TAG "CONFIG"
12#include "freertos/FreeRTOS.h"
13#include "freertos/semphr.h"
23#define NVS_NAMESPACE "app_config"
28#define APP_CONFIG_MAGIC 0x43444D58
29#define APP_CONFIG_VERSION 4
123 snprintf(
s_config.wifi_sta.password,
sizeof(
s_config.wifi_sta.password),
"%s",
128 snprintf(
s_config.wifi_ap.password,
sizeof(
s_config.wifi_ap.password),
"%s",
138 LOGW(
"Component already initialized.");
144 LOGE(
"Failed to create configuration mutex.");
145 return ESP_ERR_NO_MEM;
149 esp_err_t err = nvs_open(
NVS_NAMESPACE, NVS_READWRITE, &handle);
151 if (err == ESP_ERR_NVS_NOT_FOUND) {
152 LOGW(
"NVS namespace missing. Staging factory defaults.");
156 esp_err_to_name(err));
162 size_t size =
sizeof(config_storage_t);
165 if (err == ESP_ERR_NVS_NOT_FOUND) {
166 LOGI(
"No configuration blob found. Initializing defaults.");
168 }
else if (err != ESP_OK) {
169 LOGE(
"NVS read error: 0x%X. Falling back to defaults.", err);
171 }
else if (size !=
sizeof(config_storage_t)) {
172 LOGW(
"Configuration size mismatch (%u vs %u). Resetting to defaults.",
173 (
unsigned int)size, (
unsigned int)
sizeof(config_storage_t));
176 LOGW(
"Configuration magic mismatch (0x%08X). Data corrupted. Resetting.",
180 LOGW(
"Configuration version mismatch (%u vs %u). Upgrading/Resetting.",
184 LOGI(
"Configuration loaded successfully. Magic and Version match.");
200 LOGI(
"Factory defaults staged in RAM.");
206 return ESP_ERR_NVS_NOT_INITIALIZED;
211 LOGI(
"Flash save skipped: No changes detected.");
216 esp_err_t err = nvs_open(
NVS_NAMESPACE, NVS_READWRITE, &handle);
219 LOGE(
"Failed to open NVS for saving: 0x%X", err);
225 err = nvs_commit(handle);
232 LOGI(
"Configuration successfully persisted to NVS.");
234 LOGE(
"Failed to write/commit config to NVS: 0x%X", err);
253 LOGI(
"Setting connection type to %d", (
int)conn);
294 uint8_t brightness =
s_config.led_brightness;
302 LOGI(
"Setting LED brightness to %u", (
unsigned int)brightness);
304 if (
s_config.led_brightness == brightness) {
308 s_config.led_brightness = brightness;
322 uint16_t universe =
s_config.dmx_universes[port_index];
332 if (
s_config.dmx_universes[port_index] == universe) {
336 s_config.dmx_universes[port_index] = universe;
357 if (
s_config.dmx_directions[port_index] == direction) {
361 s_config.dmx_directions[port_index] = direction;
371 memset(dest, 0,
sizeof(wifi_config_t));
372 memcpy(dest->sta.ssid,
s_config.wifi_sta.ssid,
374 memcpy(dest->sta.password,
s_config.wifi_sta.password,
375 sizeof(
s_config.wifi_sta.password));
383 if (strnlen((
const char *)src->sta.ssid, 32) == 32 ||
384 strnlen((
const char *)src->sta.password, 64) == 64) {
385 LOGE(
"Wi-Fi credentials are not null-terminated or too long!");
389 if (memcmp(
s_config.wifi_sta.ssid, src->sta.ssid,
390 sizeof(
s_config.wifi_sta.ssid)) == 0 &&
391 memcmp(
s_config.wifi_sta.password, src->sta.password,
392 sizeof(
s_config.wifi_sta.password)) == 0) {
396 memcpy(
s_config.wifi_sta.ssid, src->sta.ssid,
sizeof(
s_config.wifi_sta.ssid));
397 memcpy(
s_config.wifi_sta.password, src->sta.password,
398 sizeof(
s_config.wifi_sta.password));
408 memset(dest, 0,
sizeof(wifi_config_t));
409 memcpy(dest->ap.ssid,
s_config.wifi_ap.ssid,
sizeof(
s_config.wifi_ap.ssid));
410 memcpy(dest->ap.password,
s_config.wifi_ap.password,
419 if (strnlen((
const char *)src->ap.ssid, 32) == 32 ||
420 strnlen((
const char *)src->ap.password, 64) == 64) {
421 LOGE(
"Wi-Fi credentials are not null-terminated or too long!");
426 if (memcmp(
s_config.wifi_ap.ssid, src->ap.ssid,
427 sizeof(
s_config.wifi_ap.ssid)) == 0 &&
428 memcmp(
s_config.wifi_ap.password, src->ap.password,
429 sizeof(
s_config.wifi_ap.password)) == 0) {
434 memcpy(
s_config.wifi_ap.password, src->ap.password,
482 uint8_t *target = NULL;
484 target = &
s_config.btn_action_single;
486 target = &
s_config.btn_action_double;
488 target = &
s_config.btn_action_multi;
490 if (target == NULL || *target == (uint8_t)action) {
495 *target = (uint8_t)action;
bool config_set_led_brightness(uint8_t brightness)
Sets the status LED brightness level in RAM.
esp_err_t config_reset_defaults(void)
Resets all configuration settings back to factory defaults.
#define UNLOCK()
Unlocks the configuration mutex after access.
config_ip_method_t config_get_ip_method(void)
Gets the current IP allocation method.
#define NVS_BLOB_KEY
Key under which the entire config blob is stored in NVS.
static bool s_is_dirty
Set to true if any RAM values diverge from the persisted flash storage state.
bool config_set_ip_method(config_ip_method_t method)
Sets the IP assignment method in RAM.
uint8_t config_get_led_brightness(void)
Gets the current status LED brightness level.
bool config_set_wifi_ap_config(const wifi_config_t *src)
Sets the Wi-Fi Access Point mode configuration in RAM.
static config_storage_t s_config
Private runtime memory footprint of the active configuration.
config_connection_t config_get_connection(void)
Gets the current network connection type.
config_direction_t config_get_dmx_direction(uint8_t port_index)
Gets the data direction for a specific port.
bool config_set_dmx_universe(uint8_t port_index, uint16_t universe)
Sets the DMX universe for a specific port in RAM.
uint16_t config_get_dmx_universe(uint8_t port_index)
Gets the configured DMX universe for a specific port.
void config_get_wifi_sta_config(wifi_config_t *dest)
Gets the Wi-Fi Station mode configuration.
bool config_set_dmx_direction(uint8_t port_index, config_direction_t direction)
Sets the data direction for a specific port in RAM.
#define APP_CONFIG_VERSION
config_button_action_t config_get_button_action(app_button_event_t event)
Retrieves the action assigned to a specific button event.
void config_get_wifi_ap_config(wifi_config_t *dest)
Gets the Wi-Fi Access Point mode configuration.
static bool s_is_initialized
Tracks if the configuration component has been successfully initialized.
esp_err_t config_init(void)
Initializes the configuration component.
bool config_set_connection(config_connection_t conn)
Sets the network connection type in RAM.
bool config_set_wifi_sta_config(const wifi_config_t *src)
Sets the Wi-Fi Station mode configuration in RAM.
esp_err_t config_save(void)
Flushes all staged RAM changes permanently to the non-volatile storage.
#define NVS_NAMESPACE
NVS storage namespace for configuration data.
static void load_factory_defaults(void)
Restores all configuration fields to their factory-defined values in RAM.
bool config_set_button_action(app_button_event_t event, config_button_action_t action)
Assigns a new action to a specific button event in RAM.
#define LOCK()
Locks the configuration mutex for exclusive access.
static SemaphoreHandle_t s_config_mutex
Mutex guard ensuring thread-safe operations on the shared configuration context.
Thread-safe configuration component utilizing NVS for ESP32.
#define APP_CONFIG_DEFAULT_LED_BRIGHTNESS
config_button_action_t
Actions that can be dynamically assigned to button events.
#define APP_CONFIG_DEFAULT_IP_METHOD
#define APP_CONFIG_DEFAULT_DMX_DIR
#define APP_CONFIG_DEFAULT_STA_PASSWORD
#define APP_CONFIG_DEFAULT_SINGLE_CLICK_ACT
#define APP_CONFIG_INVALID_UNIVERSE
Error/Invalid indicator for DMX universe.
#define APP_CONFIG_DEFAULT_AP_SSID_PREFIX
#define APP_CONFIG_DEFAULT_CONNECTION
config_connection_t
Network connection medium types.
@ APP_CONFIG_CONN_ETHERNET
app_button_event_t
Supported button event types that can be configured in the system.
@ APP_BUTTON_EVENT_SINGLE_CLICK
@ APP_BUTTON_EVENT_MULTIPLE_CLICK
@ APP_BUTTON_EVENT_DOUBLE_CLICK
#define APP_CONFIG_DEFAULT_DOUBLE_CLICK_ACT
#define APP_CONFIG_DEFAULT_START_UNIVERSE
#define APP_CONFIG_DEFAULT_STA_SSID
config_direction_t
Data direction for dmx-port.
#define APP_CONFIG_DEFAULT_MULTI_CLICK_ACT
#define APP_CONFIG_DEFAULT_AP_PASSWORD
config_ip_method_t
IP assignment method configurations.
#define APP_CONFIG_DMX_PORT_COUNT
Total number of physical DMX ports supported by the hardware.
LED control component with flexible blinking and breathing modes.
void led_set_brightness(uint8_t brightness)
Dynamically updates the LED maximum brightness.
Project-wide logging macros based on ESP-IDF's logging library.
#define LOGW(...)
Log a message at Warning level.
#define LOGI(...)
Log a message at Info level.
#define LOGE(...)
Log a message at Error level.
Internal configuration storage layout. Mirrors the private runtime configuration context state in RAM...
uint8_t btn_action_single
config_direction_t dmx_directions[APP_CONFIG_DMX_PORT_COUNT]
uint8_t btn_action_double
uint16_t dmx_universes[APP_CONFIG_DMX_PORT_COUNT]
config_connection_t connection
config_ip_method_t ip_method
app_wifi_creds_t wifi_sta
WIFI credentials structure for both Station and Access Point modes.