From de015c12b9424f3410e935c06679f9660165a919 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 09:29:09 -0500 Subject: [PATCH 1/8] fix: update ReinitializeDevice command to support help option that displays all the existing state text. --- .../subsys/bacnet_shell/bacnet_shell_reinit.c | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/zephyr/subsys/bacnet_shell/bacnet_shell_reinit.c b/zephyr/subsys/bacnet_shell/bacnet_shell_reinit.c index 1bacaba..19edbfe 100644 --- a/zephyr/subsys/bacnet_shell/bacnet_shell_reinit.c +++ b/zephyr/subsys/bacnet_shell/bacnet_shell_reinit.c @@ -27,7 +27,7 @@ static int cmd_reinit(const struct shell *sh, size_t argc, char **argv) { BACNET_REINITIALIZE_DEVICE_DATA rd_data = { 0 }; - BACNET_REINITIALIZED_STATE state = BACNET_REINIT_IDLE; + BACNET_REINITIALIZED_STATE state = BACNET_REINIT_MAX; uint32_t found_index = 0; bool status = false; const char *name = NULL, *password = NULL, *error_name = NULL; @@ -35,11 +35,29 @@ static int cmd_reinit(const struct shell *sh, size_t argc, char **argv) const char *param_name = "state"; const char *result_name = "error-code"; - rd_data.state = BACNET_REINIT_IDLE; + rd_data.state = BACNET_REINIT_MAX; + /* argv[1] = [state|help] + argv[2] = [password] */ if ((argc == 3) || (argc == 2) || (argc == 1)) { if ((argc == 3) || (argc == 2)) { - /* Request ReinitializeDevice without password */ - if (bactext_reinitialized_state_strtol(argv[1], &found_index)) { + if (bacnet_stricmp(argv[1], "help") == 0) { + /* [help] - print all possible reinitialized states in JSON */ + shell_print(sh, "{\"ReinitializeDeviceStates\":["); + for (found_index = 0; found_index < BACNET_REINIT_MAX; + found_index++) { + name = bactext_reinitialized_state_name_default( + found_index, NULL); + if (name) { + shell_print( + sh, " \"%s\"%s", name, + (found_index < BACNET_REINIT_MAX - 1) ? "," : ""); + } + } + shell_print(sh, "]}"); + return 0; + } else if (bactext_reinitialized_state_strtol( + argv[1], &found_index)) { + /* [state] - either a name or a numeric value */ rd_data.state = found_index; } } @@ -48,7 +66,7 @@ static int cmd_reinit(const struct shell *sh, size_t argc, char **argv) password = argv[2]; characterstring_init_ansi(&rd_data.password, password); } - if (rd_data.state == BACNET_REINIT_IDLE) { + if (rd_data.state == BACNET_REINIT_MAX) { /* Print current ReinitializeDevice state */ state = Device_Reinitialized_State(); name = bactext_reinitialized_state_name_default(state, "Unknown"); @@ -82,4 +100,4 @@ static int cmd_reinit(const struct shell *sh, size_t argc, char **argv) } SHELL_SUBCMD_ADD( - (bacnet), reinit, NULL, "[state] [password]", cmd_reinit, 0, 0); + (bacnet), reinit, NULL, "[state|help] [password]", cmd_reinit, 0, 0); From d9e1787498db318a1a99cd520e5e5aa1c31431b4 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 09:30:20 -0500 Subject: [PATCH 2/8] feat: add ReinitializeDevice service implementation with warm and cold start handling --- zephyr/include/bacnet_osif/bacnet_reinit.h | 24 +++++++ zephyr/samples/profiles/b-ld/src/main.c | 4 ++ zephyr/subsys/bacnet_osif/CMakeLists.txt | 1 + zephyr/subsys/bacnet_osif/bacnet_reinit.c | 79 ++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 zephyr/include/bacnet_osif/bacnet_reinit.h create mode 100644 zephyr/subsys/bacnet_osif/bacnet_reinit.c diff --git a/zephyr/include/bacnet_osif/bacnet_reinit.h b/zephyr/include/bacnet_osif/bacnet_reinit.h new file mode 100644 index 0000000..bec848b --- /dev/null +++ b/zephyr/include/bacnet_osif/bacnet_reinit.h @@ -0,0 +1,24 @@ +/** + * @file + * @brief BACnet OS interface for ReinitializeDevice reboot handling + * @author Steve Karg + * @date August 2026 + * @copyright SPDX-License-Identifier: Apache-2.0 + */ +#ifndef BACNET_OSIF_BACNET_REINIT_H +#define BACNET_OSIF_BACNET_REINIT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void bacnet_reinitialize_device_task(void *context); +void bacnet_reinitialize_device_init(uint32_t timeout_ms); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* BACNET_OSIF_BACNET_REINIT_H */ diff --git a/zephyr/samples/profiles/b-ld/src/main.c b/zephyr/samples/profiles/b-ld/src/main.c index 09610d7..bd81f50 100644 --- a/zephyr/samples/profiles/b-ld/src/main.c +++ b/zephyr/samples/profiles/b-ld/src/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include /* BACnet Stack defines - first */ @@ -32,6 +33,7 @@ /* BACnet Stack Zephyr services */ #include +#include /* Logging module registration is already done in ports/zephyr/main.c */ #include LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); @@ -152,6 +154,7 @@ static void BACnet_Lighting_Device_Init_Handler(void *context) LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number()); /* set the BACnet Basic Task device object timer for lighting output use */ bacnet_basic_task_object_timer_set(10UL); + bacnet_reinitialize_device_init(3000); srand(sys_rand32_get()); } @@ -163,6 +166,7 @@ static void BACnet_Lighting_Device_Init_Handler(void *context) static void BACnet_Lighting_Device_Task_Handler(void *context) { (void)context; + bacnet_reinitialize_device_task(NULL); } int main(void) diff --git a/zephyr/subsys/bacnet_osif/CMakeLists.txt b/zephyr/subsys/bacnet_osif/CMakeLists.txt index bf9a1ed..760aff8 100644 --- a/zephyr/subsys/bacnet_osif/CMakeLists.txt +++ b/zephyr/subsys/bacnet_osif/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_sources( bacnet_log.c bacnet_mstimer.c + bacnet_reinit.c ) diff --git a/zephyr/subsys/bacnet_osif/bacnet_reinit.c b/zephyr/subsys/bacnet_osif/bacnet_reinit.c new file mode 100644 index 0000000..61266d9 --- /dev/null +++ b/zephyr/subsys/bacnet_osif/bacnet_reinit.c @@ -0,0 +1,79 @@ +/** + * @file + * @brief The Zephyr RTOS interface for ReinitializeDevice services + * @details If the request is valid and 'Reinitialized State of Device' + * is WARMSTART or COLDSTART, then the responding BACnet-user shall + * immediately proceed to perform any applicable shut-down procedures + * prior to reinitializing the device as specified by the requesting + * BACnet-user in the request. + * + * WARMSTART shall mean to reboot the device and start over, + * retaining all data and programs that would normally be + * retained during a brief power outage. + * The precise interpretation of COLDSTART shall be defined by the vendor. + */ +#include +#include +#include +#include +/* BACnet Stack defines - first */ +#include "bacnet/bacdef.h" +/* BACnet Stack core API */ +#include "bacnet/version.h" +#include "bacnet/basic/sys/mstimer.h" +/* BACnet Stack basic device API - + see bacnet/basic/server/bacnet_device.c for details */ +#include "bacnet/basic/object/device.h" +/* Logging module registration is already done in ports/zephyr/main.c */ +#include +LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); + +/* timer for ReinitializeDevice service */ +static struct mstimer Reinitialize_Timer; + +void bacnet_reinitialize_device_task(void *context) +{ + BACNET_REINITIALIZED_STATE state; + + (void)context; + state = Device_Reinitialized_State(); + switch (state) { + case BACNET_REINIT_COLDSTART: + if (mstimer_expired(&Reinitialize_Timer)) { + LOG_INF("ReinitializeDevice COLDSTART requested. REBOOT."); +#if defined(CONFIG_REBOOT) + sys_reboot(SYS_REBOOT_COLD); +#else + LOG_ERR("Reboot not supported on this platform"); +#endif + } + break; + case BACNET_REINIT_WARMSTART: + if (mstimer_expired(&Reinitialize_Timer)) { + LOG_INF("ReinitializeDevice WARMSTART requested. REBOOT."); +#if defined(CONFIG_REBOOT) + sys_reboot(SYS_REBOOT_WARM); +#else + LOG_ERR("Reboot not supported on this platform"); +#endif + } + break; + case BACNET_REINIT_IDLE: + mstimer_reset(&Reinitialize_Timer); + break; + default: + break; + } +} + +/** + * @brief Initialize the ReinitializeDevice service timer + * @param timeout_ms The timeout in milliseconds for the ReinitializeDevice + * service + * @note This function should be called during system initialization to set up + * the timer. + */ +void bacnet_reinitialize_device_init(uint32_t timeout_ms) +{ + mstimer_set(&Reinitialize_Timer, timeout_ms); +} From c79293cb391dbf82384ee738b46fb5b034a7f9a4 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 09:54:59 -0500 Subject: [PATCH 3/8] feat: implement coldstart callback for device settings clear and reboot. Added feature to profiles samples. --- zephyr/include/bacnet_osif/bacnet_reinit.h | 6 +++++- .../include/bacnet_settings/bacnet_settings.h | 1 + zephyr/samples/profiles/b-asc/prj.conf | 1 + zephyr/samples/profiles/b-asc/src/main.c | 19 +++++++++++++++++- zephyr/samples/profiles/b-ld/prj.conf | 1 + zephyr/samples/profiles/b-ld/src/main.c | 19 ++++++++++++++++-- zephyr/samples/profiles/b-ls/prj.conf | 1 + zephyr/samples/profiles/b-ls/src/main.c | 20 ++++++++++++++++++- zephyr/samples/profiles/b-sa/prj.conf | 1 + zephyr/samples/profiles/b-sa/src/main.c | 19 ++++++++++++++++++ zephyr/samples/profiles/b-ss/prj.conf | 1 + zephyr/samples/profiles/b-ss/src/main.c | 19 ++++++++++++++++++ zephyr/subsys/bacnet_osif/bacnet_reinit.c | 18 +++++++++++++---- .../subsys/bacnet_settings/bacnet_settings.c | 12 +++++++++++ 14 files changed, 129 insertions(+), 9 deletions(-) diff --git a/zephyr/include/bacnet_osif/bacnet_reinit.h b/zephyr/include/bacnet_osif/bacnet_reinit.h index bec848b..decfe9d 100644 --- a/zephyr/include/bacnet_osif/bacnet_reinit.h +++ b/zephyr/include/bacnet_osif/bacnet_reinit.h @@ -10,11 +10,15 @@ #include +typedef void (*bacnet_reinitialize_device_coldstart_callback)(void *context); + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -void bacnet_reinitialize_device_task(void *context); +void bacnet_reinitialize_device_task( + bacnet_reinitialize_device_coldstart_callback coldstart_callback, + void *context); void bacnet_reinitialize_device_init(uint32_t timeout_ms); #ifdef __cplusplus diff --git a/zephyr/include/bacnet_settings/bacnet_settings.h b/zephyr/include/bacnet_settings/bacnet_settings.h index e5e2759..57deb91 100644 --- a/zephyr/include/bacnet_settings/bacnet_settings.h +++ b/zephyr/include/bacnet_settings/bacnet_settings.h @@ -140,6 +140,7 @@ bool bacnet_settings_string_set( const char *value); bool bacnet_settings_init(void); +int bacnet_settings_clear(void); #ifdef __cplusplus } diff --git a/zephyr/samples/profiles/b-asc/prj.conf b/zephyr/samples/profiles/b-asc/prj.conf index 993ec2e..623b7f9 100644 --- a/zephyr/samples/profiles/b-asc/prj.conf +++ b/zephyr/samples/profiles/b-asc/prj.conf @@ -171,6 +171,7 @@ CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_RUNTIME=y +CONFIG_REBOOT=y #CONFIG_SETTINGS_FILE=y #CONFIG_SETTINGS_SHELL=y # native_posix uses a simulated flash diff --git a/zephyr/samples/profiles/b-asc/src/main.c b/zephyr/samples/profiles/b-asc/src/main.c index 49b58ef..d4c6c25 100644 --- a/zephyr/samples/profiles/b-asc/src/main.c +++ b/zephyr/samples/profiles/b-asc/src/main.c @@ -29,6 +29,7 @@ #include "bacnet/basic/server/bacnet_port.h" /* BACnet Stack Zephyr services */ #include +#include /* Logging module registration is already done in ports/zephyr/main.c */ #include LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); @@ -38,6 +39,21 @@ static const uint32_t Device_Instance = 260127; static const char *Device_Name = "BACnet Application Specific Controller (B-ASC)"; +/** + * @brief Clear any stored BACnet settings before a cold start reboot + * @param context [in] The context to pass to the callback function + */ +static void BACnet_Device_Coldstart_Callback(void *context) +{ + int err; + + (void)context; + err = bacnet_settings_clear(); + if (err < 0) { + LOG_ERR("Failed to clear BACnet settings: %d", err); + } +} + /** * @brief Callback data for WriteProperty restore iterator * @param write_function The WriteProperty function to call @@ -110,6 +126,7 @@ static void BACnet_Device_Init_Handler(void *context) /* done */ LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number()); bacnet_basic_task_object_timer_set(1000UL); + bacnet_reinitialize_device_init(3000); srand(sys_rand32_get()); } @@ -120,7 +137,7 @@ static void BACnet_Device_Init_Handler(void *context) */ static void BACnet_Device_Task_Handler(void *context) { - (void)context; + bacnet_reinitialize_device_task(BACnet_Device_Coldstart_Callback, context); } int main(void) diff --git a/zephyr/samples/profiles/b-ld/prj.conf b/zephyr/samples/profiles/b-ld/prj.conf index 4131a6d..7c44e74 100644 --- a/zephyr/samples/profiles/b-ld/prj.conf +++ b/zephyr/samples/profiles/b-ld/prj.conf @@ -135,6 +135,7 @@ CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_RUNTIME=y +CONFIG_REBOOT=y #CONFIG_SETTINGS_FILE=y #CONFIG_SETTINGS_SHELL=y diff --git a/zephyr/samples/profiles/b-ld/src/main.c b/zephyr/samples/profiles/b-ld/src/main.c index bd81f50..054bcef 100644 --- a/zephyr/samples/profiles/b-ld/src/main.c +++ b/zephyr/samples/profiles/b-ld/src/main.c @@ -126,6 +126,21 @@ Settings_Restore_Callback(BACNET_WRITE_PROPERTY_DATA *wp_data, void *context) return Device_Write_Property(wp_data); } +/** + * @brief Clear any stored BACnet settings before a cold start reboot + * @param context [in] The context to pass to the callback function + */ +static void BACnet_Lighting_Device_Coldstart_Callback(void *context) +{ + int err; + + (void)context; + err = bacnet_settings_clear(); + if (err < 0) { + LOG_ERR("Failed to clear BACnet settings: %d", err); + } +} + /** * @brief BACnet Project Initialization Handler * @param context [in] The context to pass to the callback function @@ -165,8 +180,8 @@ static void BACnet_Lighting_Device_Init_Handler(void *context) */ static void BACnet_Lighting_Device_Task_Handler(void *context) { - (void)context; - bacnet_reinitialize_device_task(NULL); + bacnet_reinitialize_device_task( + BACnet_Lighting_Device_Coldstart_Callback, context); } int main(void) diff --git a/zephyr/samples/profiles/b-ls/prj.conf b/zephyr/samples/profiles/b-ls/prj.conf index 3b88aa7..e760412 100644 --- a/zephyr/samples/profiles/b-ls/prj.conf +++ b/zephyr/samples/profiles/b-ls/prj.conf @@ -134,6 +134,7 @@ CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_RUNTIME=y +CONFIG_REBOOT=y #CONFIG_SETTINGS_FILE=y #CONFIG_SETTINGS_SHELL=y # native_posix uses a simulated flash diff --git a/zephyr/samples/profiles/b-ls/src/main.c b/zephyr/samples/profiles/b-ls/src/main.c index 831c16f..c3cd7bf 100644 --- a/zephyr/samples/profiles/b-ls/src/main.c +++ b/zephyr/samples/profiles/b-ls/src/main.c @@ -32,6 +32,7 @@ #include "bacnet/basic/server/bacnet_port.h" /* BACnet Stack Zephyr services */ #include +#include /* Logging module registration is already done in ports/zephyr/main.c */ #include LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); @@ -108,6 +109,21 @@ void Binary_Lighting_Output_Blink_Warn_Handler(uint32_t object_instance) (unsigned long)object_instance); } +/** + * @brief Clear any stored BACnet settings before a cold start reboot + * @param context [in] The context to pass to the callback function + */ +static void BACnet_Lighting_Device_Coldstart_Callback(void *context) +{ + int err; + + (void)context; + err = bacnet_settings_clear(); + if (err < 0) { + LOG_ERR("Failed to clear BACnet settings: %d", err); + } +} + /** * @brief Callback data for WriteProperty restore iterator * @param write_function The WriteProperty function to call @@ -182,6 +198,7 @@ static void BACnet_Lighting_Device_Init_Handler(void *context) LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number()); /* set the BACnet Basic Task device object timer for lighting output use */ bacnet_basic_task_object_timer_set(10UL); + bacnet_reinitialize_device_init(3000); srand(sys_rand32_get()); } @@ -192,7 +209,8 @@ static void BACnet_Lighting_Device_Init_Handler(void *context) */ static void BACnet_Lighting_Device_Task_Handler(void *context) { - (void)context; + bacnet_reinitialize_device_task( + BACnet_Lighting_Device_Coldstart_Callback, context); } int main(void) diff --git a/zephyr/samples/profiles/b-sa/prj.conf b/zephyr/samples/profiles/b-sa/prj.conf index 75711f1..731966f 100644 --- a/zephyr/samples/profiles/b-sa/prj.conf +++ b/zephyr/samples/profiles/b-sa/prj.conf @@ -128,6 +128,7 @@ CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_RUNTIME=y +CONFIG_REBOOT=y #CONFIG_SETTINGS_FILE=y #CONFIG_SETTINGS_SHELL=y # native_posix uses a simulated flash diff --git a/zephyr/samples/profiles/b-sa/src/main.c b/zephyr/samples/profiles/b-sa/src/main.c index f77eedf..1696829 100644 --- a/zephyr/samples/profiles/b-sa/src/main.c +++ b/zephyr/samples/profiles/b-sa/src/main.c @@ -27,6 +27,7 @@ #include "bacnet/basic/server/bacnet_port.h" /* BACnet Stack Zephyr services */ #include +#include /* Logging module registration is already done in ports/zephyr/main.c */ #include LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); @@ -44,6 +45,21 @@ static void BACnet_Smart_Actuator_Datalink_Init(void) /* nothing to do */ } +/** + * @brief Clear any stored BACnet settings before a cold start reboot + * @param context [in] The context to pass to the callback function + */ +static void BACnet_Smart_Actuator_Coldstart_Callback(void *context) +{ + int err; + + (void)context; + err = bacnet_settings_clear(); + if (err < 0) { + LOG_ERR("Failed to clear BACnet settings: %d", err); + } +} + /** * @brief Callback data for WriteProperty restore iterator * @param write_function The WriteProperty function to call @@ -85,6 +101,7 @@ static void BACnet_Smart_Actuator_Init_Handler(void *context) LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number()); /* start the seconds cyclic timer */ mstimer_set(&Actuator_Update_Timer, 1000); + bacnet_reinitialize_device_init(3000); srand(sys_rand32_get()); } @@ -98,6 +115,8 @@ static void BACnet_Smart_Actuator_Task_Handler(void *context) float percent = 0.0f, change = 0.0f; (void)context; + bacnet_reinitialize_device_task( + BACnet_Smart_Actuator_Coldstart_Callback, context); if (mstimer_expired(&Actuator_Update_Timer)) { mstimer_reset(&Actuator_Update_Timer); /* simulate an internal software program, diff --git a/zephyr/samples/profiles/b-ss/prj.conf b/zephyr/samples/profiles/b-ss/prj.conf index 1061ea2..46da483 100644 --- a/zephyr/samples/profiles/b-ss/prj.conf +++ b/zephyr/samples/profiles/b-ss/prj.conf @@ -37,6 +37,7 @@ CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_RUNTIME=y +CONFIG_REBOOT=y # BACnet Library - options CONFIG_BACNET_MAX_CHARACTER_STRING_BYTES=128 CONFIG_BACAPP_MINIMAL=y diff --git a/zephyr/samples/profiles/b-ss/src/main.c b/zephyr/samples/profiles/b-ss/src/main.c index c8eeadc..67bb4ab 100644 --- a/zephyr/samples/profiles/b-ss/src/main.c +++ b/zephyr/samples/profiles/b-ss/src/main.c @@ -27,6 +27,7 @@ /* BACnet Stack Zephyr services */ #include #include +#include /* Logging module registration is already done in ports/zephyr/main.c */ #include LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); @@ -39,6 +40,21 @@ static const uint32_t Sensor_Instance = 1; /* timer for Sensor Update Interval */ static struct mstimer Sensor_Update_Timer; +/** + * @brief Clear any stored BACnet settings before a cold start reboot + * @param context [in] The context to pass to the callback function + */ +static void BACnet_Smart_Sensor_Coldstart_Callback(void *context) +{ + int err; + + (void)context; + err = bacnet_settings_clear(); + if (err < 0) { + LOG_ERR("Failed to clear BACnet settings: %d", err); + } +} + /** * @brief Callback data for WriteProperty restore iterator * @param write_function The WriteProperty function to call @@ -80,6 +96,7 @@ static void BACnet_Smart_Sensor_Init_Handler(void *context) LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number()); /* start the seconds cyclic timer */ mstimer_set(&Sensor_Update_Timer, 1000); + bacnet_reinitialize_device_init(3000); srand(sys_rand32_get()); } @@ -93,6 +110,8 @@ static void BACnet_Smart_Sensor_Task_Handler(void *context) float temperature = 0.0f, change = 0.0f; (void)context; + bacnet_reinitialize_device_task( + BACnet_Smart_Sensor_Coldstart_Callback, context); if (mstimer_expired(&Sensor_Update_Timer)) { mstimer_reset(&Sensor_Update_Timer); /* simulate a sensor reading, and update the BACnet object values */ diff --git a/zephyr/subsys/bacnet_osif/bacnet_reinit.c b/zephyr/subsys/bacnet_osif/bacnet_reinit.c index 61266d9..9b472b3 100644 --- a/zephyr/subsys/bacnet_osif/bacnet_reinit.c +++ b/zephyr/subsys/bacnet_osif/bacnet_reinit.c @@ -16,6 +16,7 @@ #include #include #include +#include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" /* BACnet Stack core API */ @@ -31,16 +32,25 @@ LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL); /* timer for ReinitializeDevice service */ static struct mstimer Reinitialize_Timer; -void bacnet_reinitialize_device_task(void *context) +/** + * @brief Process a ReinitializeDevice request and trigger warm/cold restart. + * @param coldstart_callback Callback invoked before a cold start reboot. + * @param context Context passed to the cold start callback. + */ +void bacnet_reinitialize_device_task( + bacnet_reinitialize_device_coldstart_callback coldstart_callback, + void *context) { BACNET_REINITIALIZED_STATE state; - (void)context; state = Device_Reinitialized_State(); switch (state) { case BACNET_REINIT_COLDSTART: if (mstimer_expired(&Reinitialize_Timer)) { LOG_INF("ReinitializeDevice COLDSTART requested. REBOOT."); + if (coldstart_callback != NULL) { + coldstart_callback(context); + } #if defined(CONFIG_REBOOT) sys_reboot(SYS_REBOOT_COLD); #else @@ -67,9 +77,9 @@ void bacnet_reinitialize_device_task(void *context) } /** - * @brief Initialize the ReinitializeDevice service timer + * @brief Initialize the ReinitializeDevice service timer. * @param timeout_ms The timeout in milliseconds for the ReinitializeDevice - * service + * service. * @note This function should be called during system initialization to set up * the timer. */ diff --git a/zephyr/subsys/bacnet_settings/bacnet_settings.c b/zephyr/subsys/bacnet_settings/bacnet_settings.c index 36af9b7..11b94d9 100644 --- a/zephyr/subsys/bacnet_settings/bacnet_settings.c +++ b/zephyr/subsys/bacnet_settings/bacnet_settings.c @@ -826,3 +826,15 @@ bool bacnet_settings_init(void) return true; } + +/** + * @brief Clear all persisted BACnet settings. + * @return 0 on success, or a negative errno value on failure. + */ +int bacnet_settings_clear(void) +{ + int err; + + err = settings_delete(CONFIG_BACNET_STORAGE_BASE_NAME); + return err; +} From 8417b70ac132ce43f953bc9420178a41e4d9e012 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 10:20:33 -0500 Subject: [PATCH 4/8] feat: add bacnet_storage_clear function and update bacnet_settings_clear to use it since settings_delete is only for a single key. --- .../include/bacnet_settings/bacnet_storage.h | 1 + .../subsys/bacnet_settings/bacnet_settings.c | 5 +- .../subsys/bacnet_settings/bacnet_storage.c | 54 +++++++++++++++++++ .../tests/subsys/bacnet_settings/src/main.c | 19 +++++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/zephyr/include/bacnet_settings/bacnet_storage.h b/zephyr/include/bacnet_settings/bacnet_storage.h index 3a85c43..61845db 100644 --- a/zephyr/include/bacnet_settings/bacnet_storage.h +++ b/zephyr/include/bacnet_settings/bacnet_storage.h @@ -64,6 +64,7 @@ int bacnet_storage_set( BACNET_STORAGE_KEY *key, const void *data, size_t data_size); int bacnet_storage_get(BACNET_STORAGE_KEY *key, void *data, size_t data_size); int bacnet_storage_delete(BACNET_STORAGE_KEY *key); +int bacnet_storage_clear(void); #ifdef __cplusplus } diff --git a/zephyr/subsys/bacnet_settings/bacnet_settings.c b/zephyr/subsys/bacnet_settings/bacnet_settings.c index 11b94d9..adec479 100644 --- a/zephyr/subsys/bacnet_settings/bacnet_settings.c +++ b/zephyr/subsys/bacnet_settings/bacnet_settings.c @@ -833,8 +833,5 @@ bool bacnet_settings_init(void) */ int bacnet_settings_clear(void) { - int err; - - err = settings_delete(CONFIG_BACNET_STORAGE_BASE_NAME); - return err; + return bacnet_storage_clear(); } diff --git a/zephyr/subsys/bacnet_settings/bacnet_storage.c b/zephyr/subsys/bacnet_settings/bacnet_storage.c index 8ba7328..022355d 100644 --- a/zephyr/subsys/bacnet_settings/bacnet_storage.c +++ b/zephyr/subsys/bacnet_settings/bacnet_storage.c @@ -720,3 +720,57 @@ int bacnet_storage_delete(BACNET_STORAGE_KEY *key) return rc; } + +struct bacnet_storage_clear_ctx { + const char *subtree; + int status; +}; + +static int bacnet_storage_clear_cb( + const char *key, + size_t len, + settings_read_cb read_cb, + void *cb_arg, + void *param) +{ + struct bacnet_storage_clear_ctx *ctx = param; + char path[SETTINGS_MAX_NAME_LEN + 1] = { 0 }; + int rc; + + ARG_UNUSED(len); + ARG_UNUSED(read_cb); + ARG_UNUSED(cb_arg); + + if (key == NULL) { + rc = snprintf(path, sizeof(path), "%s", ctx->subtree); + } else { + rc = snprintf(path, sizeof(path), "%s/%s", ctx->subtree, key); + } + if (rc < 0 || (size_t)rc >= sizeof(path)) { + return -ENAMETOOLONG; + } + + rc = settings_delete(path); + if (rc && ctx->status == 0) { + ctx->status = rc; + } + + return 0; +} + +int bacnet_storage_clear(void) +{ + struct bacnet_storage_clear_ctx ctx = { + .subtree = CONFIG_BACNET_STORAGE_BASE_NAME, + .status = 0, + }; + int rc; + + rc = settings_load_subtree_direct( + ctx.subtree, bacnet_storage_clear_cb, &ctx); + if (rc) { + return rc; + } + + return ctx.status; +} diff --git a/zephyr/tests/subsys/bacnet_settings/src/main.c b/zephyr/tests/subsys/bacnet_settings/src/main.c index 6d20657..7259d71 100644 --- a/zephyr/tests/subsys/bacnet_settings/src/main.c +++ b/zephyr/tests/subsys/bacnet_settings/src/main.c @@ -109,4 +109,23 @@ ZTEST(bacnet_storage, test_handler_set_invokes_restore_callback) zassert_mem_equal(restore_state.data, sample, sizeof(sample), NULL); } +ZTEST(bacnet_storage, test_clear_removes_namespace_entries) +{ + BACNET_STORAGE_KEY key; + char value[32] = { 0 }; + const char *persisted = "persisted"; + int rc; + + zassert_equal(bacnet_storage_init(), 0, NULL); + bacnet_storage_key_init(&key, 1, 2, 3, BACNET_STORAGE_ARRAY_INDEX_NONE); + zassert_equal( + bacnet_storage_set(&key, persisted, strlen(persisted) + 1), 0, NULL); + + rc = bacnet_storage_clear(); + zassert_equal(rc, 0, NULL); + + rc = bacnet_storage_get(&key, value, sizeof(value)); + zassert_equal(rc, -ENOENT, NULL); +} + ZTEST_SUITE(bacnet_storage, NULL, NULL, NULL, NULL, NULL); From 6241dc5a43753a50582b3e11009a00b9945b2287 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 10:21:06 -0500 Subject: [PATCH 5/8] feat: remove unnecessary includes and fix reinitialization timer for cold/warm start to be one-shot. --- zephyr/samples/profiles/b-ld/src/main.c | 1 - zephyr/samples/profiles/b-ss/src/main.c | 1 - zephyr/subsys/bacnet_osif/bacnet_reinit.c | 4 ++++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/zephyr/samples/profiles/b-ld/src/main.c b/zephyr/samples/profiles/b-ld/src/main.c index 054bcef..f3205b9 100644 --- a/zephyr/samples/profiles/b-ld/src/main.c +++ b/zephyr/samples/profiles/b-ld/src/main.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include /* BACnet Stack defines - first */ diff --git a/zephyr/samples/profiles/b-ss/src/main.c b/zephyr/samples/profiles/b-ss/src/main.c index 67bb4ab..6358de2 100644 --- a/zephyr/samples/profiles/b-ss/src/main.c +++ b/zephyr/samples/profiles/b-ss/src/main.c @@ -109,7 +109,6 @@ static void BACnet_Smart_Sensor_Task_Handler(void *context) { float temperature = 0.0f, change = 0.0f; - (void)context; bacnet_reinitialize_device_task( BACnet_Smart_Sensor_Coldstart_Callback, context); if (mstimer_expired(&Sensor_Update_Timer)) { diff --git a/zephyr/subsys/bacnet_osif/bacnet_reinit.c b/zephyr/subsys/bacnet_osif/bacnet_reinit.c index 9b472b3..c6e8ec8 100644 --- a/zephyr/subsys/bacnet_osif/bacnet_reinit.c +++ b/zephyr/subsys/bacnet_osif/bacnet_reinit.c @@ -47,6 +47,8 @@ void bacnet_reinitialize_device_task( switch (state) { case BACNET_REINIT_COLDSTART: if (mstimer_expired(&Reinitialize_Timer)) { + /* disable the interval timer - one shot */ + mstimer_set(&Reinitialize_Timer, 0); LOG_INF("ReinitializeDevice COLDSTART requested. REBOOT."); if (coldstart_callback != NULL) { coldstart_callback(context); @@ -60,6 +62,8 @@ void bacnet_reinitialize_device_task( break; case BACNET_REINIT_WARMSTART: if (mstimer_expired(&Reinitialize_Timer)) { + /* disable the interval timer - one shot */ + mstimer_set(&Reinitialize_Timer, 0); LOG_INF("ReinitializeDevice WARMSTART requested. REBOOT."); #if defined(CONFIG_REBOOT) sys_reboot(SYS_REBOOT_WARM); From 46f7ab5a9177a468f1b0aa89fedfb0bb55efc4b4 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 10:25:29 -0500 Subject: [PATCH 6/8] fix: ensure one-shot timer behavior for cold/warm start reinitialization and reset state when reboot is not supported (i.e. simulation). --- zephyr/subsys/bacnet_osif/bacnet_reinit.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/zephyr/subsys/bacnet_osif/bacnet_reinit.c b/zephyr/subsys/bacnet_osif/bacnet_reinit.c index c6e8ec8..5fcdc43 100644 --- a/zephyr/subsys/bacnet_osif/bacnet_reinit.c +++ b/zephyr/subsys/bacnet_osif/bacnet_reinit.c @@ -47,27 +47,33 @@ void bacnet_reinitialize_device_task( switch (state) { case BACNET_REINIT_COLDSTART: if (mstimer_expired(&Reinitialize_Timer)) { - /* disable the interval timer - one shot */ - mstimer_set(&Reinitialize_Timer, 0); LOG_INF("ReinitializeDevice COLDSTART requested. REBOOT."); if (coldstart_callback != NULL) { coldstart_callback(context); } #if defined(CONFIG_REBOOT) + /* disable the interval timer - one shot */ + mstimer_set(&Reinitialize_Timer, 0); sys_reboot(SYS_REBOOT_COLD); #else + /* reset the interval timer and state */ + mstimer_reset(&Reinitialize_Timer); + Device_Reinitialize_State_Set(BACNET_REINIT_IDLE); LOG_ERR("Reboot not supported on this platform"); #endif } break; case BACNET_REINIT_WARMSTART: if (mstimer_expired(&Reinitialize_Timer)) { - /* disable the interval timer - one shot */ - mstimer_set(&Reinitialize_Timer, 0); LOG_INF("ReinitializeDevice WARMSTART requested. REBOOT."); #if defined(CONFIG_REBOOT) + /* disable the interval timer - one shot */ + mstimer_set(&Reinitialize_Timer, 0); sys_reboot(SYS_REBOOT_WARM); #else + /* reset the interval timer and state */ + mstimer_reset(&Reinitialize_Timer); + Device_Reinitialize_State_Set(BACNET_REINIT_IDLE); LOG_ERR("Reboot not supported on this platform"); #endif } From 73315895903d8530e7b65476d8653ff33a98906a Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 11:33:51 -0500 Subject: [PATCH 7/8] fix: improve error logging for littlefs mounting. Fix config for the bacnet_storage unit test to actually use a file system backend. --- zephyr/subsys/bacnet_settings/bacnet_storage.c | 15 ++++++++------- zephyr/tests/subsys/bacnet_settings/prj.conf | 6 ++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/zephyr/subsys/bacnet_settings/bacnet_storage.c b/zephyr/subsys/bacnet_settings/bacnet_storage.c index 022355d..54b0af5 100644 --- a/zephyr/subsys/bacnet_settings/bacnet_storage.c +++ b/zephyr/subsys/bacnet_settings/bacnet_storage.c @@ -199,14 +199,15 @@ int bacnet_storage_init(void) rc = fs_mount(&littlefs_mnt); if (rc != 0) { - LOG_INF("mounting littlefs error: [%d]", rc); + LOG_ERR("mounting littlefs error: [%d]", rc); + return rc; + } + + rc = fs_unlink(CONFIG_SETTINGS_FILE_PATH); + if ((rc != 0) && (rc != -ENOENT)) { + LOG_ERR("can't delete config file (err %d)", rc); } else { - rc = fs_unlink(CONFIG_SETTINGS_FILE_PATH); - if ((rc != 0) && (rc != -ENOENT)) { - H("can't delete config file%d", rc); - } else { - LOG_INF("FS initialized: OK"); - } + LOG_INF("FS initialized: OK"); } #endif rc = settings_subsys_init(); diff --git a/zephyr/tests/subsys/bacnet_settings/prj.conf b/zephyr/tests/subsys/bacnet_settings/prj.conf index 75c772c..c3804ce 100644 --- a/zephyr/tests/subsys/bacnet_settings/prj.conf +++ b/zephyr/tests/subsys/bacnet_settings/prj.conf @@ -1,3 +1,9 @@ CONFIG_ZTEST=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y + CONFIG_SETTINGS=y +CONFIG_SETTINGS_RUNTIME=y +CONFIG_SETTINGS_NVS=y CONFIG_LOG=n From 4290b0783c3ff331740a7f1fc5353072982b77f8 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 27 Aug 2026 11:59:53 -0500 Subject: [PATCH 8/8] fix: output directory cleanup by removing binary files and adjusting permissions --- samples.sh | 3 +++ subsys.sh | 3 +++ unittest.sh | 3 +++ 3 files changed, 9 insertions(+) diff --git a/samples.sh b/samples.sh index 06d45e5..e3cc73b 100755 --- a/samples.sh +++ b/samples.sh @@ -30,6 +30,9 @@ TWISTER_RC=$? # twister output directory cleanup files we do not archive find "$OUTPUT_DIR" -name 'CMakeFiles' -exec rm -rf {} \; 2>/dev/null find "$OUTPUT_DIR" -name 'modules' -exec rm -rf {} \; 2>/dev/null +find "$OUTPUT_DIR" -type f \( -name '*.bin' -o -name '*.hex' -o -name '*.elf' -o -name '*.map' \) -exec rm -f {} + 2>/dev/null +find "$OUTPUT_DIR" -type f -exec chmod u+rw,go+r {} + 2>/dev/null +find "$OUTPUT_DIR" -type d -exec chmod u+rwx,go+rx {} + 2>/dev/null find "$OUTPUT_DIR" -name 'app' -exec rm -rf \ '{}/../zephyr/arch {}/../zephyr/boards diff --git a/subsys.sh b/subsys.sh index 45881b0..30319be 100755 --- a/subsys.sh +++ b/subsys.sh @@ -64,6 +64,9 @@ TWISTER_RC=$? # twister output directory cleanup files we do not archive find "$OUTPUT_DIR" -name 'CMakeFiles' -exec rm -rf {} \; 2>/dev/null find "$OUTPUT_DIR" -name 'modules' -exec rm -rf {} \; 2>/dev/null +find "$OUTPUT_DIR" -type f \( -name '*.bin' -o -name '*.hex' -o -name '*.elf' -o -name '*.map' \) -exec rm -f {} + 2>/dev/null +find "$OUTPUT_DIR" -type f -exec chmod u+rw,go+r {} + 2>/dev/null +find "$OUTPUT_DIR" -type d -exec chmod u+rwx,go+rx {} + 2>/dev/null find "$OUTPUT_DIR" -name 'app' -exec rm -rf \ '{}/../zephyr/arch {}/../zephyr/boards diff --git a/unittest.sh b/unittest.sh index d34b424..389bc2c 100755 --- a/unittest.sh +++ b/unittest.sh @@ -33,6 +33,9 @@ TWISTER_RC=$? # twister output directory cleanup files we do not archive find "$OUTPUT_DIR" -name 'CMakeFiles' -exec rm -rf {} \; 2>/dev/null find "$OUTPUT_DIR" -name 'modules' -exec rm -rf {} \; 2>/dev/null +find "$OUTPUT_DIR" -type f \( -name '*.bin' -o -name '*.hex' -o -name '*.elf' -o -name '*.map' \) -exec rm -f {} + 2>/dev/null +find "$OUTPUT_DIR" -type f -exec chmod u+rw,go+r {} + 2>/dev/null +find "$OUTPUT_DIR" -type d -exec chmod u+rwx,go+rx {} + 2>/dev/null find "$OUTPUT_DIR" -name 'app' -exec rm -rf \ '{}/../zephyr/arch {}/../zephyr/boards