From 8cab3eecc17eb3550295a86f0b3b649e993d48ce Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Tue, 1 Jul 2025 16:44:32 +0200 Subject: [PATCH] feat(settings): Implement persistent Modbus configuration - Integrate the Zephyr Settings subsystem to persist Modbus parameters. - Use NVS (Non-Volatile Storage) as the backend with a dedicated flash partition. - Modbus baudrate and slave ID are now loaded at startup. - Changes made via the shell are saved to flash and survive a reboot. - Add a 'reset' command to the shell for easier testing. - Fix all compiler and devicetree warnings for a clean build. --- software/apps/slave_node/CMakeLists.txt | 2 +- .../slave_node/boards/bluepill_f103rb.overlay | 22 ++++++++++ software/apps/slave_node/prj.conf | 10 +++++ software/apps/slave_node/src/main.c | 42 ++++++++++++++++++- software/apps/slave_node/src/shell_modbus.c | 22 ++++++---- software/apps/slave_node/src/shell_system.c | 12 ++++++ 6 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 software/apps/slave_node/src/shell_system.c diff --git a/software/apps/slave_node/CMakeLists.txt b/software/apps/slave_node/CMakeLists.txt index cfe9623..db8b1e4 100644 --- a/software/apps/slave_node/CMakeLists.txt +++ b/software/apps/slave_node/CMakeLists.txt @@ -6,4 +6,4 @@ list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(slave_node) -target_sources(app PRIVATE src/main.c src/shell_modbus.c) +target_sources(app PRIVATE src/main.c src/shell_modbus.c src/shell_system.c) diff --git a/software/apps/slave_node/boards/bluepill_f103rb.overlay b/software/apps/slave_node/boards/bluepill_f103rb.overlay index 1cbdfca..614e991 100644 --- a/software/apps/slave_node/boards/bluepill_f103rb.overlay +++ b/software/apps/slave_node/boards/bluepill_f103rb.overlay @@ -2,6 +2,7 @@ chosen { zephyr,console = &rtt; zephyr,shell = &rtt; + zephyr,settings-partition = &storage_partition; }; rtt: rtt { @@ -12,6 +13,27 @@ status = "okay"; }; }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Application partition starts at the beginning of flash */ + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x00000000 DT_SIZE_K(120)>; + }; + + /* Use the last 8K for settings */ + storage_partition: partition@1E000 { + label = "storage"; + reg = <0x0001E000 DT_SIZE_K(8)>; + }; + }; +}; + &usart1 { modbus0 { compatible = "zephyr,modbus-serial"; diff --git a/software/apps/slave_node/prj.conf b/software/apps/slave_node/prj.conf index 64b0c5e..5eb038a 100644 --- a/software/apps/slave_node/prj.conf +++ b/software/apps/slave_node/prj.conf @@ -12,6 +12,16 @@ CONFIG_USE_SEGGER_RTT=y # Enable Shell CONFIG_SHELL=y CONFIG_SHELL_BACKEND_RTT=y +CONFIG_REBOOT=y + +# Enable Settings Subsystem +CONFIG_SETTINGS=y +CONFIG_SETTINGS_NVS=y +CONFIG_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_SETTINGS_LOG_LEVEL_DBG=y # Config modbus CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/software/apps/slave_node/src/main.c b/software/apps/slave_node/src/main.c index 3f524a5..b8045e6 100644 --- a/software/apps/slave_node/src/main.c +++ b/software/apps/slave_node/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "modbus_bridge.h" @@ -164,6 +165,35 @@ uint8_t modbus_get_unit_id(void) return server_param.server.unit_id; } +static int settings_modbus_load(const char *name, size_t len, + settings_read_cb read_cb, void *cb_arg) +{ + const char *next; + int rc; + + if (settings_name_steq(name, "baudrate", &next) && !next) { + rc = read_cb(cb_arg, &server_param.serial.baud, sizeof(server_param.serial.baud)); + if (rc < 0) { + return rc; + } + LOG_INF("Loaded modbus/baudrate: %u", server_param.serial.baud); + return 0; + } + + if (settings_name_steq(name, "unit_id", &next) && !next) { + rc = read_cb(cb_arg, &server_param.server.unit_id, sizeof(server_param.server.unit_id)); + if (rc < 0) { + return rc; + } + LOG_INF("Loaded modbus/unit_id: %u", server_param.server.unit_id); + return 0; + } + + return -ENOENT; +} + +SETTINGS_STATIC_HANDLER_DEFINE(modbus, "modbus", NULL, settings_modbus_load, NULL, NULL); + static int init_modbus_server(void) { @@ -183,6 +213,16 @@ static int init_modbus_server(void) int main(void) { LOG_INF("Starting APP"); + + if (settings_subsys_init()) { + LOG_ERR("Failed to initialize settings subsystem"); + } + + if (settings_load()) { + LOG_ERR("Failed to load settings"); + } + + if (init_modbus_server()) { LOG_ERR("Modbus RTU server initialization failed"); } @@ -193,4 +233,4 @@ int main(void) } return 0; -} +} \ No newline at end of file diff --git a/software/apps/slave_node/src/shell_modbus.c b/software/apps/slave_node/src/shell_modbus.c index 7397f9d..5d83d54 100644 --- a/software/apps/slave_node/src/shell_modbus.c +++ b/software/apps/slave_node/src/shell_modbus.c @@ -1,5 +1,6 @@ #include #include +#include #include "modbus_bridge.h" static int cmd_modbus_set_baud(const struct shell *sh, size_t argc, char **argv) @@ -32,10 +33,12 @@ static int cmd_modbus_set_baud(const struct shell *sh, size_t argc, char **argv) if (modbus_reconfigure(new_baud, modbus_get_unit_id()) != 0) { shell_error(sh, "Failed to apply new baudrate"); - } else { - shell_print(sh, "Modbus baudrate set to: %u", new_baud); + return -1; } + settings_save_one("modbus/baudrate", &new_baud, sizeof(new_baud)); + shell_print(sh, "Modbus baudrate set to: %u (and saved)", new_baud); + return 0; } @@ -46,18 +49,21 @@ static int cmd_modbus_set_id(const struct shell *sh, size_t argc, char **argv) return -EINVAL; } - uint32_t new_id = (uint32_t)strtoul(argv[1], NULL, 10); - if (new_id == 0 || new_id > 247) { + uint32_t new_id_u32 = (uint32_t)strtoul(argv[1], NULL, 10); + if (new_id_u32 == 0 || new_id_u32 > 247) { shell_error(sh, "Invalid slave ID: %s. Must be between 1 and 247.", argv[1]); return -EINVAL; } + uint8_t new_id = (uint8_t)new_id_u32; - if (modbus_reconfigure(modbus_get_baudrate(), (uint8_t)new_id) != 0) { + if (modbus_reconfigure(modbus_get_baudrate(), new_id) != 0) { shell_error(sh, "Failed to apply new slave ID"); - } else { - shell_print(sh, "Modbus slave ID set to: %u", (uint8_t)new_id); + return -1; } + settings_save_one("modbus/unit_id", &new_id, sizeof(new_id)); + shell_print(sh, "Modbus slave ID set to: %u (and saved)", new_id); + return 0; } @@ -76,4 +82,4 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_modbus_cmds, SHELL_SUBCMD_SET_END ); -SHELL_CMD_REGISTER(modbus, &sub_modbus_cmds, "Modbus configuration", NULL); \ No newline at end of file +SHELL_CMD_REGISTER(modbus, &sub_modbus_cmds, "Modbus configuration", NULL); diff --git a/software/apps/slave_node/src/shell_system.c b/software/apps/slave_node/src/shell_system.c new file mode 100644 index 0000000..99dfb24 --- /dev/null +++ b/software/apps/slave_node/src/shell_system.c @@ -0,0 +1,12 @@ +#include +#include + +static int cmd_reset(const struct shell *sh, size_t argc, char **argv) +{ + shell_print(sh, "Rebooting system..."); + k_sleep(K_MSEC(100)); // Allow the shell to print the message + sys_reboot(SYS_REBOOT_WARM); + return 0; +} + +SHELL_CMD_REGISTER(reset, NULL, "Reboot the system", cmd_reset);