diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 1c0b5afe2bcb61..47ceceffe2f94d 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -726,12 +726,13 @@ menu "CHIP Device Layer" should not start advertising automatically after power-up. config USE_BLE_ONLY_FOR_COMMISSIONING - bool "Use BLE only for commissioning" - default y - help - Disable this flag if BLE is used for any other purpose than commissioning. - When enabled, it deinitialized the BLE on successful commissioning, and on - bootup do not initialize the BLE if device is already provisioned with Wi-Fi/Thread credentials. + depends on BT_ENABLED + bool "Use BLE only for commissioning" + default y + help + Disable this flag if BLE is used for any other purpose than commissioning. + When enabled, it deinitialized the BLE on successful commissioning, and on + bootup do not initialize the BLE if device is already provisioned with Wi-Fi/Thread credentials. endmenu @@ -1192,8 +1193,11 @@ menu "CHIP Device Layer" menu "Commissioning Window Options" config CHIP_DISCOVERY_TIMEOUT_SECS int "Commissioning Window Timeout in seconds" - range 180 900 - default 900 + range 180 900 if !ENABLE_BLE_EXT_ANNOUNCEMENT + range 901 172800 if ENABLE_BLE_EXT_ANNOUNCEMENT + default 900 if !ENABLE_BLE_EXT_ANNOUNCEMENT + default 172800 if ENABLE_BLE_EXT_ANNOUNCEMENT + help The amount of time (in seconds) after which the CHIP platform will close the Commissioning Window endmenu @@ -1216,4 +1220,13 @@ menu "CHIP Device Layer" endmenu + menu "Enable BLE Extended Announcement" + config ENABLE_BLE_EXT_ANNOUNCEMENT + bool "Enable BLE Extended Announcement" + default n + help + Enable BLE Extended Announcement.To be used with CHIP_DISCOVERY_TIMEOUT_SECS for extended announcement duration. + + endmenu + endmenu diff --git a/examples/platform/esp32/common/CommonDeviceCallbacks.cpp b/examples/platform/esp32/common/CommonDeviceCallbacks.cpp index ede4e154483154..763340cee45e45 100644 --- a/examples/platform/esp32/common/CommonDeviceCallbacks.cpp +++ b/examples/platform/esp32/common/CommonDeviceCallbacks.cpp @@ -51,7 +51,6 @@ void CommonDeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, i case DeviceEventType::kCHIPoBLEConnectionClosed: ESP_LOGI(TAG, "CHIPoBLE disconnected"); - Esp32AppServer::DeInitBLEIfCommissioned(); break; case DeviceEventType::kDnssdInitialized: @@ -67,6 +66,7 @@ void CommonDeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, i case DeviceEventType::kCommissioningComplete: { ESP_LOGI(TAG, "Commissioning complete"); + Esp32AppServer::DeInitBLEIfCommissioned(); } break; diff --git a/examples/platform/esp32/common/Esp32AppServer.cpp b/examples/platform/esp32/common/Esp32AppServer.cpp index b60685d34debca..da3366159ef7ee 100644 --- a/examples/platform/esp32/common/Esp32AppServer.cpp +++ b/examples/platform/esp32/common/Esp32AppServer.cpp @@ -116,47 +116,12 @@ static size_t hex_string_to_binary(const char * hex_string, uint8_t * buf, size_ void Esp32AppServer::DeInitBLEIfCommissioned(void) { -#if CONFIG_BT_ENABLED && CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING +#ifdef CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING if (chip::Server::GetInstance().GetFabricTable().FabricCount() > 0) { - esp_err_t err = ESP_OK; - -#if CONFIG_BT_NIMBLE_ENABLED - if (!ble_hs_is_enabled()) - { - ESP_LOGI(TAG, "BLE already deinited"); - return; - } - if (nimble_port_stop() != 0) - { - ESP_LOGE(TAG, "nimble_port_stop() failed"); - return; - } - vTaskDelay(100); - nimble_port_deinit(); - -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) - err = esp_nimble_hci_and_controller_deinit(); -#endif -#endif /* CONFIG_BT_NIMBLE_ENABLED */ - -#if CONFIG_IDF_TARGET_ESP32 - err |= esp_bt_mem_release(ESP_BT_MODE_BTDM); -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 || \ - CONFIG_IDF_TARGET_ESP32C6 - err |= esp_bt_mem_release(ESP_BT_MODE_BLE); -#endif - - if (err != ESP_OK) - { - ESP_LOGE(TAG, "BLE deinit failed"); - } - else - { - ESP_LOGI(TAG, "BLE deinit successful and memory reclaimed"); - } + chip::DeviceLayer::Internal::BLEMgr().Shutdown(); } -#endif /* CONFIG_BT_ENABLED && CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING */ +#endif /* CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING */ } void Esp32AppServer::Init(AppDelegate * sAppDelegate) @@ -167,7 +132,7 @@ void Esp32AppServer::Init(AppDelegate * sAppDelegate) if (hex_string_to_binary(CONFIG_TEST_EVENT_TRIGGER_ENABLE_KEY, sTestEventTriggerEnableKey, sizeof(sTestEventTriggerEnableKey)) == 0) { - ESP_LOGE(TAG, "Failed to convert the EnableKey string to octstr type value"); + ChipLogError(DeviceLayer, "Failed to convert the EnableKey string to octstr type value"); memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); } static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{}; @@ -194,7 +159,7 @@ void Esp32AppServer::Init(AppDelegate * sAppDelegate) if (chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned() && (chip::Server::GetInstance().GetFabricTable().FabricCount() != 0)) { - ESP_LOGI(TAG, "Thread has been provisioned, publish the dns service now"); + ChipLogProgress(DeviceLayer, "Thread has been provisioned, publish the dns service now"); chip::app::DnssdServer::Instance().StartServer(); } #endif diff --git a/src/platform/ESP32/BLEManagerImpl.h b/src/platform/ESP32/BLEManagerImpl.h index 5cb1421750786a..8265b36f177028 100644 --- a/src/platform/ESP32/BLEManagerImpl.h +++ b/src/platform/ESP32/BLEManagerImpl.h @@ -156,7 +156,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement the BLEManager internal interface. CHIP_ERROR _Init(void); - void _Shutdown() {} + void _Shutdown(); bool _IsAdvertisingEnabled(void); CHIP_ERROR _SetAdvertisingEnabled(bool val); bool _IsAdvertising(void); @@ -232,6 +232,7 @@ class BLEManagerImpl final : public BLEManager, kFastAdvertisingEnabled = 0x0200, /**< The application has enabled fast advertising. */ kUseCustomDeviceName = 0x0400, /**< The application has configured a custom BLE device name. */ kAdvertisingRefreshNeeded = 0x0800, /**< The advertising configuration/state in ESP BLE layer needs to be updated. */ + kExtAdvertisingEnabled = 0x1000, /**< The application has enabled Extended BLE announcement. */ }; enum @@ -296,15 +297,12 @@ class BLEManagerImpl final : public BLEManager, void DriveBLEState(void); CHIP_ERROR InitESPBleLayer(void); + void DeinitESPBleLayer(void); CHIP_ERROR ConfigureAdvertisingData(void); CHIP_ERROR StartAdvertising(void); - - static constexpr System::Clock::Timeout kFastAdvertiseTimeout = - System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); - System::Clock::Timestamp mAdvertiseStartTime; - - static void HandleFastAdvertisementTimer(System::Layer * systemLayer, void * context); - void HandleFastAdvertisementTimer(); + void StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs); + void CancelBleAdvTimeoutTimer(void); + static void BleAdvTimeoutHandler(TimerHandle_t xTimer); #if CONFIG_BT_BLUEDROID_ENABLED void HandleGATTControlEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t * param); @@ -330,6 +328,9 @@ class BLEManagerImpl final : public BLEManager, static void HandleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t * param); #elif CONFIG_BT_NIMBLE_ENABLED + CHIP_ERROR DeinitBLE(); + static void ClaimBLEMemory(System::Layer *, void *); + void HandleRXCharRead(struct ble_gatt_char_context * param); void HandleRXCharWrite(struct ble_gatt_char_context * param); void HandleTXCharWrite(struct ble_gatt_char_context * param); diff --git a/src/platform/ESP32/CHIPDevicePlatformConfig.h b/src/platform/ESP32/CHIPDevicePlatformConfig.h index f0f28408a3ce12..5e97b4e7eb4473 100644 --- a/src/platform/ESP32/CHIPDevicePlatformConfig.h +++ b/src/platform/ESP32/CHIPDevicePlatformConfig.h @@ -106,6 +106,7 @@ #define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS CONFIG_CHIP_DISCOVERY_TIMEOUT_SECS #define CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE CONFIG_ENABLE_ESP32_BLE_CONTROLLER #define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART +#define CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING CONFIG_ENABLE_BLE_EXT_ANNOUNCEMENT // Options for background chip task #define CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING CONFIG_ENABLE_BG_EVENT_PROCESSING diff --git a/src/platform/ESP32/nimble/BLEManagerImpl.cpp b/src/platform/ESP32/nimble/BLEManagerImpl.cpp index b1f01554ddb0ef..0e4cdf7a4be309 100644 --- a/src/platform/ESP32/nimble/BLEManagerImpl.cpp +++ b/src/platform/ESP32/nimble/BLEManagerImpl.cpp @@ -76,6 +76,7 @@ namespace Internal { namespace { +TimerHandle_t sbleAdvTimeoutTimer; // FreeRTOS sw timer. #if CONFIG_ENABLE_ESP32_BLE_CONTROLLER static constexpr uint16_t kNewConnectionScanTimeout = 60; static constexpr uint16_t kConnectTimeout = 20; @@ -123,8 +124,6 @@ uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; ChipDeviceScanner & mDeviceScanner = Internal::ChipDeviceScanner::GetInstance(); #endif BLEManagerImpl BLEManagerImpl::sInstance; -constexpr System::Clock::Timeout BLEManagerImpl::kFastAdvertiseTimeout; - const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTAttrs[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), @@ -213,6 +212,16 @@ CHIP_ERROR BLEManagerImpl::_Init() { CHIP_ERROR err; + // Create FreeRTOS sw timer for BLE timeouts and interval change. + sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel + 1, // == default timer period + false, // no timer reload (==one-shot) + (void *) this, // init timer id = ble obj context + BleAdvTimeoutHandler // timer callback handler + ); + + VerifyOrReturnError(sbleAdvTimeoutTimer != nullptr, CHIP_ERROR_NO_MEMORY); + // Initialize the Chip BleLayer. #if CONFIG_ENABLE_ESP32_BLE_CONTROLLER err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer()); @@ -246,6 +255,25 @@ CHIP_ERROR BLEManagerImpl::_Init() return err; } +void BLEManagerImpl::_Shutdown() +{ + VerifyOrReturn(sbleAdvTimeoutTimer != nullptr); + xTimerDelete(sbleAdvTimeoutTimer, portMAX_DELAY); + sbleAdvTimeoutTimer = nullptr; + + BleLayer::Shutdown(); + + // selectively setting kGATTServiceStarted flag, in order to notify the state machine to stop the CHIPoBLE GATT service + mFlags.ClearAll().Set(Flags::kGATTServiceStarted); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + +#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER + OnChipBleConnectReceived = nullptr; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -254,8 +282,7 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) if (val) { - mAdvertiseStartTime = System::SystemClock().GetMonotonicTimestamp(); - ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleFastAdvertisementTimer, this)); + StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); } mFlags.Set(Flags::kFastAdvertisingEnabled, val); @@ -267,21 +294,31 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) return err; } -void BLEManagerImpl::HandleFastAdvertisementTimer(System::Layer * systemLayer, void * context) -{ - static_cast(context)->HandleFastAdvertisementTimer(); -} - -void BLEManagerImpl::HandleFastAdvertisementTimer() +void BLEManagerImpl::BleAdvTimeoutHandler(TimerHandle_t xTimer) { - System::Clock::Timestamp currentTimestamp = System::SystemClock().GetMonotonicTimestamp(); + if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + ChipLogProgress(DeviceLayer, "bleAdv Timeout : Start slow advertisement"); + BLEMgrImpl().mFlags.Set(Flags::kFastAdvertisingEnabled, 0); + BLEMgrImpl().mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); - if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout) +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + BLEMgrImpl().mFlags.Clear(Flags::kExtAdvertisingEnabled); + BLEMgrImpl().StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS); +#endif + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + else { - mFlags.Set(Flags::kFastAdvertisingEnabled, 0); - mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + ChipLogProgress(DeviceLayer, "bleAdv Timeout : Start extended advertisement"); + BLEMgrImpl().mFlags.Set(Flags::kAdvertising); + BLEMgrImpl().mFlags.Set(Flags::kExtAdvertisingEnabled); + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); + BLEMgrImpl().mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); PlatformMgr().ScheduleWork(DriveBLEState, 0); } +#endif } CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) @@ -690,6 +727,32 @@ CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) return CHIP_ERROR(ChipError::Range::kPlatform, CHIP_DEVICE_CONFIG_ESP32_BLE_ERROR_MIN + bleErr); } } +void BLEManagerImpl::CancelBleAdvTimeoutTimer(void) +{ + VerifyOrReturn(sbleAdvTimeoutTimer != nullptr); + + if (xTimerStop(sbleAdvTimeoutTimer, pdMS_TO_TICKS(0)) == pdFAIL) + { + ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer"); + } +} +void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs) +{ + VerifyOrReturn(sbleAdvTimeoutTimer != nullptr); + + if (xTimerIsTimerActive(sbleAdvTimeoutTimer)) + { + CancelBleAdvTimeoutTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sbleAdvTimeoutTimer, pdMS_TO_TICKS(aTimeoutInMs), pdMS_TO_TICKS(100)) != pdPASS) + { + ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer"); + } +} void BLEManagerImpl::DriveBLEState(void) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -806,7 +869,8 @@ void BLEManagerImpl::DriveBLEState(void) // Stop the CHIPoBLE GATT service if needed. if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kGATTServiceStarted)) { - // TODO: Not supported + DeinitESPBleLayer(); + mFlags.ClearAll(); } exit: @@ -932,6 +996,56 @@ CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void) return err; } +void BLEManagerImpl::DeinitESPBleLayer() +{ + VerifyOrReturn(DeinitBLE() == CHIP_NO_ERROR); + BLEManagerImpl::ClaimBLEMemory(nullptr, nullptr); +} + +void BLEManagerImpl::ClaimBLEMemory(System::Layer *, void *) +{ + TaskHandle_t handle = xTaskGetHandle("nimble_host"); + if (handle) + { + ChipLogDetail(DeviceLayer, "Schedule ble memory reclaiming since nimble host is still running"); + + // Rescheduling it for later, 2 seconds is an arbitrary value, keeping it a bit more so that + // we dont have to reschedule it again + SystemLayer().StartTimer(System::Clock::Seconds32(2), ClaimBLEMemory, nullptr); + } + else + { + // Free up all the space occupied by ble and add it to heap + esp_err_t err = ESP_OK; + +#if CONFIG_IDF_TARGET_ESP32 + err = esp_bt_mem_release(ESP_BT_MODE_BTDM); +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 || \ + CONFIG_IDF_TARGET_ESP32C6 + err = esp_bt_mem_release(ESP_BT_MODE_BLE); +#endif + + VerifyOrReturn(err == ESP_OK, ChipLogError(DeviceLayer, "BLE deinit failed")); + ChipLogProgress(DeviceLayer, "BLE deinit successful and memory reclaimed"); + // TODO: post an event when ble is deinitialized and memory is added to heap + } +} + +CHIP_ERROR BLEManagerImpl::DeinitBLE() +{ + VerifyOrReturnError(ble_hs_is_enabled(), CHIP_ERROR_INCORRECT_STATE, ChipLogProgress(DeviceLayer, "BLE already deinited")); + VerifyOrReturnError(0 == nimble_port_stop(), MapBLEError(ESP_FAIL), ChipLogError(DeviceLayer, "nimble_port_stop() failed")); + + esp_err_t err = nimble_port_deinit(); + VerifyOrReturnError(err == ESP_OK, MapBLEError(err)); + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + err = esp_nimble_hci_and_controller_deinit(); +#endif + + return MapBLEError(err); +} + CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) { CHIP_ERROR err; @@ -977,8 +1091,25 @@ CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) ExitNow(); } +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + // Check for extended advertisement interval and redact VID/PID if past the initial period. + if (mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + deviceIdInfo.SetVendorId(0); + deviceIdInfo.SetProductId(0); + deviceIdInfo.SetExtendedAnnouncementFlag(true); + } +#endif + #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING - deviceIdInfo.SetAdditionalDataFlag(true); + if (!mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + deviceIdInfo.SetAdditionalDataFlag(true); + } + else + { + deviceIdInfo.SetAdditionalDataFlag(false); + } #endif VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); @@ -1565,8 +1696,23 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) } else { +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + if (!mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } + else + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX; + } +#else + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + +#endif } ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable)",