feat: add settings mgmt and split debug transport snippets

This commit is contained in:
2026-05-11 16:19:37 +02:00
parent 3fed249430
commit 5ae098962d
15 changed files with 366 additions and 56 deletions

View File

@@ -0,0 +1,239 @@
#include <zephyr/settings/settings.h>
#include <zephyr/logging/log.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "settings_mgmt.h"
LOG_MODULE_REGISTER(settings_mgmt, LOG_LEVEL_INF);
/* Sanity check limits */
#define VOL_MIN 0
#define VOL_MAX 100
#define SHUFFLE_MODE_MIN 0
#define SHUFFLE_MODE_MAX 1
#define BLE_TIMEOUT_MIN 1000
#define BLE_TIMEOUT_MAX 0xFFFFFFFF
#define BLE_INTERVAL_MIN 10
#define BLE_INTERVAL_MAX 10000
#define CHG_MODE_MIN 0
#define CHG_MODE_MAX 2
#define OFF_THRESHOLD_MIN 2900 /* mV, LiPo cut-off */
#define OFF_THRESHOLD_MAX 3500 /* mV, LiPo nominal */
#define ADC_GAIN_MIN -100
#define ADC_GAIN_MAX 100
#define ADC_OFFSET_MIN -1000
#define ADC_OFFSET_MAX 1000
/* The "Source of Truth" in RAM */
struct app_settings_t app_cfg = {
.dev_name = "Edis Buzzer",
.vol = 100, /* 0-100 % */
.shuffle_mode = 0,
.ble_timeout = 0xFFFFFFFF,
.ble_interval = 100,
.chg_mode = 2, /* Auto */
.off_threshold = 3000, /* mV */
.adc_gain = 0,
.adc_offset = 0,
};
static int read_exact(settings_read_cb read_cb, void *cb_arg,
void *dst, size_t expected_len)
{
int rc = read_cb(cb_arg, dst, expected_len);
if (rc < 0) {
return rc;
}
if ((size_t)rc != expected_len) {
return -EINVAL;
}
return 0;
}
/* Sanity check helpers */
static int check_uint8_range(uint8_t val, uint8_t min, uint8_t max,
const char *name)
{
if (val < min || val > max) {
LOG_WRN("%s out of range: %u (valid: %u-%u)", name, val, min, max);
return -EINVAL;
}
return 0;
}
static int check_uint16_range(uint16_t val, uint16_t min, uint16_t max,
const char *name)
{
if (val < min || val > max) {
LOG_WRN("%s out of range: %u (valid: %u-%u)", name, val, min, max);
return -EINVAL;
}
return 0;
}
static int check_uint32_range(uint32_t val, uint32_t min, uint32_t max,
const char *name)
{
if (val < min || val > max) {
LOG_WRN("%s out of range: %u (valid: %u-%u)", name, val, min, max);
return -EINVAL;
}
return 0;
}
static int check_int16_range(int16_t val, int16_t min, int16_t max,
const char *name)
{
if (val < min || val > max) {
LOG_WRN("%s out of range: %d (valid: %d-%d)", name, val, min, max);
return -EINVAL;
}
return 0;
}
/* Callback: Called by settings_load() or settings_runtime_set() */
static int buzzy_settings_set(const char *name, size_t len,
settings_read_cb read_cb, void *cb_arg)
{
const char *next;
int rc;
/* Path matching: "buzzy/sys/name" -> name is "sys/name" here */
if (settings_name_steq(name, "sys/name", &next) && !next) {
rc = read_cb(cb_arg, app_cfg.dev_name, sizeof(app_cfg.dev_name) - 1);
if (rc >= 0) app_cfg.dev_name[rc] = '\0';
return 0;
}
if (settings_name_steq(name, "audio/vol", &next) && !next) {
uint8_t vol;
rc = read_exact(read_cb, cb_arg, &vol, sizeof(vol));
if (rc == 0) {
rc = check_uint8_range(vol, VOL_MIN, VOL_MAX, "audio/vol");
if (rc == 0) {
app_cfg.vol = vol;
}
}
return rc;
}
if ((settings_name_steq(name, "audio/shuffle", &next) ||
settings_name_steq(name, "audio/shuffle_mode", &next)) && !next) {
uint8_t shuffle;
rc = read_exact(read_cb, cb_arg, &shuffle, sizeof(shuffle));
if (rc == 0) {
rc = check_uint8_range(shuffle, SHUFFLE_MODE_MIN, SHUFFLE_MODE_MAX, "shuffle_mode");
if (rc == 0) {
app_cfg.shuffle_mode = shuffle;
}
}
return rc;
}
if (settings_name_steq(name, "ble/to", &next) && !next) {
uint32_t timeout;
rc = read_exact(read_cb, cb_arg, &timeout, sizeof(timeout));
if (rc == 0) {
rc = check_uint32_range(timeout, BLE_TIMEOUT_MIN, BLE_TIMEOUT_MAX, "ble/to");
if (rc == 0) {
app_cfg.ble_timeout = timeout;
}
}
return rc;
}
if ((settings_name_steq(name, "ble/interval", &next) ||
settings_name_steq(name, "ble/int", &next)) && !next) {
uint16_t interval;
rc = read_exact(read_cb, cb_arg, &interval, sizeof(interval));
if (rc == 0) {
rc = check_uint16_range(interval, BLE_INTERVAL_MIN, BLE_INTERVAL_MAX, "ble/interval");
if (rc == 0) {
app_cfg.ble_interval = interval;
}
}
return rc;
}
if ((settings_name_steq(name, "power/chg_mode", &next) ||
settings_name_steq(name, "sys/chg_mode", &next)) && !next) {
uint8_t chg_mode;
rc = read_exact(read_cb, cb_arg, &chg_mode, sizeof(chg_mode));
if (rc == 0) {
rc = check_uint8_range(chg_mode, CHG_MODE_MIN, CHG_MODE_MAX, "chg_mode");
if (rc == 0) {
app_cfg.chg_mode = chg_mode;
}
}
return rc;
}
if ((settings_name_steq(name, "power/off_threshold", &next) ||
settings_name_steq(name, "sys/off_threshold", &next)) && !next) {
uint16_t threshold;
rc = read_exact(read_cb, cb_arg, &threshold, sizeof(threshold));
if (rc == 0) {
rc = check_uint16_range(threshold, OFF_THRESHOLD_MIN, OFF_THRESHOLD_MAX, "off_threshold [mV]");
if (rc == 0) {
app_cfg.off_threshold = threshold;
}
}
return rc;
}
if (settings_name_steq(name, "adc/gain", &next) && !next) {
int16_t gain;
rc = read_exact(read_cb, cb_arg, &gain, sizeof(gain));
if (rc == 0) {
rc = check_int16_range(gain, ADC_GAIN_MIN, ADC_GAIN_MAX, "adc/gain");
if (rc == 0) {
app_cfg.adc_gain = gain;
}
}
return rc;
}
if (settings_name_steq(name, "adc/offset", &next) && !next) {
int16_t offset;
rc = read_exact(read_cb, cb_arg, &offset, sizeof(offset));
if (rc == 0) {
rc = check_int16_range(offset, ADC_OFFSET_MIN, ADC_OFFSET_MAX, "adc/offset");
if (rc == 0) {
app_cfg.adc_offset = offset;
}
}
return rc;
}
return -ENOENT;
}
struct settings_handler buzzy_handler = {
.name = "buzzy",
.h_set = buzzy_settings_set
};
int settings_mgmt_set_by_path(const char *path, const void *value, size_t len)
{
char full_path[64];
snprintf(full_path, sizeof(full_path), "buzzy/%s", path);
/* Schreibt in ZMS UND triggert buzzy_settings_set zur RAM-Aktualisierung */
return settings_runtime_set(full_path, value, len);
}
int settings_mgmt_init(void)
{
int rc = settings_subsys_init();
if (rc) return rc;
rc = settings_register(&buzzy_handler);
if (rc) return rc;
/* Lädt alle gespeicherten Werte aus dem ZMS in die app_cfg Struktur */
return settings_load();
}