#include #include #include #include #include #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(); }