diff --git a/firmware/boards/buzzy_nrf52840.conf b/firmware/boards/buzzy_nrf52840.conf index 6126862..f8b0be8 100644 --- a/firmware/boards/buzzy_nrf52840.conf +++ b/firmware/boards/buzzy_nrf52840.conf @@ -1,11 +1,11 @@ -### Console / Logging: RTT -CONFIG_USE_SEGGER_RTT=y -CONFIG_CONSOLE=y -CONFIG_RTT_CONSOLE=y +### Console / Logging: disabled in base board config (enable via debug snippet) +CONFIG_USE_SEGGER_RTT=n +CONFIG_CONSOLE=n +CONFIG_RTT_CONSOLE=n +CONFIG_LOG_BACKEND_RTT=n CONFIG_UART_CONSOLE=n CONFIG_LOG_BACKEND_UART=n -CONFIG_LOG_BACKEND_RTT=y # Keep SPI NOR page layout aligned with generated LittleFS block size (4KB). CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 diff --git a/firmware/boards/nrf52840dk_nrf52840.conf b/firmware/boards/nrf52840dk_nrf52840.conf index f770b15..2620be5 100644 --- a/firmware/boards/nrf52840dk_nrf52840.conf +++ b/firmware/boards/nrf52840dk_nrf52840.conf @@ -1,4 +1,5 @@ -### Console / Logging: UART -CONFIG_UART_CONSOLE=y -CONFIG_LOG_BACKEND_UART=y +### Console / Logging: disabled in base board config (enable via debug snippet) +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_LOG_BACKEND_UART=n CONFIG_LOG_BACKEND_RTT=n diff --git a/firmware/debug_rtt.conf b/firmware/debug_rtt.conf new file mode 100644 index 0000000..d7cb749 --- /dev/null +++ b/firmware/debug_rtt.conf @@ -0,0 +1,8 @@ +### Debug transport: RTT +CONFIG_CONSOLE=y +CONFIG_USE_SEGGER_RTT=y +CONFIG_RTT_CONSOLE=y +CONFIG_LOG_BACKEND_RTT=y + +CONFIG_UART_CONSOLE=n +CONFIG_LOG_BACKEND_UART=n diff --git a/firmware/debug_uart.conf b/firmware/debug_uart.conf new file mode 100644 index 0000000..ca6ca56 --- /dev/null +++ b/firmware/debug_uart.conf @@ -0,0 +1,7 @@ +### Debug transport: UART +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_LOG_BACKEND_UART=y + +CONFIG_RTT_CONSOLE=n +CONFIG_LOG_BACKEND_RTT=n diff --git a/firmware/libs/CMakeLists.txt b/firmware/libs/CMakeLists.txt index 52a299a..3735de5 100644 --- a/firmware/libs/CMakeLists.txt +++ b/firmware/libs/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(settings_mgmt) add_subdirectory(fw_mgmt) add_subdirectory(fs_mgmt) add_subdirectory(ble_mgmt) diff --git a/firmware/libs/Kconfig b/firmware/libs/Kconfig index 89388ed..7a96d6f 100644 --- a/firmware/libs/Kconfig +++ b/firmware/libs/Kconfig @@ -1,6 +1,7 @@ +rsource "settings_mgmt/Kconfig" rsource "fw_mgmt/Kconfig" rsource "fs_mgmt/Kconfig" rsource "ble_mgmt/Kconfig" rsource "buzz_proto/Kconfig" rsource "audio/Kconfig" -rsource "event_mgmt/Kconfig" \ No newline at end of file +rsource "event_mgmt/Kconfig" diff --git a/firmware/libs/ble_mgmt/Kconfig b/firmware/libs/ble_mgmt/Kconfig index d5c9cb8..757f574 100644 --- a/firmware/libs/ble_mgmt/Kconfig +++ b/firmware/libs/ble_mgmt/Kconfig @@ -64,8 +64,6 @@ if BLE_MGMT default y # Automatic updates - config BT_AUTO_PHY_UPDATE - default y config BT_AUTO_DATA_LEN_UPDATE default y config BT_GAP_AUTO_UPDATE_CONN_PARAMS diff --git a/firmware/libs/fs_mgmt/src/fs_mgmt.c b/firmware/libs/fs_mgmt/src/fs_mgmt.c index ed9d333..c3bdb2f 100644 --- a/firmware/libs/fs_mgmt/src/fs_mgmt.c +++ b/firmware/libs/fs_mgmt/src/fs_mgmt.c @@ -12,13 +12,16 @@ LOG_MODULE_REGISTER(fs_mgmt, CONFIG_FS_MGMT_LOG_LEVEL); -/* Prefer external LittleFS partition when present, otherwise internal storage partition. */ -#if DT_NODE_EXISTS(DT_NODELABEL(ext_flash_lfs)) +/* + * Under sysbuild, Partition Manager generates PM__ID symbols. + * Without PM, we fall back to the DTS node label. + */ +#if defined(PM_littlefs_storage_ID) +#define FS_PARTITION_ID FIXED_PARTITION_ID(littlefs_storage) +#elif DT_NODE_EXISTS(DT_NODELABEL(ext_flash_lfs)) #define FS_PARTITION_ID FIXED_PARTITION_ID(ext_flash_lfs) -#elif DT_NODE_EXISTS(DT_NODELABEL(storage_partition)) -#define FS_PARTITION_ID FIXED_PARTITION_ID(storage_partition) #else -#error "No compatible LittleFS partition node label found (expected ext_flash_lfs or storage_partition)" +#error "No compatible LittleFS partition found (expected PM littlefs_storage or DTS ext_flash_lfs)" #endif FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(fs_storage_data); diff --git a/firmware/libs/settings_mgmt/CMakeLists.txt b/firmware/libs/settings_mgmt/CMakeLists.txt new file mode 100644 index 0000000..b31c35b --- /dev/null +++ b/firmware/libs/settings_mgmt/CMakeLists.txt @@ -0,0 +1,5 @@ +if(CONFIG_SETTINGS_MGMT) + zephyr_library() + zephyr_library_sources(src/settings_mgmt.c) + zephyr_include_directories(include) +endif() \ No newline at end of file diff --git a/firmware/libs/settings_mgmt/Kconfig b/firmware/libs/settings_mgmt/Kconfig new file mode 100644 index 0000000..991edb2 --- /dev/null +++ b/firmware/libs/settings_mgmt/Kconfig @@ -0,0 +1,14 @@ +menuconfig SETTINGS_MGMT + bool "Settings Management" + default y + select SETTINGS + select ZMS + help + Library for initializing and managing the settings subsystem. + ZMS (Zephyr Memory Storage) backend is automatically selected when ZMS is enabled. + +if SETTINGS_MGMT + module = SETTINGS_MGMT + module-str = settings_mgmt + source "subsys/logging/Kconfig.template.log_config" +endif # SETTINGS_MGMT \ No newline at end of file diff --git a/firmware/libs/settings_mgmt/include/settings_mgmt.h b/firmware/libs/settings_mgmt/include/settings_mgmt.h new file mode 100644 index 0000000..7f3c612 --- /dev/null +++ b/firmware/libs/settings_mgmt/include/settings_mgmt.h @@ -0,0 +1,34 @@ +#ifndef SETTINGS_MGMT_H +#define SETTINGS_MGMT_H + +#include + +struct app_settings_t { + /* System */ + char dev_name[33]; + + /* Audio */ + uint8_t vol; + uint8_t shuffle_mode; /* 0: Rnd, 1: No-Rep */ + + /* BLE */ + uint32_t ble_timeout; /* Seconds, 0xFFFFFFFF = forever */ + uint16_t ble_interval; /* Milliseconds */ + + /* Power & Calibration */ + uint8_t chg_mode; /* 0: 500mA, 1: 1A, 2: Auto */ + uint16_t off_threshold;/* mV */ + int16_t adc_gain; + int16_t adc_offset; +}; + +/* Global access to the current runtime configuration */ +extern struct app_settings_t app_cfg; + +/* Initializes the settings subsystem and loads values from flash */ +int settings_mgmt_init(void); + +/* Sets a setting via string path (for your protocol) */ +int settings_mgmt_set_by_path(const char *path, const void *value, size_t len); + +#endif \ No newline at end of file diff --git a/firmware/libs/settings_mgmt/src/settings_mgmt.c b/firmware/libs/settings_mgmt/src/settings_mgmt.c new file mode 100644 index 0000000..d13010b --- /dev/null +++ b/firmware/libs/settings_mgmt/src/settings_mgmt.c @@ -0,0 +1,239 @@ +#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(); +} \ No newline at end of file diff --git a/firmware/pm_static.yml b/firmware/pm_static.yml index 908036e..8260b7f 100644 --- a/firmware/pm_static.yml +++ b/firmware/pm_static.yml @@ -1,4 +1,39 @@ -# External Flash +# Static Partition Manager layout for sysbuild builds. +# Keep this aligned with boards/iten/buzzy/buzzy.dts internal flash partitions. + +mcuboot: + address: 0x0 + size: 0xC000 + region: flash_primary + +mcuboot_pad: + address: 0xC000 + size: 0x200 + region: flash_primary + +app: + address: 0xC200 + size: 0x75E00 + region: flash_primary + +mcuboot_primary: + address: 0xC000 + size: 0x76000 + region: flash_primary + span: [mcuboot_pad, app] + +mcuboot_secondary: + address: 0x82000 + size: 0x76000 + region: flash_primary + +# Internal flash tail partition (8 x 4 KiB pages) for ZMS/settings-style usage. +storage: + address: 0xF8000 + size: 0x8000 + region: flash_primary + +# External flash LittleFS image area. littlefs_storage: address: 0x0 size: 0x800000 diff --git a/firmware/pm_static_nrf52840dk_nrf52840.yml b/firmware/pm_static_nrf52840dk_nrf52840.yml deleted file mode 100644 index d5e6f3b..0000000 --- a/firmware/pm_static_nrf52840dk_nrf52840.yml +++ /dev/null @@ -1,39 +0,0 @@ -# mcuboot: -# address: 0x0 -# size: 0xC000 -# region: flash_primary - -# # Primary Slot: Start bleibt 0xC000, Größe 200KB (0x32000) -# mcuboot_primary: -# address: 0xC000 -# size: 0x32000 -# region: flash_primary - -# mcuboot_pad: -# address: 0xC000 -# size: 0x200 -# region: flash_primary - -# # Die App startet nach dem Padding des Primary Slots -# app: -# address: 0xC200 -# size: 0x31E00 # (0x32000 - 0x200) -# region: flash_primary - -# # Secondary Slot: Startet jetzt bei 0xC000 + 0x32000 = 0x3E000 -# mcuboot_secondary: -# address: 0x3E000 -# size: 0x32000 -# region: flash_primary - -# # NVS storage am Ende des Flashs, 16KB (0x4000) -# settings_storage: -# address: 0xFC000 -# size: 0x4000 -# region: flash_primary - -# External Flash -littlefs_storage: - address: 0x0 - size: 0x800000 # 8MB - region: external_flash \ No newline at end of file diff --git a/firmware/prj.conf b/firmware/prj.conf index f539f05..e1e2e34 100644 --- a/firmware/prj.conf +++ b/firmware/prj.conf @@ -1,6 +1,9 @@ ### Bluetooth CONFIG_BLE_MGMT=y +### Audio +CONFIG_BUZZ_AUDIO=y + ### Error handling CONFIG_HW_STACK_PROTECTION=y CONFIG_RESET_ON_FATAL_ERROR=y