From 4c6a6583614f683d55517acd766aa692f8a29f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Mon, 30 Jan 2023 18:49:44 +0100 Subject: [PATCH] [nrfconnect] Introduce BLE advertising arbiter (#24637) * [nrfconnect] Introduce BLE advertising arbiter Add a class that enables easier coexistence of Matter and custom BLE services. Signed-off-by: Damian Krolik * Restyled by clang-format --------- Signed-off-by: Damian Krolik Co-authored-by: Restyled.io --- .../nrfconnect/chip-module/Kconfig.defaults | 4 +- .../nrfconnect/main/AppTask.cpp | 10 -- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../nrfconnect/main/AppTask.cpp | 10 -- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../lighting-app/nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - examples/lock-app/nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../platform/nrfconnect/util/DFUOverSMP.cpp | 169 ++++++------------ .../nrfconnect/util/include/DFUOverSMP.h | 57 ++++-- examples/pump-app/nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - .../window-app/nrfconnect/main/AppTask.cpp | 12 +- .../nrfconnect/main/include/AppEvent.h | 1 - .../nrfconnect/main/include/AppTask.h | 4 - src/platform/Zephyr/BLEAdvertisingArbiter.cpp | 122 +++++++++++++ src/platform/Zephyr/BLEAdvertisingArbiter.h | 104 +++++++++++ src/platform/Zephyr/BLEManagerImpl.cpp | 92 ++++++---- src/platform/Zephyr/BLEManagerImpl.h | 9 +- src/platform/Zephyr/BUILD.gn | 2 + .../Zephyr/CHIPDevicePlatformConfig.h | 6 + src/platform/nrfconnect/BUILD.gn | 2 + .../nrfconnect/CHIPDevicePlatformConfig.h | 6 + 35 files changed, 397 insertions(+), 308 deletions(-) create mode 100644 src/platform/Zephyr/BLEAdvertisingArbiter.cpp create mode 100644 src/platform/Zephyr/BLEAdvertisingArbiter.h diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults index 5303d8b2b9940b..26126987a5055c 100644 --- a/config/nrfconnect/chip-module/Kconfig.defaults +++ b/config/nrfconnect/chip-module/Kconfig.defaults @@ -127,9 +127,7 @@ config BT_DEVICE_NAME_MAX default 15 config BT_MAX_CONN - default 2 # a workaround for non-unreferenced BLE connection object - # when restaring the BLE advertising in disconnect callback - # TODO: analyze and revert to 1 if proper fix exists + default 1 config BT_L2CAP_TX_MTU default 247 diff --git a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp index ea8dcfddc8f535..e09f87af3a9cd9 100644 --- a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp +++ b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp @@ -332,16 +332,6 @@ void AppTask::FunctionTimerEventHandler(const AppEvent & event) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionHandler(const AppEvent & event) { if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) diff --git a/examples/all-clusters-app/nrfconnect/main/include/AppEvent.h b/examples/all-clusters-app/nrfconnect/main/include/AppEvent.h index ccefe5d52bbdac..0a61ed41b083c3 100644 --- a/examples/all-clusters-app/nrfconnect/main/include/AppEvent.h +++ b/examples/all-clusters-app/nrfconnect/main/include/AppEvent.h @@ -33,7 +33,6 @@ enum class AppEventType : uint8_t UpdateLedState, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/all-clusters-app/nrfconnect/main/include/AppTask.h b/examples/all-clusters-app/nrfconnect/main/include/AppTask.h index 72e87e480f9fc1..a369eeefe55c6b 100644 --- a/examples/all-clusters-app/nrfconnect/main/include/AppTask.h +++ b/examples/all-clusters-app/nrfconnect/main/include/AppTask.h @@ -66,10 +66,6 @@ class AppTask static void FunctionTimerTimeoutCallback(k_timer * timer); static void UpdateStatusLED(); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; diff --git a/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp b/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp index 5d3c2b0d2bba8c..dc6a5750698248 100644 --- a/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp +++ b/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp @@ -209,16 +209,6 @@ void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionTimerTimeoutCallback(k_timer * timer) { if (!timer) diff --git a/examples/all-clusters-minimal-app/nrfconnect/main/include/AppEvent.h b/examples/all-clusters-minimal-app/nrfconnect/main/include/AppEvent.h index 4589d636a4decf..057a32ad41ed05 100644 --- a/examples/all-clusters-minimal-app/nrfconnect/main/include/AppEvent.h +++ b/examples/all-clusters-minimal-app/nrfconnect/main/include/AppEvent.h @@ -33,7 +33,6 @@ enum class AppEventType : uint8_t UpdateLedState, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/all-clusters-minimal-app/nrfconnect/main/include/AppTask.h b/examples/all-clusters-minimal-app/nrfconnect/main/include/AppTask.h index 94a3de35f04038..1a6922e9286f0d 100644 --- a/examples/all-clusters-minimal-app/nrfconnect/main/include/AppTask.h +++ b/examples/all-clusters-minimal-app/nrfconnect/main/include/AppTask.h @@ -62,10 +62,6 @@ class AppTask static void FunctionTimerTimeoutCallback(k_timer * timer); static void UpdateStatusLED(); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; diff --git a/examples/light-switch-app/nrfconnect/main/AppTask.cpp b/examples/light-switch-app/nrfconnect/main/AppTask.cpp index bf28af3f97fab5..d2f7a6a6581c8d 100644 --- a/examples/light-switch-app/nrfconnect/main/AppTask.cpp +++ b/examples/light-switch-app/nrfconnect/main/AppTask.cpp @@ -185,7 +185,7 @@ CHIP_ERROR AppTask::Init() // Initialize DFU #ifdef CONFIG_MCUMGR_SMP_BT - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -646,16 +646,6 @@ void AppTask::FunctionTimerTimeoutCallback(k_timer * timer) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::PostEvent(const AppEvent & event) { if (k_msgq_put(&sAppEventQueue, &event, K_NO_WAIT) != 0) diff --git a/examples/light-switch-app/nrfconnect/main/include/AppEvent.h b/examples/light-switch-app/nrfconnect/main/include/AppEvent.h index b3248e3e0c29d6..98a3bb54a5244f 100644 --- a/examples/light-switch-app/nrfconnect/main/include/AppEvent.h +++ b/examples/light-switch-app/nrfconnect/main/include/AppEvent.h @@ -33,7 +33,6 @@ enum class AppEventType : uint8_t UpdateLedState, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/light-switch-app/nrfconnect/main/include/AppTask.h b/examples/light-switch-app/nrfconnect/main/include/AppTask.h index 9bd5ac4f5d98c0..5c7e2278976c00 100644 --- a/examples/light-switch-app/nrfconnect/main/include/AppTask.h +++ b/examples/light-switch-app/nrfconnect/main/include/AppTask.h @@ -84,10 +84,6 @@ class AppTask static void StartTimer(Timer, uint32_t); static void CancelTimer(Timer); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; #if CONFIG_CHIP_FACTORY_DATA diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp index 390a6718c8ea77..52e7c3100761f7 100644 --- a/examples/lighting-app/nrfconnect/main/AppTask.cpp +++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp @@ -195,7 +195,7 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -443,16 +443,6 @@ void AppTask::FunctionTimerEventHandler(const AppEvent & event) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionHandler(const AppEvent & event) { if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) diff --git a/examples/lighting-app/nrfconnect/main/include/AppEvent.h b/examples/lighting-app/nrfconnect/main/include/AppEvent.h index 19e8cede4dab5a..49c92cc03af5a6 100644 --- a/examples/lighting-app/nrfconnect/main/include/AppEvent.h +++ b/examples/lighting-app/nrfconnect/main/include/AppEvent.h @@ -35,7 +35,6 @@ enum class AppEventType : uint8_t Lighting, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/lighting-app/nrfconnect/main/include/AppTask.h b/examples/lighting-app/nrfconnect/main/include/AppTask.h index 461981e44835f7..874be7d759b5a8 100644 --- a/examples/lighting-app/nrfconnect/main/include/AppTask.h +++ b/examples/lighting-app/nrfconnect/main/include/AppTask.h @@ -86,10 +86,6 @@ class AppTask static void FunctionHandler(const AppEvent & event); static void StartBLEAdvertisementAndLightActionEventHandler(const AppEvent & event); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; PWMDevice mPWMDevice; diff --git a/examples/lock-app/nrfconnect/main/AppTask.cpp b/examples/lock-app/nrfconnect/main/AppTask.cpp index 88b58c1a32fcd8..20a4beeeb61de8 100644 --- a/examples/lock-app/nrfconnect/main/AppTask.cpp +++ b/examples/lock-app/nrfconnect/main/AppTask.cpp @@ -179,7 +179,7 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -399,16 +399,6 @@ void AppTask::FunctionTimerEventHandler(const AppEvent & event) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionHandler(const AppEvent & event) { if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) diff --git a/examples/lock-app/nrfconnect/main/include/AppEvent.h b/examples/lock-app/nrfconnect/main/include/AppEvent.h index f171149750e181..3189e78d848deb 100644 --- a/examples/lock-app/nrfconnect/main/include/AppEvent.h +++ b/examples/lock-app/nrfconnect/main/include/AppEvent.h @@ -34,7 +34,6 @@ enum class AppEventType : uint8_t UpdateLedState, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/lock-app/nrfconnect/main/include/AppTask.h b/examples/lock-app/nrfconnect/main/include/AppTask.h index a23ad0f64b4ad7..841362ed6ba8ce 100644 --- a/examples/lock-app/nrfconnect/main/include/AppTask.h +++ b/examples/lock-app/nrfconnect/main/include/AppTask.h @@ -76,10 +76,6 @@ class AppTask static void LockStateChanged(BoltLockManager::State state, BoltLockManager::OperationSource source); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; diff --git a/examples/platform/nrfconnect/util/DFUOverSMP.cpp b/examples/platform/nrfconnect/util/DFUOverSMP.cpp index 629bb8bc894db5..b1205f12c16c3d 100644 --- a/examples/platform/nrfconnect/util/DFUOverSMP.cpp +++ b/examples/platform/nrfconnect/util/DFUOverSMP.cpp @@ -21,35 +21,61 @@ #error "DFUOverSMP requires MCUMGR module configs enabled" #endif -#include -#include -#include -#include +#include "OTAUtil.h" #include #include -#include "OTAUtil.h" +#include +#include +#include +#include +#include +using namespace ::chip; using namespace ::chip::DeviceLayer; -constexpr uint16_t kAdvertisingIntervalMinMs = 400; -constexpr uint16_t kAdvertisingIntervalMaxMs = 500; +constexpr uint8_t kAdvertisingPriority = UINT8_MAX; +constexpr uint32_t kAdvertisingOptions = BT_LE_ADV_OPT_CONNECTABLE; +constexpr uint16_t kAdvertisingIntervalMin = 400; +constexpr uint16_t kAdvertisingIntervalMax = 500; +constexpr uint8_t kAdvertisingFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR; DFUOverSMP DFUOverSMP::sDFUOverSMP; -void DFUOverSMP::Init(DFUOverSMPRestartAdvertisingHandler startAdvertisingCb) +void DFUOverSMP::Init() { + const char * name = bt_get_name(); + + mAdvertisingItems[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); + mAdvertisingItems[1] = BT_DATA(BT_DATA_NAME_COMPLETE, name, static_cast(strlen(name))); + + mAdvertisingRequest.priority = kAdvertisingPriority; + mAdvertisingRequest.options = kAdvertisingOptions; + mAdvertisingRequest.minInterval = kAdvertisingIntervalMin; + mAdvertisingRequest.maxInterval = kAdvertisingIntervalMax; + mAdvertisingRequest.advertisingData = Span(mAdvertisingItems); + + mAdvertisingRequest.onStarted = [](int rc) { + if (rc == 0) + { + ChipLogProgress(SoftwareUpdate, "SMP BLE advertising started"); + } + else + { + ChipLogError(SoftwareUpdate, "Failed to start SMP BLE advertising: %d", rc); + } + }; + os_mgmt_register_group(); img_mgmt_register_group(); - img_mgmt_set_upload_cb(UploadConfirmHandler); - - memset(&mBleConnCallbacks, 0, sizeof(mBleConnCallbacks)); - mBleConnCallbacks.connected = nullptr; - mBleConnCallbacks.disconnected = OnBleDisconnect; - bt_conn_cb_register(&mBleConnCallbacks); + img_mgmt_set_upload_cb([](const img_mgmt_upload_req req, const img_mgmt_upload_action action) { + ChipLogProgress(SoftwareUpdate, "DFU over SMP progress: %u/%u B of image %u", static_cast(req.off), + static_cast(action.size), static_cast(req.image)); + return 0; + }); mgmt_register_evt_cb([](uint8_t opcode, uint16_t group, uint8_t id, void * arg) { switch (opcode) @@ -64,127 +90,34 @@ void DFUOverSMP::Init(DFUOverSMPRestartAdvertisingHandler startAdvertisingCb) break; } }); - - restartAdvertisingCallback = startAdvertisingCb; - - PlatformMgr().AddEventHandler(ChipEventHandler, 0); } void DFUOverSMP::ConfirmNewImage() { // Check if the image is run in the REVERT mode and eventually // confirm it to prevent reverting on the next boot. - if (mcuboot_swap_type() == BOOT_SWAP_TYPE_REVERT) - { - if (boot_write_img_confirmed()) - { - ChipLogError(DeviceLayer, "Confirming firmware image failed, it will be reverted on the next boot."); - } - else - { - ChipLogProgress(DeviceLayer, "New firmware image confirmed."); - } - } -} - -int DFUOverSMP::UploadConfirmHandler(const struct img_mgmt_upload_req req, const struct img_mgmt_upload_action action) -{ - // For now just print update progress and confirm data chunk without any additional checks. - ChipLogProgress(DeviceLayer, "Software update progress of image %u: %u B / %u B", static_cast(req.image), - static_cast(req.off), static_cast(action.size)); + VerifyOrReturn(mcuboot_swap_type() == BOOT_SWAP_TYPE_REVERT); - return 0; -} - -void DFUOverSMP::StartServer() -{ - if (!mIsEnabled) + if (boot_write_img_confirmed()) { - mIsEnabled = true; - smp_bt_register(); - - ChipLogProgress(DeviceLayer, "Enabled software update"); - - // Start SMP advertising only in case CHIPoBLE advertising is not working. - if (!ConnectivityMgr().IsBLEAdvertisingEnabled()) - StartBLEAdvertising(); + ChipLogError(SoftwareUpdate, "Confirming firmware image failed, it will be reverted on the next boot"); } else { - ChipLogProgress(DeviceLayer, "Software update is already enabled"); + ChipLogProgress(SoftwareUpdate, "New firmware image confirmed"); } } -void DFUOverSMP::StartBLEAdvertising() +void DFUOverSMP::StartServer() { - if (!mIsEnabled && !mIsAdvertisingEnabled) - return; - - const char * deviceName = bt_get_name(); - const uint8_t advFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR; - - bt_data ad[] = { BT_DATA(BT_DATA_FLAGS, &advFlags, sizeof(advFlags)), - BT_DATA(BT_DATA_NAME_COMPLETE, deviceName, static_cast(strlen(deviceName))) }; - - int rc; - bt_le_adv_param advParams = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, kAdvertisingIntervalMinMs, - kAdvertisingIntervalMaxMs, nullptr); + VerifyOrReturn(!mIsStarted, ChipLogProgress(SoftwareUpdate, "DFU over SMP was already started")); + smp_bt_register(); - rc = bt_le_adv_stop(); - if (rc) - { - ChipLogError(DeviceLayer, "SMP advertising stop failed (rc %d)", rc); - } - - rc = bt_le_adv_start(&advParams, ad, ARRAY_SIZE(ad), NULL, 0); - if (rc) - { - ChipLogError(DeviceLayer, "SMP advertising start failed (rc %d)", rc); - } - else - { - ChipLogProgress(DeviceLayer, "Started SMP service BLE advertising"); - mIsAdvertisingEnabled = true; - } -} - -void DFUOverSMP::OnBleDisconnect(struct bt_conn * conId, uint8_t reason) -{ + // Synchronize access to the advertising arbiter that normally runs on the CHIP thread. PlatformMgr().LockChipStack(); - - // After BLE disconnect SMP advertising needs to be restarted. Before making it ensure that BLE disconnect was not triggered - // by closing CHIPoBLE service connection (in that case CHIPoBLE advertising needs to be restarted). - if (!ConnectivityMgr().IsBLEAdvertisingEnabled() && (ConnectivityMgr().NumBLEConnections() == 0)) - { - sDFUOverSMP.restartAdvertisingCallback(); - } - + BLEAdvertisingArbiter::InsertRequest(mAdvertisingRequest); PlatformMgr().UnlockChipStack(); -} -void DFUOverSMP::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */) -{ - if (!GetDFUOverSMP().IsEnabled()) - return; - - switch (event->Type) - { - case DeviceEventType::kCHIPoBLEAdvertisingChange: - if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) - { - // Check if CHIPoBLE advertising was stopped permanently or it just a matter of opened BLE connection. - if (ConnectivityMgr().NumBLEConnections() == 0) - sDFUOverSMP.restartAdvertisingCallback(); - } - break; - case DeviceEventType::kCHIPoBLEConnectionClosed: - // Check if after closing CHIPoBLE connection advertising is working, if no start SMP advertising. - if (!ConnectivityMgr().IsBLEAdvertisingEnabled()) - { - sDFUOverSMP.restartAdvertisingCallback(); - } - break; - default: - break; - } + mIsStarted = true; + ChipLogProgress(DeviceLayer, "DFU over SMP started"); } diff --git a/examples/platform/nrfconnect/util/include/DFUOverSMP.h b/examples/platform/nrfconnect/util/include/DFUOverSMP.h index 1c5ace635783e1..b12b6a6d517494 100644 --- a/examples/platform/nrfconnect/util/include/DFUOverSMP.h +++ b/examples/platform/nrfconnect/util/include/DFUOverSMP.h @@ -23,37 +23,58 @@ #pragma once -#include +#include -#include - -typedef void (*DFUOverSMPRestartAdvertisingHandler)(void); +#include +/** + * @brief DFU over SMP helper class + * + * The purpose of this class is to enable Device Firmware Upgrade mechanism + * using Simple Management Protocol (SMP) over Bluetooth LE. Besides + * facilitating initialization of the SMP server, it is capable of requesting + * BLE advertising in a way that is compatible with other application components + * that use BLE, such as Matter BLE layer. + */ class DFUOverSMP { public: - void Init(DFUOverSMPRestartAdvertisingHandler startAdvertisingCb); + /** + * @brief Initialize DFU over SMP utility + * + * Initialize internal structures and register necessary commands in the SMP + * server. + */ + void Init(); + + /** + * @brief Confirm the current firmware image + * + * In case the current image is run tentatively after performing the + * firmware update, approve it to prevent the system from restoring the + * previous image on the next boot. + */ void ConfirmNewImage(); + + /** + * @brief Start BLE SMP server + * + * Register SMP BLE service that supports image management commands and + * request BLE advertising. The BLE advertising may begin immediately, or be + * deferred if another component with higher priority uses BLE. + */ void StartServer(); - void StartBLEAdvertising(); - bool IsEnabled() { return mIsEnabled; } private: - friend DFUOverSMP & GetDFUOverSMP(void); - - static int UploadConfirmHandler(const struct img_mgmt_upload_req req, const struct img_mgmt_upload_action action); - static void OnBleDisconnect(bt_conn * conn, uint8_t reason); - static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); - - bool mIsEnabled; - bool mIsAdvertisingEnabled; - bt_conn_cb mBleConnCallbacks; - DFUOverSMPRestartAdvertisingHandler restartAdvertisingCallback; + bool mIsStarted = false; + chip::DeviceLayer::BLEAdvertisingArbiter::Request mAdvertisingRequest = {}; + std::array mAdvertisingItems; + friend DFUOverSMP & GetDFUOverSMP(); static DFUOverSMP sDFUOverSMP; }; -inline DFUOverSMP & GetDFUOverSMP(void) +inline DFUOverSMP & GetDFUOverSMP() { return DFUOverSMP::sDFUOverSMP; } diff --git a/examples/pump-app/nrfconnect/main/AppTask.cpp b/examples/pump-app/nrfconnect/main/AppTask.cpp index b6454b09be2871..c779cee1e6e336 100644 --- a/examples/pump-app/nrfconnect/main/AppTask.cpp +++ b/examples/pump-app/nrfconnect/main/AppTask.cpp @@ -158,7 +158,7 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -318,16 +318,6 @@ void AppTask::FunctionTimerEventHandler(const AppEvent & event) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionHandler(const AppEvent & event) { if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) diff --git a/examples/pump-app/nrfconnect/main/include/AppEvent.h b/examples/pump-app/nrfconnect/main/include/AppEvent.h index 3dfff7913f3a47..b2218ac74c6b12 100644 --- a/examples/pump-app/nrfconnect/main/include/AppEvent.h +++ b/examples/pump-app/nrfconnect/main/include/AppEvent.h @@ -32,7 +32,6 @@ enum class AppEventType : uint8_t ButtonReleased, Timer, UpdateLedState, - StartSMPAdvertising, Start, Install }; diff --git a/examples/pump-app/nrfconnect/main/include/AppTask.h b/examples/pump-app/nrfconnect/main/include/AppTask.h index a551dae7d2b326..a534482c2b7c87 100644 --- a/examples/pump-app/nrfconnect/main/include/AppTask.h +++ b/examples/pump-app/nrfconnect/main/include/AppTask.h @@ -71,10 +71,6 @@ class AppTask static void FunctionTimerTimeoutCallback(k_timer * timer); static void UpdateStatusLED(); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; diff --git a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp index dd2ce3e4eab5f2..8753f759763357 100644 --- a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp +++ b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp @@ -156,7 +156,7 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -315,16 +315,6 @@ void AppTask::FunctionTimerEventHandler(const AppEvent & event) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionHandler(const AppEvent & event) { if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) diff --git a/examples/pump-controller-app/nrfconnect/main/include/AppEvent.h b/examples/pump-controller-app/nrfconnect/main/include/AppEvent.h index 3dfff7913f3a47..b2218ac74c6b12 100644 --- a/examples/pump-controller-app/nrfconnect/main/include/AppEvent.h +++ b/examples/pump-controller-app/nrfconnect/main/include/AppEvent.h @@ -32,7 +32,6 @@ enum class AppEventType : uint8_t ButtonReleased, Timer, UpdateLedState, - StartSMPAdvertising, Start, Install }; diff --git a/examples/pump-controller-app/nrfconnect/main/include/AppTask.h b/examples/pump-controller-app/nrfconnect/main/include/AppTask.h index 5681b25b32313c..742923f106a195 100644 --- a/examples/pump-controller-app/nrfconnect/main/include/AppTask.h +++ b/examples/pump-controller-app/nrfconnect/main/include/AppTask.h @@ -72,10 +72,6 @@ class AppTask static void FunctionTimerTimeoutCallback(k_timer * timer); static void UpdateStatusLED(); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; diff --git a/examples/window-app/nrfconnect/main/AppTask.cpp b/examples/window-app/nrfconnect/main/AppTask.cpp index 753149b19233e0..69d21a4455090f 100644 --- a/examples/window-app/nrfconnect/main/AppTask.cpp +++ b/examples/window-app/nrfconnect/main/AppTask.cpp @@ -158,7 +158,7 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP - GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().Init(); GetDFUOverSMP().ConfirmNewImage(); #endif @@ -288,16 +288,6 @@ void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) } } -#ifdef CONFIG_MCUMGR_SMP_BT -void AppTask::RequestSMPAdvertisingStart(void) -{ - AppEvent event; - event.Type = AppEventType::StartSMPAdvertising; - event.Handler = [](const AppEvent &) { GetDFUOverSMP().StartBLEAdvertising(); }; - PostEvent(event); -} -#endif - void AppTask::FunctionTimerTimeoutCallback(k_timer * timer) { if (!timer) diff --git a/examples/window-app/nrfconnect/main/include/AppEvent.h b/examples/window-app/nrfconnect/main/include/AppEvent.h index 035a92cc0d8e20..a97acb02346c22 100644 --- a/examples/window-app/nrfconnect/main/include/AppEvent.h +++ b/examples/window-app/nrfconnect/main/include/AppEvent.h @@ -33,7 +33,6 @@ enum class AppEventType : uint8_t UpdateLedState, IdentifyStart, IdentifyStop, - StartSMPAdvertising }; enum class FunctionEvent : uint8_t diff --git a/examples/window-app/nrfconnect/main/include/AppTask.h b/examples/window-app/nrfconnect/main/include/AppTask.h index 0b8c586cb1d067..9fbed1b2efba3b 100644 --- a/examples/window-app/nrfconnect/main/include/AppTask.h +++ b/examples/window-app/nrfconnect/main/include/AppTask.h @@ -71,10 +71,6 @@ class AppTask static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); static void UpdateStatusLED(); -#ifdef CONFIG_MCUMGR_SMP_BT - static void RequestSMPAdvertisingStart(void); -#endif - FunctionEvent mFunction{ FunctionEvent::NoneSelected }; OperationalState mMoveType{ OperationalState::MovingUpOrOpen }; bool mFunctionTimerActive{ false }; diff --git a/src/platform/Zephyr/BLEAdvertisingArbiter.cpp b/src/platform/Zephyr/BLEAdvertisingArbiter.cpp new file mode 100644 index 00000000000000..24f7b27317b637 --- /dev/null +++ b/src/platform/Zephyr/BLEAdvertisingArbiter.cpp @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BLEAdvertisingArbiter.h" + +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace BLEAdvertisingArbiter { +namespace { + +// List of advertising requests ordered by priority +sys_slist_t sRequests; + +// Cast an intrusive list node to the containing request object +const BLEAdvertisingArbiter::Request & ToRequest(const sys_snode_t * node) +{ + return *static_cast(node); +} + +// Notify application about stopped advertising if the callback has been provided +void NotifyAdvertisingStopped(const sys_snode_t * node) +{ + const Request & request = ToRequest(node); + + if (request.onStopped != nullptr) + { + request.onStopped(); + } +} + +// Restart advertising using the top-priority request +CHIP_ERROR RestartAdvertising() +{ + // Note: bt_le_adv_stop() returns success when the advertising was not started + ReturnErrorOnFailure(System::MapErrorZephyr(bt_le_adv_stop())); + ReturnErrorCodeIf(sys_slist_is_empty(&sRequests), CHIP_NO_ERROR); + + const Request & top = ToRequest(sys_slist_peek_head(&sRequests)); + const bt_le_adv_param params = BT_LE_ADV_PARAM_INIT(top.options, top.minInterval, top.maxInterval, nullptr); + const int result = bt_le_adv_start(¶ms, top.advertisingData.data(), top.advertisingData.size(), top.scanResponseData.data(), + top.scanResponseData.size()); + + if (top.onStarted != nullptr) + { + top.onStarted(result); + } + + return System::MapErrorZephyr(result); +} + +} // namespace + +CHIP_ERROR InsertRequest(Request & request) +{ + CancelRequest(request); + + sys_snode_t * prev = nullptr; + sys_snode_t * node = nullptr; + + // Find position of the request in the list that preserves ordering by priority + SYS_SLIST_FOR_EACH_NODE(&sRequests, node) + { + if (request.priority < ToRequest(node).priority) + { + break; + } + + prev = node; + } + + if (prev == nullptr) + { + NotifyAdvertisingStopped(sys_slist_peek_head(&sRequests)); + sys_slist_prepend(&sRequests, &request); + } + else + { + sys_slist_insert(&sRequests, prev, &request); + } + + // If the request is top-priority, restart the advertising + if (sys_slist_peek_head(&sRequests) == &request) + { + return RestartAdvertising(); + } + + return CHIP_NO_ERROR; +} + +void CancelRequest(Request & request) +{ + const bool isTopPriority = (sys_slist_peek_head(&sRequests) == &request); + VerifyOrReturn(sys_slist_find_and_remove(&sRequests, &request)); + + // If cancelled request was top-priority, restart the advertising. + if (isTopPriority) + { + RestartAdvertising(); + } +} + +} // namespace BLEAdvertisingArbiter +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Zephyr/BLEAdvertisingArbiter.h b/src/platform/Zephyr/BLEAdvertisingArbiter.h new file mode 100644 index 00000000000000..6176c6cedb997d --- /dev/null +++ b/src/platform/Zephyr/BLEAdvertisingArbiter.h @@ -0,0 +1,104 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#include + +/** + * @file + * Bluetooth LE advertising arbiter. + * + * The purpose for this module is to coordinate BLE advertising between + * different application components. + * + * An application component that wants to advertise BLE services is expected to + * define a request with a desired priority, and pass it to the BLE advertising + * arbiter. If there are multiple components that request BLE advertising at the + * same time, the arbiter selects the one with the highest priority (represented + * by the lowest numeric value) and starts the BLE advertising using parameters + * defined in the winning request. + * + * The BLE arbiter does not take ownership of a submitted request, so the + * request object must be sustained until it is cancelled by the application. + */ + +namespace chip { +namespace DeviceLayer { +namespace BLEAdvertisingArbiter { + +using OnAdvertisingStarted = void (*)(int result); +using OnAdvertisingStopped = void (*)(); + +struct Request : public sys_snode_t +{ + uint8_t priority; ///< Advertising request priority. Lower value means higher priority + uint32_t options; ///< Advertising options: bitmask of BT_LE_ADV_OPT_XXX constants from Zephyr + uint16_t minInterval; ///< Minimum advertising interval in 0.625 ms units + uint16_t maxInterval; ///< Maximum advertising interval in 0.625 ms units + Span advertisingData; ///< Advertising data fields + Span scanResponseData; ///< Scan response data fields + OnAdvertisingStarted onStarted; ///< (Optional) Callback invoked when the request becomes top-priority. + OnAdvertisingStopped onStopped; ///< (Optional) Callback invoked when the request stops being top-priority. +}; + +/** + * @brief Request BLE advertising + * + * Add the request to the internal list of competing requests. If the request + * has higher priority than other requests in the list, restart the BLE + * advertising immediately using parameters defined in the new request. + * + * Inserting a request object that is already registered at the advertising + * arbiter automatically cancels the previous request. + * + * @note This method does not take ownership of the request object so the object + * must not get destroyed before it is cancelled. + * + * @param request Reference to advertising request that contains priority and + * other advertising parameters. + * @return error If the request is top-priority and failed to restart the + * advertising. + * @return success Otherwise. + */ +CHIP_ERROR InsertRequest(Request & request); + +/** + * @brief Cancel BLE advertising request + * + * Remove the request from the internal list of competing requests. If the + * request is the winning (top-priority) one at the time of calling this + * function, restart the BLE advertising using parameters defined in the 2nd + * top-priority request in the list, or stop the BLE advertising completely if + * this is the last request in the list. + * + * An attempt to cancel a request that has not been registered at the + * advertising arbiter is a no-op. That is, it returns immediately. + * + * @param request Reference to advertising request that contains priority and + * other advertising parameters. + */ +void CancelRequest(Request & request); + +} // namespace BLEAdvertisingArbiter +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp index e6b299d37af4e9..8a7877aab3c779 100644 --- a/src/platform/Zephyr/BLEManagerImpl.cpp +++ b/src/platform/Zephyr/BLEManagerImpl.cpp @@ -43,6 +43,8 @@ #include #include +#include + using namespace ::chip; using namespace ::chip::Ble; using namespace ::chip::System; @@ -53,6 +55,9 @@ namespace Internal { namespace { +constexpr uint32_t kAdvertisingOptions = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME; +constexpr uint8_t kAdvertisingFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR; + const bt_uuid_128 UUID128_CHIPoBLEChar_RX = BT_UUID_INIT_128(0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18); const bt_uuid_128 UUID128_CHIPoBLEChar_TX = @@ -74,7 +79,7 @@ _bt_gatt_ccc CHIPoBLEChar_TX_CCC = BT_GATT_CCC_INITIALIZER(nullptr, BLEManagerIm // clang-format off -static bt_gatt_attr sChipoBleAttributes[] = { +bt_gatt_attr sChipoBleAttributes[] = { BT_GATT_PRIMARY_SERVICE(&UUID16_CHIPoBLEService.uuid), BT_GATT_CHARACTERISTIC(&UUID128_CHIPoBLEChar_RX.uuid, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, @@ -93,7 +98,7 @@ static bt_gatt_attr sChipoBleAttributes[] = { #endif }; -static bt_gatt_service sChipoBleService = BT_GATT_SERVICE(sChipoBleAttributes); +bt_gatt_service sChipoBleService = BT_GATT_SERVICE(sChipoBleAttributes); // clang-format on @@ -233,35 +238,57 @@ struct BLEManagerImpl::ServiceData ChipBLEDeviceIdentificationInfo deviceIdInfo; } __attribute__((packed)); -CHIP_ERROR BLEManagerImpl::StartAdvertising(void) +inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() { - int err = 0; + static ServiceData serviceData; + static std::array advertisingData; + static std::array scanResponseData; + static_assert(sizeof(serviceData) == 10, "Unexpected size of BLE advertising data!"); - // At first run always select fast advertising, on the next attempt slow down interval. - const uint32_t intervalMin = mFlags.Has(Flags::kFastAdvertisingEnabled) ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; - const uint32_t intervalMax = mFlags.Has(Flags::kFastAdvertisingEnabled) ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + const char * name = bt_get_name(); + const uint8_t nameSize = static_cast(strlen(name)); - bt_le_adv_param advParams = - BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, intervalMin, intervalMax, nullptr); + Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val); + ReturnErrorOnFailure(ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo)); - // Define advertising and, if BLE device name is set, scan response data - ServiceData serviceData; - const uint8_t advFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR; - const bt_data advertisingData[] = { BT_DATA(BT_DATA_FLAGS, &advFlags, sizeof(advFlags)), - BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)) }; + advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); + advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); + scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); + + mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; + mAdvertisingRequest.options = kAdvertisingOptions; + mAdvertisingRequest.minInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) + ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN + : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) + ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX + : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + mAdvertisingRequest.advertisingData = Span(advertisingData); + mAdvertisingRequest.scanResponseData = nameSize ? Span(scanResponseData) : Span{}; + + mAdvertisingRequest.onStarted = [](int rc) { + if (rc == 0) + { + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); + } + else + { + ChipLogError(DeviceLayer, "Failed to start CHIPoBLE advertising: %d", rc); + } + }; + + return CHIP_NO_ERROR; +} - const char * deviceName = bt_get_name(); - const uint8_t deviceNameSize = static_cast(strlen(deviceName)); - const bt_data scanResponseData[] = { BT_DATA(BT_DATA_NAME_COMPLETE, deviceName, deviceNameSize) }; - const bt_data * scanResponseDataPtr = deviceNameSize > 0 ? scanResponseData : nullptr; - const size_t scanResponseDataLen = deviceNameSize > 0 ? ARRAY_SIZE(scanResponseData) : 0u; +CHIP_ERROR BLEManagerImpl::StartAdvertising() +{ + // Prepare advertising request + ReturnErrorOnFailure(PrepareAdvertisingRequest()); // Register dynamically CHIPoBLE GATT service if (!mFlags.Has(Flags::kChipoBleGattServiceRegister)) { - err = bt_gatt_service_register(&sChipoBleService); + int err = bt_gatt_service_register(&sChipoBleService); if (err != 0) ChipLogError(DeviceLayer, "Failed to register CHIPoBLE GATT service"); @@ -271,27 +298,17 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) mFlags.Set(Flags::kChipoBleGattServiceRegister); } - // Initialize service data - static_assert(sizeof(serviceData) == 10, "Size of BLE advertisement data changed! Was that intentional?"); - chip::Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val); - ReturnErrorOnFailure(ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo)); - + // Initialize C3 characteristic data #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING ReturnErrorOnFailure(PrepareC3CharData()); #endif - // Restart advertising - err = bt_le_adv_stop(); - VerifyOrReturnError(err == 0, MapErrorZephyr(err)); - - err = bt_le_adv_start(&advParams, advertisingData, ARRAY_SIZE(advertisingData), scanResponseDataPtr, scanResponseDataLen); - VerifyOrReturnError(err == 0, MapErrorZephyr(err)); + // Request advertising + ReturnErrorOnFailure(BLEAdvertisingArbiter::InsertRequest(mAdvertisingRequest)); // Transition to the Advertising state... if (!mFlags.Has(Flags::kAdvertising)) { - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); - mFlags.Set(Flags::kAdvertising); // Post a CHIPoBLEAdvertisingChange(Started) event. @@ -314,10 +331,9 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) return CHIP_NO_ERROR; } -CHIP_ERROR BLEManagerImpl::StopAdvertising(void) +CHIP_ERROR BLEManagerImpl::StopAdvertising() { - int err = bt_le_adv_stop(); - VerifyOrReturnError(err == 0, MapErrorZephyr(err)); + BLEAdvertisingArbiter::CancelRequest(mAdvertisingRequest); // Transition to the not Advertising state... if (mFlags.Has(Flags::kAdvertising)) diff --git a/src/platform/Zephyr/BLEManagerImpl.h b/src/platform/Zephyr/BLEManagerImpl.h index b87f111460a2ca..7db469f4a5df93 100644 --- a/src/platform/Zephyr/BLEManagerImpl.h +++ b/src/platform/Zephyr/BLEManagerImpl.h @@ -25,14 +25,12 @@ #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include + #include #include #include -#include - -#include - namespace chip { namespace DeviceLayer { namespace Internal { @@ -103,12 +101,13 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla bool mSubscribedConns[CONFIG_BT_MAX_CONN]; bt_gatt_indicate_params mIndicateParams[CONFIG_BT_MAX_CONN]; bt_conn_cb mConnCallbacks; + BLEAdvertisingArbiter::Request mAdvertisingRequest = {}; #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING PacketBufferHandle c3CharDataBufferHandle; #endif void DriveBLEState(void); - CHIP_ERROR ConfigureAdvertising(void); + CHIP_ERROR PrepareAdvertisingRequest(); CHIP_ERROR StartAdvertising(void); CHIP_ERROR StopAdvertising(void); CHIP_ERROR HandleGAPConnect(const ChipDeviceEvent * event); diff --git a/src/platform/Zephyr/BUILD.gn b/src/platform/Zephyr/BUILD.gn index 61444b0fe43631..61834d8b12eb52 100644 --- a/src/platform/Zephyr/BUILD.gn +++ b/src/platform/Zephyr/BUILD.gn @@ -24,6 +24,8 @@ assert(chip_device_platform == "zephyr") static_library("Zephyr") { sources = [ "../SingletonConfigurationManager.cpp", + "BLEAdvertisingArbiter.cpp", + "BLEAdvertisingArbiter.h", "BLEManagerImpl.cpp", "BLEManagerImpl.h", "BlePlatformConfig.h", diff --git a/src/platform/Zephyr/CHIPDevicePlatformConfig.h b/src/platform/Zephyr/CHIPDevicePlatformConfig.h index 72192ad1361d4c..18df25c480ac6f 100644 --- a/src/platform/Zephyr/CHIPDevicePlatformConfig.h +++ b/src/platform/Zephyr/CHIPDevicePlatformConfig.h @@ -78,6 +78,12 @@ #endif // !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC) #endif // CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO +#ifndef CHIP_DEVICE_BLE_ADVERTISING_PRIORITY +/// Priority of the Matter BLE advertising when there are multiple application +/// components that compete for the BLE advertising. +#define CHIP_DEVICE_BLE_ADVERTISING_PRIORITY 0 +#endif // CHIP_DEVICE_BLE_ADVERTISING_PRIORITY + // ========== Platform-specific Configuration Overrides ========= #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY diff --git a/src/platform/nrfconnect/BUILD.gn b/src/platform/nrfconnect/BUILD.gn index 186b45e4a54219..f4a79e118b8da7 100644 --- a/src/platform/nrfconnect/BUILD.gn +++ b/src/platform/nrfconnect/BUILD.gn @@ -22,6 +22,8 @@ assert(chip_device_platform == "nrfconnect") static_library("nrfconnect") { sources = [ "../SingletonConfigurationManager.cpp", + "../Zephyr/BLEAdvertisingArbiter.cpp", + "../Zephyr/BLEAdvertisingArbiter.h", "../Zephyr/BLEManagerImpl.cpp", "../Zephyr/ConfigurationManagerImpl.cpp", "../Zephyr/DiagnosticDataProviderImpl.cpp", diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h index 098cf0786816fc..f92203a93e1641 100644 --- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h +++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h @@ -129,6 +129,12 @@ #endif // !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC) #endif // CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO +#ifndef CHIP_DEVICE_BLE_ADVERTISING_PRIORITY +/// Priority of the Matter BLE advertising when there are multiple application +/// components that compete for the BLE advertising. +#define CHIP_DEVICE_BLE_ADVERTISING_PRIORITY 0 +#endif // CHIP_DEVICE_BLE_ADVERTISING_PRIORITY + #ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION //-> format_version = 1 //-> vendor_id = 0xFFF1