Restructure config module for easier addition of items
This commit is contained in:
parent
10c77203ab
commit
d7f1c2ace0
@ -15,28 +15,28 @@
|
|||||||
#define TAG "Config"
|
#define TAG "Config"
|
||||||
|
|
||||||
#define NAMESPACE "config"
|
#define NAMESPACE "config"
|
||||||
#define MAX_CONSUMERS 8
|
#define MAX_CALLBACKS 8
|
||||||
|
|
||||||
#define DEFAULT_HOSTNAME "bedside-clock"
|
typedef enum {
|
||||||
#define HOSTNAME_KEY "hostname"
|
HOSTNAME,
|
||||||
|
ITEM_COUNT,
|
||||||
|
} ItemIndex;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char hostname[MAX_HOSTNAME_SIZE];
|
const char *id;
|
||||||
} Config;
|
const char *default_value;
|
||||||
|
char value[CONFIG_MAX_VALUE_SIZE];
|
||||||
|
struct {
|
||||||
|
ConfigCallback funcs[MAX_CALLBACKS];
|
||||||
|
unsigned count;
|
||||||
|
} callbacks;
|
||||||
|
} Item;
|
||||||
|
|
||||||
typedef struct {
|
static Item state[ITEM_COUNT] = {
|
||||||
ConfigStringCallback callbacks[MAX_CONSUMERS];
|
[HOSTNAME] = { .id = "hostname", .default_value = "bedside-clock" },
|
||||||
unsigned count;
|
};
|
||||||
} StringConsumers;
|
|
||||||
|
|
||||||
typedef struct {
|
static bool load(ItemIndex item)
|
||||||
Config config;
|
|
||||||
StringConsumers hostname_consumers;
|
|
||||||
} State;
|
|
||||||
|
|
||||||
static State state;
|
|
||||||
|
|
||||||
static bool load_hostname()
|
|
||||||
{
|
{
|
||||||
esp_err_t error;
|
esp_err_t error;
|
||||||
|
|
||||||
@ -49,10 +49,12 @@ static bool load_hostname()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = MAX_HOSTNAME_SIZE;
|
size_t size = CONFIG_MAX_VALUE_SIZE;
|
||||||
error = nvs_get_str(handle, HOSTNAME_KEY, state.config.hostname, &size);
|
error = nvs_get_str(handle, state[item].id, state[item].value, &size);
|
||||||
if (error != ESP_OK) {
|
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);
|
nvs_close(handle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ static bool load_hostname()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_hostname()
|
static void save(ItemIndex item)
|
||||||
{
|
{
|
||||||
esp_err_t error;
|
esp_err_t error;
|
||||||
|
|
||||||
@ -74,9 +76,11 @@ static void save_hostname()
|
|||||||
return;
|
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) {
|
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);
|
nvs_close(handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -88,6 +92,58 @@ static void save_hostname()
|
|||||||
nvs_close(handle);
|
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()
|
void config_init()
|
||||||
{
|
{
|
||||||
esp_err_t error;
|
esp_err_t error;
|
||||||
@ -104,56 +160,25 @@ void config_init()
|
|||||||
FATAL();
|
FATAL();
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&state, 0, sizeof(state));
|
for (ItemIndex item = (ItemIndex)0; item < ITEM_COUNT; ++item) {
|
||||||
|
if (!load(item)) {
|
||||||
if (!load_hostname()) {
|
set(item, state[item].default_value);
|
||||||
config_set_hostname(DEFAULT_HOSTNAME);
|
save(item);
|
||||||
save_hostname();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_set_hostname(const char *hostname)
|
void config_set_hostname(const char *hostname)
|
||||||
{
|
{
|
||||||
if (hostname == NULL) {
|
set(HOSTNAME, hostname);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t config_get_hostname(char *buffer, size_t buffer_size)
|
size_t config_get_hostname(char *buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
size_t len = strlen(state.config.hostname);
|
return get(HOSTNAME, buffer, buffer_size);
|
||||||
if (len < buffer_size) {
|
|
||||||
memcpy(buffer, state.config.hostname, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_add_hostname_consumer(ConfigStringCallback callback)
|
void config_add_hostname_callback(ConfigCallback callback)
|
||||||
{
|
{
|
||||||
if (callback == NULL) {
|
add_callback(HOSTNAME, callback);
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#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.
|
* 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,
|
* If there is a saved configuration, it will be loaded. Otherwise,
|
||||||
* the default configuration will be loaded and saved.
|
* the default configuration will be loaded and saved.
|
||||||
*/
|
*/
|
||||||
void config_init();
|
void config_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the device's hostname.
|
* 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
|
* lifetime of the passed argument will be static, but the value may
|
||||||
* be modified once the callback returns.
|
* be modified once the callback returns.
|
||||||
*/
|
*/
|
||||||
void config_add_hostname_callback(ConfigStringCallback callback);
|
void config_add_hostname_callback(ConfigCallback callback);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user