Move all firmware files to subdirectory

This commit is contained in:
2023-05-21 15:06:44 +01:00
parent 3d8ec33cd3
commit 8c957d043a
46 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "settings.c"
INCLUDE_DIRS "."
REQUIRES console_wrapper fatal nvs_flash
)

View File

@@ -0,0 +1,296 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) Camden Dixie O'Brien
*/
#include "settings.h"
#include "console.h"
#include "fatal.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <stdbool.h>
#include <string.h>
#define TAG "Settings"
#define NAMESPACE "settings"
#define MAX_CALLBACKS 8
typedef enum {
HOSTNAME,
SSID,
PSK,
TIMEZONE,
SNTP_SERVER,
ITEM_COUNT,
} ItemIndex;
typedef struct {
const char *id;
const char *default_value;
char value[SETTINGS_MAX_VALUE_SIZE];
struct {
SettingsCallback funcs[MAX_CALLBACKS];
unsigned count;
} callbacks;
} Item;
static Item state[ITEM_COUNT] = {
[HOSTNAME] = {
.id = "hostname",
.default_value = CONFIG_DEFAULT_HOSTNAME,
},
[SSID] = {
.id = "ssid",
.default_value = CONFIG_DEFAULT_SSID,
},
[PSK] = {
.id = "psk",
.default_value = CONFIG_DEFAULT_PSK,
},
[TIMEZONE] = {
.id = "timezone",
.default_value = CONFIG_DEFAULT_TIMEZONE,
},
[SNTP_SERVER] = {
.id = "sntp-server",
.default_value = CONFIG_DEFAULT_SNTP_SERVER,
},
};
static bool load(ItemIndex item)
{
esp_err_t error;
nvs_handle_t handle;
error = nvs_open(NAMESPACE, NVS_READONLY, &handle);
if (error == ESP_ERR_NVS_NOT_FOUND)
return false;
if (error != ESP_OK) {
ESP_LOGE(TAG, "Error opening NVS: %04x", error);
return false;
}
size_t size = SETTINGS_MAX_VALUE_SIZE;
error = nvs_get_str(handle, state[item].id, state[item].value, &size);
if (error == ESP_ERR_NVS_NOT_FOUND) {
nvs_close(handle);
return false;
} else if (error != ESP_OK) {
ESP_LOGE(
TAG, "Error loading %s from storage: %04x", state[item].id,
error);
nvs_close(handle);
return false;
}
nvs_close(handle);
return true;
}
static void save(ItemIndex item)
{
esp_err_t error;
nvs_handle_t handle;
error = nvs_open(NAMESPACE, NVS_READWRITE, &handle);
if (error == ESP_ERR_NVS_NOT_FOUND)
return;
if (error != ESP_OK) {
ESP_LOGE(TAG, "Error opening NVS: %04x", error);
return;
}
error = nvs_set_str(handle, state[item].id, state[item].value);
if (error != ESP_OK) {
ESP_LOGE(
TAG, "Error loading %s from storage: %04x", state[item].id,
error);
nvs_close(handle);
return;
}
error = nvs_commit(handle);
if (error != ESP_OK)
ESP_LOGE(TAG, "Error commiting NVS update: %04x", error);
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 >= SETTINGS_MAX_VALUE_SIZE) {
ESP_LOGW(
TAG, "%s value \"%s\" exceeds maximum size; truncated",
state[item].id, value);
len = SETTINGS_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, SettingsCallback 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;
}
}
static int command_func(int argc, char **argv)
{
if (argc == 1) {
char buffer[SETTINGS_MAX_VALUE_SIZE];
for (unsigned i = 0; i < ITEM_COUNT; ++i) {
(void)get(i, buffer, SETTINGS_MAX_VALUE_SIZE);
printf("%-15s %s\n", state[i].id, buffer);
}
return 0;
} else if (argc == 2) {
for (unsigned i = 0; i < ITEM_COUNT; ++i) {
if (strcmp(state[i].id, argv[1]) != 0)
continue;
char buffer[SETTINGS_MAX_VALUE_SIZE];
(void)get(i, buffer, SETTINGS_MAX_VALUE_SIZE);
printf("%s\n", buffer);
return 0;
}
printf("Setting not found\n");
return 1;
} else if (argc == 3) {
for (unsigned i = 0; i < ITEM_COUNT; ++i) {
if (strcmp(state[i].id, argv[1]) != 0)
continue;
set(i, argv[2]);
return 0;
}
printf("Setting not found\n");
return 1;
} else {
printf("Invalid number of arguments\n");
return 1;
}
}
void settings_init()
{
for (ItemIndex item = (ItemIndex)0; item < ITEM_COUNT; ++item) {
if (!load(item)) {
set(item, state[item].default_value);
save(item);
}
}
console_register(
"settings", "Get or set a setting",
"settings [id] OR settings <id> <value>", command_func);
}
void settings_set_hostname(const char *hostname)
{
set(HOSTNAME, hostname);
}
size_t settings_get_hostname(char *buffer, size_t buffer_size)
{
return get(HOSTNAME, buffer, buffer_size);
}
void settings_add_hostname_callback(SettingsCallback callback)
{
add_callback(HOSTNAME, callback);
}
void settings_set_ssid(const char *ssid)
{
set(SSID, ssid);
}
size_t settings_get_ssid(char *buffer, size_t buffer_size)
{
return get(SSID, buffer, buffer_size);
}
void settings_add_ssid_callback(SettingsCallback callback)
{
add_callback(SSID, callback);
}
void settings_set_psk(const char *psk)
{
set(PSK, psk);
}
size_t settings_get_psk(char *buffer, size_t buffer_size)
{
return get(PSK, buffer, buffer_size);
}
void settings_add_psk_callback(SettingsCallback callback)
{
add_callback(PSK, callback);
}
void settings_set_timezone(const char *timezone)
{
set(TIMEZONE, timezone);
}
size_t settings_get_timezone(char *buffer, size_t buffer_size)
{
return get(TIMEZONE, buffer, buffer_size);
}
void settings_add_timezone_callback(SettingsCallback callback)
{
add_callback(TIMEZONE, callback);
}
void settings_set_sntp_server(const char *sntp_server)
{
set(SNTP_SERVER, sntp_server);
}
size_t settings_get_sntp_server(char *buffer, size_t buffer_size)
{
return get(SNTP_SERVER, buffer, buffer_size);
}
void settings_add_sntp_server_callback(SettingsCallback callback)
{
add_callback(SNTP_SERVER, callback);
}

