diff --git a/components/config/config.c b/components/config/config.c index 09b67c6..f06ea3f 100644 --- a/components/config/config.c +++ b/components/config/config.c @@ -15,28 +15,28 @@ #define TAG "Config" #define NAMESPACE "config" -#define MAX_CONSUMERS 8 +#define MAX_CALLBACKS 8 -#define DEFAULT_HOSTNAME "bedside-clock" -#define HOSTNAME_KEY "hostname" +typedef enum { + HOSTNAME, + ITEM_COUNT, +} ItemIndex; typedef struct { - char hostname[MAX_HOSTNAME_SIZE]; -} Config; + const char *id; + const char *default_value; + char value[CONFIG_MAX_VALUE_SIZE]; + struct { + ConfigCallback funcs[MAX_CALLBACKS]; + unsigned count; + } callbacks; +} Item; -typedef struct { - ConfigStringCallback callbacks[MAX_CONSUMERS]; - unsigned count; -} StringConsumers; +static Item state[ITEM_COUNT] = { + [HOSTNAME] = { .id = "hostname", .default_value = "bedside-clock" }, +}; -typedef struct { - Config config; - StringConsumers hostname_consumers; -} State; - -static State state; - -static bool load_hostname() +static bool load(ItemIndex item) { esp_err_t error; @@ -49,10 +49,12 @@ static bool load_hostname() return false; } - size_t size = MAX_HOSTNAME_SIZE; - error = nvs_get_str(handle, HOSTNAME_KEY, state.config.hostname, &size); + size_t size = CONFIG_MAX_VALUE_SIZE; + error = nvs_get_str(handle, state[item].id, state[item].value, &size); if (error != ESP_OK) { - ESP_LOGE(TAG, "Error loading hostname from storage: %04x", error); + ESP_LOGE( + TAG, "Error loading %s from storage: %04x", state[item].id, + error); nvs_close(handle); return false; } @@ -61,7 +63,7 @@ static bool load_hostname() return true; } -static void save_hostname() +static void save(ItemIndex item) { esp_err_t error; @@ -74,9 +76,11 @@ static void save_hostname() return; } - error = nvs_set_str(handle, HOSTNAME_KEY, state.config.hostname); + error = nvs_set_str(handle, state[item].id, state[item].value); if (error != ESP_OK) { - ESP_LOGE(TAG, "Error loading hostname from storage: %04x", error); + ESP_LOGE( + TAG, "Error loading %s from storage: %04x", state[item].id, + error); nvs_close(handle); return; } @@ -88,6 +92,58 @@ static void save_hostname() nvs_close(handle); } +static void set(ItemIndex item, const char *value) +{ + if (value == NULL) { + ESP_LOGW( + TAG, "Attempt to set %s to null pointer; ignored", + state[item].id); + return; + } + + size_t len = strlen(value); + if (len >= CONFIG_MAX_VALUE_SIZE) { + ESP_LOGW( + TAG, "%s value \"%s\" exceeds maximum size; truncated", + state[item].id, value); + len = CONFIG_MAX_VALUE_SIZE - 1; + } + + memcpy(state[item].value, value, len); + state[item].value[len] = '\0'; + + save(item); + for (unsigned i = 0; i < state[item].callbacks.count; ++i) + state[item].callbacks.funcs[i](state[item].value); +} + +static size_t get(ItemIndex item, char *buffer, size_t buffer_size) +{ + size_t len = strlen(state[item].value); + if (len < buffer_size) { + memcpy(buffer, state[item].value, len); + buffer[len] = '\0'; + } + return len; +} + +static void add_callback(ItemIndex item, ConfigCallback callback) +{ + if (callback == NULL) { + ESP_LOGW( + TAG, "Attempt to add null callback for %s; ignored", + state[item].id); + } else if (state[item].callbacks.count >= MAX_CALLBACKS) { + ESP_LOGE( + TAG, "Max callbacks exceeded for %s; callback discarded", + state[item].id); + } else { + const unsigned pos = state[item].callbacks.count; + state[item].callbacks.funcs[pos] = callback; + ++state[item].callbacks.count; + } +} + void config_init() { esp_err_t error; @@ -104,56 +160,25 @@ void config_init() FATAL(); } - memset(&state, 0, sizeof(state)); - - if (!load_hostname()) { - config_set_hostname(DEFAULT_HOSTNAME); - save_hostname(); + for (ItemIndex item = (ItemIndex)0; item < ITEM_COUNT; ++item) { + if (!load(item)) { + set(item, state[item].default_value); + save(item); + } } } void config_set_hostname(const char *hostname) { - if (hostname == NULL) { - ESP_LOGW(TAG, "Null pointer passed to %s(); ignored", __func__); - return; - } - size_t len = strlen(hostname); - if (len >= MAX_HOSTNAME_SIZE) { - ESP_LOGW( - TAG, "Hostname \"%s\" exceeds maximum size; truncated", - hostname); - len = MAX_HOSTNAME_SIZE - 1; - } - - memcpy(state.config.hostname, hostname, len); - state.config.hostname[len] = '\0'; - - save_hostname(); - - for (unsigned i = 0; i < state.hostname_consumers.count; ++i) - state.hostname_consumers.callbacks[i](state.config.hostname); + set(HOSTNAME, hostname); } size_t config_get_hostname(char *buffer, size_t buffer_size) { - size_t len = strlen(state.config.hostname); - if (len < buffer_size) { - memcpy(buffer, state.config.hostname, len); - buffer[len] = '\0'; - } - return len; + return get(HOSTNAME, buffer, buffer_size); } -void config_add_hostname_consumer(ConfigStringCallback callback) +void config_add_hostname_callback(ConfigCallback callback) { - if (callback == NULL) { - } else if (state.hostname_consumers.count >= MAX_CONSUMERS) { - ESP_LOGE( - TAG, "Max consumers exceeded for hostname; callback discarded"); - } else { - state.hostname_consumers.callbacks[state.hostname_consumers.count] - = callback; - ++state.hostname_consumers.count; - } + add_callback(HOSTNAME, callback); } diff --git a/components/config/config.h b/components/config/config.h index b8ad893..869e26d 100644 --- a/components/config/config.h +++ b/components/config/config.h @@ -8,12 +8,12 @@ #include -#define MAX_HOSTNAME_SIZE 32 +#define CONFIG_MAX_VALUE_SIZE 32U /** - * Callback type for consumers of string settings. + * Callback type for config updates */ -typedef void (*ConfigStringCallback)(const char *value); +typedef void (*ConfigCallback)(const char *value); /** * Initialize the configuration module. @@ -21,7 +21,7 @@ typedef void (*ConfigStringCallback)(const char *value); * If there is a saved configuration, it will be loaded. Otherwise, * the default configuration will be loaded and saved. */ -void config_init(); +void config_init(void); /** * Set the device's hostname. @@ -49,6 +49,6 @@ size_t config_get_hostname(char *buffer, size_t buffer_size); * lifetime of the passed argument will be static, but the value may * be modified once the callback returns. */ -void config_add_hostname_callback(ConfigStringCallback callback); +void config_add_hostname_callback(ConfigCallback callback); #endif