feat: implement Wi-Fi provisioning and persistent configuration
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "maze32_config_store.c" "maze32_wifi_config.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES nvs_flash
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef MAZE32_CONFIG_STORE_H
|
||||
#define MAZE32_CONFIG_STORE_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "maze32_wifi_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
esp_err_t maze32_config_store_init(void);
|
||||
esp_err_t maze32_config_store_load(maze32_wifi_credentials_t *credentials);
|
||||
esp_err_t maze32_config_store_save(const maze32_wifi_credentials_t *credentials);
|
||||
esp_err_t maze32_config_store_clear(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef MAZE32_WIFI_CONFIG_H
|
||||
#define MAZE32_WIFI_CONFIG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAZE32_WIFI_CONFIG_SCHEMA_VERSION 1U
|
||||
#define MAZE32_WIFI_SSID_MAX_BYTES 32U
|
||||
#define MAZE32_WIFI_PASSWORD_MAX_BYTES 63U
|
||||
|
||||
typedef struct {
|
||||
char ssid[MAZE32_WIFI_SSID_MAX_BYTES + 1U];
|
||||
char password[MAZE32_WIFI_PASSWORD_MAX_BYTES + 1U];
|
||||
} maze32_wifi_credentials_t;
|
||||
|
||||
typedef enum {
|
||||
MAZE32_WIFI_CONFIG_VALID = 0,
|
||||
MAZE32_WIFI_CONFIG_INVALID_SSID,
|
||||
MAZE32_WIFI_CONFIG_INVALID_PASSWORD,
|
||||
} maze32_wifi_config_validation_t;
|
||||
|
||||
typedef int (*maze32_reconfiguration_guard_fn)(void *context);
|
||||
typedef int (*maze32_credentials_save_fn)(const maze32_wifi_credentials_t *credentials,
|
||||
void *context);
|
||||
typedef int (*maze32_credentials_clear_fn)(void *context);
|
||||
|
||||
maze32_wifi_config_validation_t maze32_wifi_credentials_validate(
|
||||
const maze32_wifi_credentials_t *credentials);
|
||||
int maze32_wifi_config_apply(const maze32_wifi_credentials_t *credentials,
|
||||
maze32_reconfiguration_guard_fn guard,
|
||||
maze32_credentials_save_fn save,
|
||||
void *context);
|
||||
int maze32_wifi_config_reset(maze32_reconfiguration_guard_fn guard,
|
||||
maze32_credentials_clear_fn clear,
|
||||
void *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "maze32_config_store.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
static const char *NAMESPACE = "maze32";
|
||||
static const char *SCHEMA_KEY = "cfg_ver";
|
||||
static const char *SSID_KEY = "wifi_ssid";
|
||||
static const char *PASSWORD_KEY = "wifi_pass";
|
||||
|
||||
esp_err_t maze32_config_store_init(void)
|
||||
{
|
||||
esp_err_t result = nvs_flash_init();
|
||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
result = nvs_flash_erase();
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_flash_init();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t maze32_config_store_load(maze32_wifi_credentials_t *credentials)
|
||||
{
|
||||
if (credentials == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = nvs_open(NAMESPACE, NVS_READONLY, &handle);
|
||||
if (result == ESP_ERR_NVS_NOT_FOUND) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t schema_version = 0U;
|
||||
result = nvs_get_u32(handle, SCHEMA_KEY, &schema_version);
|
||||
if (result == ESP_OK && schema_version != MAZE32_WIFI_CONFIG_SCHEMA_VERSION) {
|
||||
result = ESP_ERR_INVALID_VERSION;
|
||||
}
|
||||
|
||||
maze32_wifi_credentials_t loaded = {0};
|
||||
size_t ssid_size = sizeof(loaded.ssid);
|
||||
size_t password_size = sizeof(loaded.password);
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_get_str(handle, SSID_KEY, loaded.ssid, &ssid_size);
|
||||
}
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_get_str(handle, PASSWORD_KEY, loaded.password, &password_size);
|
||||
}
|
||||
nvs_close(handle);
|
||||
|
||||
if (result == ESP_ERR_NVS_NOT_FOUND) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (result == ESP_OK &&
|
||||
maze32_wifi_credentials_validate(&loaded) != MAZE32_WIFI_CONFIG_VALID) {
|
||||
result = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (result == ESP_OK) {
|
||||
memcpy(credentials, &loaded, sizeof(*credentials));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t maze32_config_store_save(const maze32_wifi_credentials_t *credentials)
|
||||
{
|
||||
if (maze32_wifi_credentials_validate(credentials) != MAZE32_WIFI_CONFIG_VALID) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = nvs_open(NAMESPACE, NVS_READWRITE, &handle);
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = nvs_set_str(handle, SSID_KEY, credentials->ssid);
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_set_str(handle, PASSWORD_KEY, credentials->password);
|
||||
}
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_set_u32(handle, SCHEMA_KEY, MAZE32_WIFI_CONFIG_SCHEMA_VERSION);
|
||||
}
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t maze32_config_store_clear(void)
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = nvs_open(NAMESPACE, NVS_READWRITE, &handle);
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
result = nvs_erase_all(handle);
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "maze32_wifi_config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static size_t bounded_length(const char *value, size_t capacity)
|
||||
{
|
||||
size_t length = 0U;
|
||||
while (length < capacity && value[length] != '\0') {
|
||||
++length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int has_control_bytes(const char *value)
|
||||
{
|
||||
const unsigned char *cursor = (const unsigned char *)value;
|
||||
while (*cursor != '\0') {
|
||||
if (*cursor < 0x20U || *cursor == 0x7fU) {
|
||||
return 1;
|
||||
}
|
||||
++cursor;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
maze32_wifi_config_validation_t maze32_wifi_credentials_validate(
|
||||
const maze32_wifi_credentials_t *credentials)
|
||||
{
|
||||
if (credentials == NULL) {
|
||||
return MAZE32_WIFI_CONFIG_INVALID_SSID;
|
||||
}
|
||||
|
||||
size_t ssid_length = bounded_length(credentials->ssid, sizeof(credentials->ssid));
|
||||
if (ssid_length == 0U || ssid_length > MAZE32_WIFI_SSID_MAX_BYTES ||
|
||||
has_control_bytes(credentials->ssid)) {
|
||||
return MAZE32_WIFI_CONFIG_INVALID_SSID;
|
||||
}
|
||||
|
||||
size_t password_length = bounded_length(credentials->password, sizeof(credentials->password));
|
||||
if (password_length > MAZE32_WIFI_PASSWORD_MAX_BYTES ||
|
||||
(password_length > 0U && password_length < 8U) ||
|
||||
has_control_bytes(credentials->password)) {
|
||||
return MAZE32_WIFI_CONFIG_INVALID_PASSWORD;
|
||||
}
|
||||
|
||||
return MAZE32_WIFI_CONFIG_VALID;
|
||||
}
|
||||
|
||||
int maze32_wifi_config_apply(const maze32_wifi_credentials_t *credentials,
|
||||
maze32_reconfiguration_guard_fn guard,
|
||||
maze32_credentials_save_fn save,
|
||||
void *context)
|
||||
{
|
||||
if (maze32_wifi_credentials_validate(credentials) != MAZE32_WIFI_CONFIG_VALID ||
|
||||
guard == NULL || save == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (guard(context) != 0) {
|
||||
return -2;
|
||||
}
|
||||
return save(credentials, context) == 0 ? 0 : -3;
|
||||
}
|
||||
|
||||
int maze32_wifi_config_reset(maze32_reconfiguration_guard_fn guard,
|
||||
maze32_credentials_clear_fn clear,
|
||||
void *context)
|
||||
{
|
||||
if (guard == NULL || clear == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (guard(context) != 0) {
|
||||
return -2;
|
||||
}
|
||||
return clear(context) == 0 ? 0 : -3;
|
||||
}
|
||||
Reference in New Issue
Block a user