diff --git a/CODEOWNERS b/CODEOWNERS index 64588aedf4..20745f7c8c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -44,6 +44,7 @@ /include/*.h @nrfconnect/ncs-bm /include/bm/ @nrfconnect/ncs-bm /include/bm/bluetooth/ @nrfconnect/ncs-bm +/include/bm/settings/ @nrfconnect/ncs-eris # Libraries /lib/bluetooth/ble_adv/ @nrfconnect/ncs-bm @@ -88,6 +89,7 @@ /subsys/logging/ @nrfconnect/ncs-bm /subsys/mgmt/mcumgr/ @nrfconnect/ncs-eris /subsys/nfc/ @nrfconnect/ncs-bm +/subsys/settings/ @nrfconnect/ncs-eris /subsys/softdevice/ @nrfconnect/ncs-bm /subsys/softdevice_handler/ @nrfconnect/ncs-bm /subsys/storage/bm_storage/ @nrfconnect/ncs-bm diff --git a/applications/firmware_loader/ble_mcumgr/src/main.c b/applications/firmware_loader/ble_mcumgr/src/main.c index 6a1ec1eb08..e77d764929 100644 --- a/applications/firmware_loader/ble_mcumgr/src/main.c +++ b/applications/firmware_loader/ble_mcumgr/src/main.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include LOG_MODULE_REGISTER(app, CONFIG_APP_LOG_LEVEL); @@ -214,6 +217,19 @@ int main(void) LOG_INF("Bluetooth enabled"); +#if CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME + /* Initialize setting subsystem with SRAM retention backend + * for fetching ADV device name provided by the application. + */ + err = settings_subsys_init(); + + if (err) { + LOG_ERR("Failed to enable settings, err %d", err); + } + + settings_load(); +#endif + nrf_err = ble_mcumgr_init(&mcumgr_cfg); if (nrf_err) { @@ -240,13 +256,55 @@ int main(void) return 0; } +#if CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME + const char *custom_advertising_name; + uint8_t custom_advertising_name_size; + ble_gap_conn_sec_mode_t sec_mode = {0}; + + custom_advertising_name = bluetooth_name_value_get(); + custom_advertising_name_size = strlen(custom_advertising_name); + + if (custom_advertising_name_size > 0) { + /* Change advertising name to one from application */ + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + err = sd_ble_gap_device_name_set(&sec_mode, custom_advertising_name, + custom_advertising_name_size); + + if (err) { + LOG_ERR("Failed to change advertising name, err %d", err); + return 0; + } + + err = ble_adv_data_encode(&ble_adv_cfg.adv_data, ble_adv.enc_adv_data[0], + &ble_adv.adv_data.adv_data.len); + + if (err) { + LOG_ERR("Failed to update advertising data, err %d", err); + return 0; + } + + /* Clear settings after device name has been set so it does not persist */ + err = retention_clear(DEVICE_DT_GET(DT_CHOSEN(zephyr_settings_partition))); + + if (err) { + LOG_ERR("Failed to clear retention area, err %d", err); + return 0; + } + } +#endif /* CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME */ + nrf_err = ble_adv_start(&ble_adv, BLE_ADV_MODE_FAST); if (nrf_err) { LOG_ERR("Failed to start advertising, nrf_error %#x", nrf_err); return 0; } +#if CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME + LOG_INF("Advertising as %s", (custom_advertising_name_size > 0 ? custom_advertising_name : + CONFIG_BLE_ADV_NAME)); +#else LOG_INF("Advertising as %s", CONFIG_BLE_ADV_NAME); +#endif /* CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME */ while (notification_sent == false && device_disconnected == false) { while (LOG_PROCESS()) { diff --git a/doc/nrf-bm/app_dev/dfu/dfu_name.rst b/doc/nrf-bm/app_dev/dfu/dfu_name.rst new file mode 100644 index 0000000000..0d458d2341 --- /dev/null +++ b/doc/nrf-bm/app_dev/dfu/dfu_name.rst @@ -0,0 +1,31 @@ +.. _ug_dfu_name: + +Setting up DFU Device Bluetooth name remotely +############################################# + +The Device Firmware Update (DFU) over Bluetooth® Low Energy in the single bank solution uses the loader application for firmware download support. +The firmware loader is separate application to which the remote Bluetooth LE DFU client connects to perform the firmware update. +To identify the firmware loader application over Bluetooth LE, it uses a specific advertising name provided by the remote client to the application. + +You can configure the name at application runtime using the MCUmgr settings command group. + +Write the name using the MCUmgr write setting request for ``fw_loader/adv_name`` key and export the key value to retention memory using the MCUmgr save settings request. +Once the device is rebooted into the firmware loader application, the name can be read back from the retention memory and used as the advertising name of the firmware loader. + +Enabling the feature +******************** + +To enable this feature for a sysbuild project, use the :kconfig:option:`SB_CONFIG_BM_APP_CAN_SETUP_FIRMWARE_LOADER_NAME` Kconfig option. +Otherwise, enable the following Kconfig options in both the application and the firmware loader configuration: + +* :kconfig:option:`CONFIG_RETAINED_MEM` - Enables the use of retained memory. +* :kconfig:option:`CONFIG_RETENTION` - Allows the retention of data across device reboots. +* :kconfig:option:`CONFIG_SETTINGS`- Enables the settings management subsystem. +* :kconfig:option:`CONFIG_SETTINGS_RETENTION`- Enables retention backend implementation of settings subsystem. +* :kconfig:option:`CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME`- Enables setting handlers required for Bluetooth name sharing support. + +Additionally, the application must enable the MCUmgr settings group using the following Kconfig options: +* :kconfig:option:`CONFIG_MCUMGR_GRP_SETTINGS`- Enables the MCUmgr settings group. +* :kconfig:option:`CONFIG_SETTINGS_RUNTIME`- Allows runtime modification of settings. + +This feature is used in the :ref:`ble_mcuboot_recovery_entry_sample`. diff --git a/doc/nrf-bm/app_dev/dfu/index.rst b/doc/nrf-bm/app_dev/dfu/index.rst index 141e156162..11724e7cf3 100644 --- a/doc/nrf-bm/app_dev/dfu/index.rst +++ b/doc/nrf-bm/app_dev/dfu/index.rst @@ -13,3 +13,4 @@ This chapter provides an overview of the Device Firmware Update (DFU) capabiliti single_bank_dfu bootloader_keys ug_dfu + dfu_name diff --git a/include/bm/settings/bluetooth_name.h b/include/bm/settings/bluetooth_name.h new file mode 100644 index 0000000000..558369aa2b --- /dev/null +++ b/include/bm/settings/bluetooth_name.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +/** + * @brief Retrieve the variable that holds the desired device advertising name. + * + * @retval Address of device name setting. + */ +const char *bluetooth_name_value_get(void); diff --git a/samples/boot/mcuboot_recovery_entry/prj.conf b/samples/boot/mcuboot_recovery_entry/prj.conf index 9d9adc23c6..a6302b44b3 100644 --- a/samples/boot/mcuboot_recovery_entry/prj.conf +++ b/samples/boot/mcuboot_recovery_entry/prj.conf @@ -47,3 +47,5 @@ CONFIG_NRF_SDH_BLE_GATT_MAX_MTU_SIZE=498 CONFIG_BLE_CONN_PARAMS_MAX_CONN_INTERVAL=24 CONFIG_BLE_CONN_PARAMS_SUP_TIMEOUT=20 CONFIG_BLE_CONN_PARAMS_MAX_SUP_TIMEOUT_DEVIATION=20 + +CONFIG_MCUMGR_GRP_SETTINGS=y diff --git a/samples/boot/mcuboot_recovery_entry/src/main.c b/samples/boot/mcuboot_recovery_entry/src/main.c index e5a8c08285..a826d8fe39 100644 --- a/samples/boot/mcuboot_recovery_entry/src/main.c +++ b/samples/boot/mcuboot_recovery_entry/src/main.c @@ -14,7 +14,7 @@ #include #include #include - +#include LOG_MODULE_REGISTER(app, CONFIG_APP_LOG_LEVEL); @@ -187,6 +187,17 @@ int main(void) return 0; } +#if CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME + /* Initialize setting subsystem with SRAM retention backend + * for setup ADV device name to the firmware loader + */ + err = settings_subsys_init(); + + if (err) { + LOG_ERR("Failed to enable settings: %d", err); + } +#endif + LOG_INF("Bluetooth enabled"); nrf_err = ble_mcumgr_init(&mcumgr_cfg); diff --git a/samples/boot/mcuboot_recovery_entry/sysbuild.conf b/samples/boot/mcuboot_recovery_entry/sysbuild.conf index 66e3ddd3d7..65a880e9ba 100644 --- a/samples/boot/mcuboot_recovery_entry/sysbuild.conf +++ b/samples/boot/mcuboot_recovery_entry/sysbuild.conf @@ -1 +1,2 @@ SB_CONFIG_BM_BOOTLOADER_MCUBOOT_FIRMWARE_LOADER_ENTRANCE_BOOT_MODE=y +SB_CONFIG_BM_APP_CAN_SETUP_FIRMWARE_LOADER_NAME=y diff --git a/scripts/ci/license_allow_list.yaml b/scripts/ci/license_allow_list.yaml index dbf57f5fff..12231e1efb 100644 --- a/scripts/ci/license_allow_list.yaml +++ b/scripts/ci/license_allow_list.yaml @@ -46,6 +46,8 @@ Apache-2.0: | ^nrf-bm/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig ^nrf-bm/subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt ^nrf-bm/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig + ^nrf-bm/subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt + ^nrf-bm/subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig ^nrf-bm/subsys/mgmt/mcumgr/mgmt/CMakeLists.txt ^nrf-bm/subsys/mgmt/mcumgr/mgmt/Kconfig ^nrf-bm/subsys/mgmt/mcumgr/smp/CMakeLists.txt diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index d2a19ac0e1..2d7df440f9 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -13,5 +13,6 @@ add_subdirectory(nfc) add_subdirectory(storage) add_subdirectory_ifdef(CONFIG_NCS_BM_MCUMGR mgmt/mcumgr) add_subdirectory_ifdef(CONFIG_NRF_SDH softdevice_handler) +add_subdirectory_ifdef(CONFIG_SETTINGS settings) add_subdirectory_ifdef(CONFIG_SOFTDEVICE softdevice) # zephyr-keep-sorted-stop diff --git a/subsys/Kconfig b/subsys/Kconfig index dabee517e8..62161dcee8 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -13,6 +13,7 @@ rsource "fs/Kconfig" rsource "logging/Kconfig" rsource "mgmt/mcumgr/Kconfig" rsource "nfc/Kconfig" +rsource "settings/Kconfig" rsource "softdevice/Kconfig" rsource "softdevice_handler/Kconfig" rsource "storage/Kconfig" diff --git a/subsys/mgmt/mcumgr/grp/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/CMakeLists.txt index 5d152f19a3..d0be33c66c 100644 --- a/subsys/mgmt/mcumgr/grp/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/grp/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG img_mgmt) add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS os_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SETTINGS settings_mgmt) diff --git a/subsys/mgmt/mcumgr/grp/Kconfig b/subsys/mgmt/mcumgr/grp/Kconfig index f9b660b5fa..9b2b08dfe2 100644 --- a/subsys/mgmt/mcumgr/grp/Kconfig +++ b/subsys/mgmt/mcumgr/grp/Kconfig @@ -5,3 +5,5 @@ rsource "img_mgmt/Kconfig" rsource "os_mgmt/Kconfig" + +rsource "settings_mgmt/Kconfig" diff --git a/subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt new file mode 100644 index 0000000000..0ab82a75e2 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Settings management group public API is exposed by MCUmgr API +# interface, when settings management is enabled. +zephyr_library() +zephyr_library_sources(${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/settings_mgmt/src/settings_mgmt.c) + +if(CONFIG_MCUMGR_GRP_SETTINGS AND NOT CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK) + message(WARNING "Note: MCUmgr settings management is enabled but settings access hooks are " + "disabled, this is an insecure configuration and not recommended for production " + "use, as all settings on the device can be manipulated by a remote device. See " + "https://docs.zephyrproject.org/latest/services/device_mgmt/mcumgr_callbacks.html " + "for details on enabling and using MCUmgr hooks.") +endif() diff --git a/subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig new file mode 100644 index 0000000000..ed61f4d7c5 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig @@ -0,0 +1,68 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MCUMGR_GRP_SETTINGS + bool "MCUmgr handlers for settings management" + depends on SETTINGS + depends on SETTINGS_RUNTIME + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 + select MCUMGR_SMP_CBOR_MIN_ENCODING_LEVEL_2 if ZCBOR_CANONICAL + select MCUMGR_SMP_CBOR_MIN_ENCODING_LEVEL_1 + help + Enables MCUmgr handlers for settings manipulation. + +if MCUMGR_GRP_SETTINGS + +choice MCUMGR_GRP_SETTINGS_BUFFER_TYPE + prompt "Buffer type" + default MCUMGR_GRP_SETTINGS_BUFFER_TYPE_STACK + help + Selects if the stack or heap will be used for variables that are + needed when processing requests. + +config MCUMGR_GRP_SETTINGS_BUFFER_TYPE_STACK + bool "Stack (fixed size)" + help + Use a fixed size stack buffer, any user-supplied values longer than + this will be rejected. + + Note that stack usage for parameter storage alone will be + MCUMGR_GRP_SETTINGS_NAME_LEN + MCUMGR_GRP_SETTINGS_VALUE_LEN, + therefore the MCUmgr stack should be appropriately sized. + +config MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP + bool "Heap (dynamic size)" + depends on COMMON_LIBC_MALLOC_ARENA_SIZE > 0 + help + Use dynamic heap memory allocation through malloc, if there is + insufficient heap memory for the allocation then the request will be + rejected. + +endchoice + +config MCUMGR_GRP_SETTINGS_NAME_LEN + int "Maximum setting name length" + default 32 + help + Maximum length of a key to lookup, this will be the size of the + variable if placed on the stack or the maximum allocated size of the + variable if placed on the heap. + +config MCUMGR_GRP_SETTINGS_VALUE_LEN + int "Maximum setting value length" + default 32 + help + Maximum length of a value to read, this will be the size of the + variable if placed on the stack or the allocated size of the + variable if placed on the heap (settings does not support getting + the size of a value prior to looking it up). + +config MCUMGR_GRP_SETTINGS_ACCESS_HOOK + bool "Settings access hook" + depends on MCUMGR_MGMT_NOTIFICATION_HOOKS + help + Allows applications to control settings management access by + registering for a callback which is then triggered whenever a + settings read or write attempt is made. + +endif diff --git a/subsys/settings/CMakeLists.txt b/subsys/settings/CMakeLists.txt new file mode 100644 index 0000000000..c62c68f62e --- /dev/null +++ b/subsys/settings/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_sources_ifdef(CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME src/bluetooth_name.c) diff --git a/subsys/settings/Kconfig b/subsys/settings/Kconfig new file mode 100644 index 0000000000..54c745acb3 --- /dev/null +++ b/subsys/settings/Kconfig @@ -0,0 +1,17 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menu "Settings" + depends on SETTINGS + +config NCS_BM_SETTINGS_BLUETOOTH_NAME + bool "Bluetooth name [EXPERIMENTAL]" + select EXPERIMENTAL + help + If enabled, settings handlers for support BLE advertising name + sharing under `fw_loader/adv_name` key are included into the build. + +endmenu diff --git a/subsys/settings/src/bluetooth_name.c b/subsys/settings/src/bluetooth_name.c new file mode 100644 index 0000000000..4e0a7a2307 --- /dev/null +++ b/subsys/settings/src/bluetooth_name.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(settings_bluetooth_name, CONFIG_SETTINGS_LOG_LEVEL); + +static char bluetooth_name_val[16] = ""; + +static int bluetooth_name_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg); +static int bluetooth_name_handle_export(int (*cb)(const char *name, const void *value, + size_t val_len)); +static int bluetooth_name_handle_commit(void); +static int bluetooth_name_handle_get(const char *name, char *val, int val_len_max); + +SETTINGS_STATIC_HANDLER_DEFINE(bluetooth_name, "fw_loader", bluetooth_name_handle_get, + bluetooth_name_handle_set, bluetooth_name_handle_commit, + bluetooth_name_handle_export); + +static int bluetooth_name_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) +{ + const char *next; + size_t name_len; + int rc; + + name_len = settings_name_next(name, &next); + + if (!next) { + if (!strncmp(name, "adv_name", name_len)) { + if (len > (sizeof(bluetooth_name_val) - 1)) { + LOG_ERR("Invalid settings value for fw_loader/adv_name"); + return -EINVAL; + } + + rc = read_cb(cb_arg, bluetooth_name_val, sizeof(bluetooth_name_val)); + + if (rc < 0) { + return rc; + } else if (rc > 0) { + LOG_INF("Config set to %s", bluetooth_name_val); + } + + return 0; + } + } + + return -ENOENT; +} + +static int bluetooth_name_handle_export(int (*cb)(const char *name, const void *value, + size_t val_len)) +{ + (void)cb("fw_loader/adv_name", bluetooth_name_val, strlen(bluetooth_name_val) + 1); + LOG_INF("export_done"); + return 0; +} + +static int bluetooth_name_handle_commit(void) +{ + LOG_INF("loading_done"); + return 0; +} + +static int bluetooth_name_handle_get(const char *name, char *val, int val_len_max) +{ + const char *next; + + if (name == NULL || val == NULL) { + return -EINVAL; + } + + if (settings_name_steq(name, "adv_name", &next) && !next) { + val_len_max = MIN(val_len_max, strlen(bluetooth_name_val)); + memcpy(val, bluetooth_name_val, val_len_max); + return val_len_max; + } + + return -ENOENT; +} + +const char *bluetooth_name_value_get(void) +{ + return bluetooth_name_val; +} diff --git a/sysbuild/CMakeLists.txt b/sysbuild/CMakeLists.txt index 9e7f852557..000084f43b 100644 --- a/sysbuild/CMakeLists.txt +++ b/sysbuild/CMakeLists.txt @@ -167,6 +167,21 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) if(SB_CONFIG_BM_BOOTLOADER_MCUBOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) set_config_bool(mcuboot CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO y) endif() + + if(SB_CONFIG_BM_APP_CAN_SETUP_FIRMWARE_LOADER_NAME) + set_config_bool(firmware_loader CONFIG_RETAINED_MEM y) + set_config_bool(firmware_loader CONFIG_RETENTION y) + set_config_bool(firmware_loader CONFIG_SETTINGS y) + set_config_bool(firmware_loader CONFIG_SETTINGS_RETENTION y) + set_config_bool(firmware_loader CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME y) + + set_config_bool(${DEFAULT_IMAGE} CONFIG_RETAINED_MEM y) + set_config_bool(${DEFAULT_IMAGE} CONFIG_RETENTION y) + set_config_bool(${DEFAULT_IMAGE} CONFIG_SETTINGS y) + set_config_bool(${DEFAULT_IMAGE} CONFIG_SETTINGS_RUNTIME y) + set_config_bool(${DEFAULT_IMAGE} CONFIG_SETTINGS_RETENTION y) + set_config_bool(${DEFAULT_IMAGE} CONFIG_NCS_BM_SETTINGS_BLUETOOTH_NAME y) + endif() endif() # Use BM-supplied bootloader image configuration file diff --git a/sysbuild/Kconfig.bm b/sysbuild/Kconfig.bm index d220df92bb..54b6810483 100644 --- a/sysbuild/Kconfig.bm +++ b/sysbuild/Kconfig.bm @@ -86,6 +86,15 @@ config BM_BOOTLOADER_MCUBOOT_FIRMWARE_LOADER_ENTRANCE_BOOT_MODE endmenu +config BM_APP_CAN_SETUP_FIRMWARE_LOADER_NAME + bool "Remote setup firmware loader BLE Advertising Name [EXPERIMENTAL]" + depends on !BM_FIRMWARE_LOADER_NONE + select EXPERIMENTAL + help + If enable, the application and the firmware loader will be configured + for supporting setup of the firmware loader BLE name using the settings retention + memory backend. The settings key for writing the name is `fw_loader/adv_name`. + choice BM_BOOTLOADER_MCUBOOT_IMG_HASH_ALG prompt "Hashing algorithm" default BM_BOOT_IMG_HASH_ALG_PURE if BM_BOOTLOADER_MCUBOOT_SIGNATURE_TYPE_ED25519 && SOC_SERIES_NRF54LX