View File

@@ -0,0 +1,167 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) Camden Dixie O'Brien
*/
#ifndef SETTINGS_H
#define SETTINGS_H
#include <stddef.h>
#define SETTINGS_MAX_VALUE_SIZE 32U
/**
* Callback type for settings updates
*/
typedef void (*SettingsCallback)(const char *value);
/**
* Initialize the settings module.
*
* If there are saved settings, they will be loaded. Otherwise,
* the default settings will be loaded and saved.
*/
void settings_init(void);
/**
* Set the device's hostname.
*
* The argument should be a null-terminated string. If the maximum
* length is exceeded, the value will still be used, but will be
* truncated.
*/
void settings_set_hostname(const char *hostname);
/**
* Write the device's hostname into the given buffer.
*
* The length of the hostname is returned. If the value's size exceeds
* the size of the buffer, nothing will be written to the buffer but
* the length is still returned.
*/
size_t settings_get_hostname(char *buffer, size_t buffer_size);
/**
* Add a callback for hostname updates.
*
* The function specified in the argument will be invoked whenever
* the hostname is updated, with the new value as its argument. The
* lifetime of the passed argument will be static, but the value may
* be modified once the callback returns.
*/
void settings_add_hostname_callback(SettingsCallback callback);
/**
* Set the SSID of the WiFi network.
*
* The argument should be a null-terminated string. If the maximum
* length is exceeded, the value will still be used, but will be
* truncated.
*/
void settings_set_ssid(const char *ssid);
/**
* Write the SSID of the WiFi network into the given buffer.
*
* The length of the SSID is returned. If the value's size exceeds
* the size of the buffer, nothing will be written to the buffer but
* the length is still returned.
*/
size_t settings_get_ssid(char *buffer, size_t buffer_size);
/**
* Add a callback for SSID updates.
*
* The function specified in the argument will be invoked whenever
* the SSID is updated, with the new value as its argument. The
* lifetime of the passed argument will be static, but the value may
* be modified once the callback returns.
*/
void settings_add_ssid_callback(SettingsCallback callback);
/**
* Set the PSK for the WiFi network.
*
* The argument should be a null-terminated string. If the maximum
* length is exceeded, the value will still be used, but will be
* truncated.
*/
void settings_set_psk(const char *psk);
/**
* Write the PSK for the WiFi network into the given buffer.
*
* The length of the psk is returned. If the value's size exceeds
* the size of the buffer, nothing will be written to the buffer but
* the length is still returned.
*/
size_t settings_get_psk(char *buffer, size_t buffer_size);
/**
* Add a callback for PSK updates.
*
* The function specified in the argument will be invoked whenever the
* PSK is updated, with the new value as its argument. The lifetime of
* the passed argument will be static, but the value may be modified
* once the callback returns.
*/
void settings_add_psk_callback(SettingsCallback callback);
/**
* Set the timezone.
*
* The argument should be a null-terminated string, containing a
* timezone spec in the format expected by tzset(). If the maximum
* length is exceeded, the value will still be used, but will be
* truncated.
*/
void settings_set_timezone(const char *psk);
/**
* Write the timezone into the given buffer.
*
* The length of the timezone is returned. If the value's size exceeds
* the size of the buffer, nothing will be written to the buffer but
* the length is still returned.
*/
size_t settings_get_timezone(char *buffer, size_t buffer_size);
/**
* Add a callback for timezone updates.
*
* The function specified in the argument will be invoked whenever the
* timezone is updated, with the new value as its argument. The
* lifetime of the passed argument will be static, but the value may
* be modified once the callback returns.
*/
void settings_add_timezone_callback(SettingsCallback callback);
/**
* Set the SNTP server URL.
*
* The argument should be a null-terminated string, containing a valid
* domain name for an SNTP server. If the maximum length is exceeded,
* the value will still be used, but will be truncated.
*/
void settings_set_sntp_server(const char *sntp_server);
/**
* Write the SNTP server URL into the given buffer.
*
* The length of the SNTP server domain is returned. If the value's
* size exceeds the size of the buffer, nothing will be written to the
* buffer but the length is still returned.
*/
size_t settings_get_sntp_server(char *buffer, size_t buffer_size);
/**
* Add a callback for SNTP server URL updates.
*
* The function specified in the argument will be invoked whenever the
* SNTP server is updated, with the new value as its argument. The
* lifetime of the passed argument will be static, but the value may
* be modified once the callback returns.
*/
void settings_add_sntp_server_callback(SettingsCallback callback);
#endif