| /* | 
 |  * | 
 |  *    Copyright (c) 2020-2025 Project CHIP Authors | 
 |  *    Copyright (c) 2018 Nest Labs, Inc. | 
 |  * | 
 |  *    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. | 
 |  */ | 
 |  | 
 | /** | 
 |  *    @file | 
 |  *          Provides an implementation of the BLEManager singleton object | 
 |  *          for webOS platforms. | 
 |  */ | 
 |  | 
 | /** | 
 |  * Note: BLEManager requires ConnectivityManager to be defined beforehand, | 
 |  *       otherwise we will face circular dependency between them. */ | 
 | #include <platform/ConnectivityManager.h> | 
 |  | 
 | /** | 
 |  * Note: Use public include for BLEManager which includes our local | 
 |  *       platform/<PLATFORM>/BLEManagerImpl.h after defining interface class. */ | 
 | #include "platform/internal/BLEManager.h" | 
 |  | 
 | #include <cassert> | 
 | #include <type_traits> | 
 | #include <utility> | 
 |  | 
 | #include <ble/Ble.h> | 
 | #include <lib/support/CHIPMemString.h> | 
 | #include <lib/support/CodeUtils.h> | 
 | #include <lib/support/SafeInt.h> | 
 | #include <platform/CHIPDeviceLayer.h> | 
 | #include <platform/CommissionableDataProvider.h> | 
 |  | 
 | #include "wbs/WbsConnection.h" | 
 |  | 
 | #if !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION | 
 | #include <platform/DeviceControlServer.h> | 
 | #endif | 
 |  | 
 | using namespace ::nl; | 
 | using namespace ::chip::Ble; | 
 |  | 
 | namespace chip { | 
 | namespace DeviceLayer { | 
 | namespace Internal { | 
 |  | 
 | namespace { | 
 |  | 
 | static constexpr System::Clock::Timeout kNewConnectionScanTimeout = System::Clock::Seconds16(20); | 
 | static constexpr System::Clock::Timeout kConnectTimeout           = System::Clock::Seconds16(20); | 
 | static constexpr System::Clock::Timeout kFastAdvertiseTimeout = | 
 |     System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); | 
 | #if CHIP_DEVICE_CONFIG_EXT_ADVERTISING | 
 | // The CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS specifies the transition time | 
 | // starting from advertisement commencement. Since the extended advertisement timer is started after | 
 | // the fast-to-slow transition, we have to subtract the time spent in fast advertising. | 
 | static constexpr System::Clock::Timeout kSlowAdvertiseTimeout = System::Clock::Milliseconds32( | 
 |     CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS - CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); | 
 | static_assert(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS >= | 
 |                   CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME, | 
 |               "The extended advertising interval change time must be greater than the fast advertising interval change time"); | 
 | #endif | 
 |  | 
 | } // namespace | 
 |  | 
 | BLEManagerImpl BLEManagerImpl::sInstance; | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::_Init() | 
 | { | 
 |     CHIP_ERROR err; | 
 |  | 
 |     err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer()); | 
 |     SuccessOrExit(err); | 
 |  | 
 |     mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; | 
 |     mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART && !mIsCentral); | 
 |     mFlags.Set(Flags::kFastAdvertisingEnabled, true); | 
 |  | 
 |     memset(mDeviceName, 0, sizeof(mDeviceName)); | 
 |  | 
 |     DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); }); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | void BLEManagerImpl::_Shutdown() | 
 | { | 
 |     // Make sure that timers are stopped before shutting down the BLE layer. | 
 |     DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this); | 
 |     DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this); | 
 |     DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this); | 
 |  | 
 |     mDeviceScanner.Shutdown(); | 
 |     // Release BLE connection resources | 
 |     // ShutdownWbsLayer(mEndpoint); | 
 |     mFlags.Clear(Flags::kWBSManagerInitialized); | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) | 
 | { | 
 |     CHIP_ERROR err = CHIP_NO_ERROR; | 
 |  | 
 |     if (mFlags.Has(Flags::kAdvertisingEnabled) != val) | 
 |     { | 
 |         mFlags.Set(Flags::kAdvertisingEnabled, val); | 
 |     } | 
 |  | 
 |     DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); }); | 
 |  | 
 |     return err; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) | 
 | { | 
 |     switch (mode) | 
 |     { | 
 |     case BLEAdvertisingMode::kFastAdvertising: | 
 |         mFlags.Set(Flags::kFastAdvertisingEnabled, true); | 
 |         break; | 
 |     case BLEAdvertisingMode::kSlowAdvertising: | 
 |         mFlags.Set(Flags::kFastAdvertisingEnabled, false); | 
 |         break; | 
 |     default: | 
 |         return CHIP_ERROR_INVALID_ARGUMENT; | 
 |     } | 
 |     mFlags.Set(Flags::kAdvertisingRefreshNeeded); | 
 |     DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); }); | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) | 
 | { | 
 |     if (strlen(mDeviceName) >= bufSize) | 
 |     { | 
 |         return CHIP_ERROR_BUFFER_TOO_SMALL; | 
 |     } | 
 |     strcpy(buf, mDeviceName); | 
 |  | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName) | 
 | { | 
 |     CHIP_ERROR err = CHIP_NO_ERROR; | 
 |  | 
 |     VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); | 
 |  | 
 |     if (deviceName != nullptr && deviceName[0] != 0) | 
 |     { | 
 |         VerifyOrExit(strlen(deviceName) < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); | 
 |         strcpy(mDeviceName, deviceName); | 
 |         mFlags.Set(Flags::kUseCustomDeviceName); | 
 |     } | 
 |     else | 
 |     { | 
 |         uint16_t discriminator; | 
 |         SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator)); | 
 |         snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); | 
 |         mDeviceName[kMaxDeviceNameLength] = 0; | 
 |         mFlags.Clear(Flags::kUseCustomDeviceName); | 
 |     } | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | uint16_t BLEManagerImpl::_NumConnections() | 
 | { | 
 |     uint16_t numCons = 0; | 
 |     return numCons; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral) | 
 | { | 
 |     mAdapterId = aAdapterId; | 
 |     mIsCentral = aIsCentral; | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) | 
 | { | 
 |     switch (event->Type) | 
 |     { | 
 |     case DeviceEventType::kCHIPoBLESubscribe: | 
 |         HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); | 
 |         { | 
 |             ChipDeviceEvent connectionEvent{ .Type = DeviceEventType::kCHIPoBLEConnectionEstablished }; | 
 |             PlatformMgr().PostEventOrDie(&connectionEvent); | 
 |         } | 
 |         break; | 
 |  | 
 |     case DeviceEventType::kCHIPoBLEUnsubscribe: | 
 |         HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); | 
 |         break; | 
 |  | 
 |     case DeviceEventType::kCHIPoBLEWriteReceived: | 
 |         HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID, | 
 |                             PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); | 
 |         break; | 
 |  | 
 |     case DeviceEventType::kCHIPoBLEIndicateConfirm: | 
 |         HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); | 
 |         break; | 
 |  | 
 |     case DeviceEventType::kCHIPoBLEConnectionError: | 
 |         HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); | 
 |         break; | 
 |     case DeviceEventType::kServiceProvisioningChange: | 
 |         // Force the advertising configuration to be refreshed to reflect new provisioning state. | 
 |         mFlags.Clear(Flags::kAdvertisingConfigured); | 
 |  | 
 |         DriveBLEState(); | 
 |         break; | 
 |     default: | 
 |         HandlePlatformSpecificBLEEvent(event); | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEvent) | 
 | { | 
 |     CHIP_ERROR err = CHIP_NO_ERROR; | 
 |     // ChipLogDetail(DeviceLayer, "HandlePlatformSpecificBLEEvent %d", apEvent->Type); | 
 |     switch (apEvent->Type) | 
 |     { | 
 |     case DeviceEventType::kPlatformWebOSBLEAdapterAdded: | 
 |         ChipLogDetail(DeviceLayer, "BLE adapter added: id=%u address=%s", apEvent->Platform.BLEAdapter.mAdapterId, | 
 |                       apEvent->Platform.BLEAdapter.mAdapterAddress); | 
 |         if (apEvent->Platform.BLEAdapter.mAdapterId == mAdapterId) | 
 |         { | 
 |             mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; | 
 |             DriveBLEState(); | 
 |         } | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEAdapterRemoved: | 
 |         ChipLogDetail(DeviceLayer, "BLE adapter removed: id=%u address=%s", apEvent->Platform.BLEAdapter.mAdapterId, | 
 |                       apEvent->Platform.BLEAdapter.mAdapterAddress); | 
 |         if (apEvent->Platform.BLEAdapter.mAdapterId == mAdapterId) | 
 |         { | 
 |             // Shutdown all BLE operations and release resources | 
 |             mDeviceScanner.Shutdown(); | 
 |             // mEndpoint->Shutdown(); | 
 |             //  Clear all flags related to WBS BLE operations | 
 |             mFlags.Clear(Flags::kWBSAdapterAvailable); | 
 |             mFlags.Clear(Flags::kWBSBLELayerInitialized); | 
 |             mFlags.Clear(Flags::kAdvertisingConfigured); | 
 |             mFlags.Clear(Flags::kAppRegistered); | 
 |             mFlags.Clear(Flags::kAdvertising); | 
 |             CleanScanConfig(); | 
 |             // Indicate that the adapter is no longer available | 
 |             err = BLE_ERROR_ADAPTER_UNAVAILABLE; | 
 |         } | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLECentralConnected: | 
 |         if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting) | 
 |         { | 
 |             BleConnectionDelegate::OnConnectionComplete(mBLEScanConfig.mAppState, | 
 |                                                         apEvent->Platform.BLECentralConnected.mConnection); | 
 |             CleanScanConfig(); | 
 |         } | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLECentralConnectFailed: | 
 |         if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting) | 
 |         { | 
 |             BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, apEvent->Platform.BLECentralConnectFailed.mError); | 
 |             CleanScanConfig(); | 
 |         } | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEWriteComplete: | 
 |         HandleWriteConfirmation(apEvent->Platform.BLEWriteComplete.mConnection, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID); | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLESubscribeOpComplete: | 
 |         if (apEvent->Platform.BLESubscribeOpComplete.mIsSubscribed) | 
 |             HandleSubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID, | 
 |                                     &Ble::CHIP_BLE_CHAR_2_UUID); | 
 |         else | 
 |             HandleUnsubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID, | 
 |                                       &Ble::CHIP_BLE_CHAR_2_UUID); | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEIndicationReceived: | 
 |         HandleIndicationReceived(apEvent->Platform.BLEIndicationReceived.mConnection, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID, | 
 |                                  PacketBufferHandle::Adopt(apEvent->Platform.BLEIndicationReceived.mData)); | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEPeripheralAdvStartComplete: | 
 |         SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStartComplete.mError); | 
 |         mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded); | 
 |         // Do not restart the timer if it is still active. This is to avoid the timer from being restarted | 
 |         // if the advertising is stopped due to a premature release. | 
 |         if (!DeviceLayer::SystemLayer().IsTimerActive(HandleAdvertisingTimer, this)) | 
 |         { | 
 |             // Start a timer to make sure that the fast advertising is stopped after specified timeout. | 
 |             SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleAdvertisingTimer, this)); | 
 |         } | 
 |         mFlags.Set(Flags::kAdvertising); | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEPeripheralAdvStopComplete: | 
 |         SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStopComplete.mError); | 
 |         mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded); | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this); | 
 |         // Transition to the not Advertising state... | 
 |         if (mFlags.Has(Flags::kAdvertising)) | 
 |         { | 
 |             mFlags.Clear(Flags::kAdvertising); | 
 |             ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); | 
 |         } | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEPeripheralAdvReleased: | 
 |         // If the advertising was stopped due to a premature release, check if it needs to be restarted. | 
 |         mFlags.Clear(Flags::kAdvertising); | 
 |         DriveBLEState(); | 
 |         break; | 
 |     case DeviceEventType::kPlatformWebOSBLEPeripheralRegisterAppComplete: | 
 |         SuccessOrExit(err = apEvent->Platform.BLEPeripheralRegisterAppComplete.mError); | 
 |         mFlags.Clear(Flags::kControlOpInProgress); | 
 |         mFlags.Set(Flags::kAppRegistered); | 
 |         DriveBLEState(); | 
 |         break; | 
 |     default: | 
 |         break; | 
 |     } | 
 |  | 
 | exit: | 
 |     if (err != CHIP_NO_ERROR) | 
 |     { | 
 |         DisableBLEService(err); | 
 |         mFlags.Clear(Flags::kControlOpInProgress); | 
 |     } | 
 | } | 
 |  | 
 | uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const | 
 | { | 
 |     uint16_t mtu = 0; | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     mtu = conId->GetMTU(); | 
 | exit: | 
 |     return mtu; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, | 
 |                                                    const ChipBleUUID * charId) | 
 | { | 
 |     CHIP_ERROR err = BLE_ERROR_GATT_SUBSCRIBE_FAILED; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), | 
 |                  ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid service ID")); | 
 |     VerifyOrExit(Ble::UUIDsMatch(charId, &Ble::CHIP_BLE_CHAR_2_UUID), | 
 |                  ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid characteristic ID")); | 
 |     err = conId->SubscribeCharacteristic(); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, | 
 |                                                      const ChipBleUUID * charId) | 
 | { | 
 |     CHIP_ERROR err = BLE_ERROR_GATT_UNSUBSCRIBE_FAILED; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), | 
 |                  ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid service ID")); | 
 |     VerifyOrExit(Ble::UUIDsMatch(charId, &Ble::CHIP_BLE_CHAR_2_UUID), | 
 |                  ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid characteristic ID")); | 
 |     err = conId->UnsubscribeCharacteristic(); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     CHIP_ERROR err = CHIP_ERROR_INTERNAL; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %p)", conId); | 
 |     err = conId->CloseConnection(); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, | 
 |                                           chip::System::PacketBufferHandle pBuf) | 
 | { | 
 |     CHIP_ERROR err = BLE_ERROR_GATT_INDICATE_FAILED; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     err = conId->SendIndication(std::move(pBuf)); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | /*CHIP_ERROR BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, | 
 |                                             const Ble::ChipBleUUID * charId, chip::System::PacketBufferHandle pBuf) | 
 | { | 
 |     CHIP_ERROR err = BLE_ERROR_GATT_WRITE_FAILED; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), | 
 |                  ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid service ID")); | 
 |     VerifyOrExit(Ble::UUIDsMatch(charId, &Ble::CHIP_BLE_CHAR_1_UUID), | 
 |                  ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid characteristic ID")); | 
 |     err = conId->SendWriteRequest(std::move(pBuf)); | 
 |  | 
 | exit: | 
 |     return err; | 
 | }*/ | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, | 
 |                                             const Ble::ChipBleUUID * charId, chip::System::PacketBufferHandle pBuf) | 
 | { | 
 |     CHIP_ERROR err = BLE_ERROR_GATT_WRITE_FAILED; | 
 |  | 
 |     VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                  ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |     VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), | 
 |                  ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid service ID")); | 
 |     VerifyOrExit(Ble::UUIDsMatch(charId, &Ble::CHIP_BLE_CHAR_1_UUID), | 
 |                  ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid characteristic ID")); | 
 |     err = conId->SendWriteRequest(std::move(pBuf)); | 
 |  | 
 | exit: | 
 |     return err; | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleNewConnection(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     if (sInstance.mIsCentral) | 
 |     { | 
 |         ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLECentralConnected, | 
 |                                .Platform = { .BLECentralConnected = { .mConnection = conId } } }; | 
 |         PlatformMgr().PostEventOrDie(&event); | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleConnectFailed(CHIP_ERROR error) | 
 | { | 
 |     if (sInstance.mIsCentral) | 
 |     { | 
 |         ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLECentralConnectFailed, | 
 |                                .Platform = { .BLECentralConnectFailed = { .mError = error } } }; | 
 |         PlatformMgr().PostEventOrDie(&event); | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleWriteComplete(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEWriteComplete, | 
 |                            .Platform = { .BLEWriteComplete = { .mConnection = conId } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool subscribed) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLESubscribeOpComplete, | 
 |                            .Platform = { .BLESubscribeOpComplete = { .mConnection = conId, .mIsSubscribed = subscribed } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len) | 
 | { | 
 |     System::PacketBufferHandle buf(System::PacketBufferHandle::NewWithData(value, len)); | 
 |     VerifyOrReturn(!buf.IsNull(), ChipLogError(DeviceLayer, "Failed to allocate packet buffer in %s", __func__)); | 
 |  | 
 |     // ChipLogDetail(DeviceLayer, "Indication received, conn = %p", conId); | 
 |  | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEIndicationReceived, | 
 |                            .Platform = { | 
 |                                .BLEIndicationReceived = { .mConnection = conId, .mData = std::move(buf).UnsafeRelease() } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleRXCharWrite(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len) | 
 | { | 
 |     // Copy the data to a packet buffer. | 
 |     System::PacketBufferHandle buf(System::PacketBufferHandle::NewWithData(value, len)); | 
 |     VerifyOrReturn(!buf.IsNull(), ChipLogError(DeviceLayer, "Failed to allocate packet buffer in %s", __func__)); | 
 |  | 
 |     ChipLogProgress(Ble, "Write request received, conn = %p", conId); | 
 |  | 
 |     // Post an event to the Chip queue to deliver the data into the Chip stack. | 
 |     ChipDeviceEvent event{ .Type                  = DeviceEventType::kCHIPoBLEWriteReceived, | 
 |                            .CHIPoBLEWriteReceived = { .ConId = conId, .Data = std::move(buf).UnsafeRelease() } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleConnectionClosed(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     // If this was a CHIPoBLE connection, post an event to deliver a connection error to the CHIPoBLE layer. | 
 |     ChipDeviceEvent event{ .Type                    = DeviceEventType::kCHIPoBLEConnectionError, | 
 |                            .CHIPoBLEConnectionError = { .ConId = conId, .Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     VerifyOrReturn(conId != BLE_CONNECTION_UNINITIALIZED, | 
 |                    ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); | 
 |  | 
 |     ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", conId->IsNotifyAcquired() ? "subscribe" : "unsubscribe"); | 
 |  | 
 |     // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on | 
 |     // whether the client is enabling or disabling indications. | 
 |     ChipDeviceEvent event{ .Type = conId->IsNotifyAcquired() ? static_cast<uint16_t>(DeviceEventType::kCHIPoBLESubscribe) | 
 |                                                              : static_cast<uint16_t>(DeviceEventType::kCHIPoBLEUnsubscribe), | 
 |                            .CHIPoBLESubscribe = { .ConId = conId } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleTXComplete(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     // Post an event to the Chip queue to process the indicate confirmation. | 
 |     ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoBLEIndicateConfirm, .CHIPoBLEIndicateConfirm = { .ConId = conId } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::DriveBLEState() | 
 | { | 
 |     CHIP_ERROR err = CHIP_NO_ERROR; | 
 |  | 
 |     // Perform any initialization actions that must occur after the Chip task is running. | 
 |     if (!mFlags.Has(Flags::kAsyncInitCompleted)) | 
 |     { | 
 |         mFlags.Set(Flags::kAsyncInitCompleted); | 
 |         ExitNow(); | 
 |     } | 
 |  | 
 |     // If there's already a control operation in progress, wait until it completes. | 
 |     VerifyOrExit(!mFlags.Has(Flags::kControlOpInProgress), /* */); | 
 |  | 
 |     // Initializes the WBS BLE layer if needed. | 
 |     if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled) | 
 |     { | 
 |         if (!mFlags.Has(Flags::kWBSManagerInitialized)) | 
 |         { | 
 |             // SuccessOrExit(err = mBluezObjectManager.Init()); | 
 |             mFlags.Set(Flags::kWBSManagerInitialized); | 
 |         } | 
 |         if (!mFlags.Has(Flags::kWBSAdapterAvailable)) | 
 |         { | 
 |             // mAdapter.reset(mBluezObjectManager.GetAdapter(mAdapterId)); | 
 |             // VerifyOrExit(mAdapter, err = BLE_ERROR_ADAPTER_UNAVAILABLE); | 
 |             mFlags.Set(Flags::kWBSAdapterAvailable); | 
 |         } | 
 |         if (!mFlags.Has(Flags::kWBSBLELayerInitialized)) | 
 |         { | 
 |             SuccessOrExit(err = mConnection.InitConnectionData(mIsCentral, mEndpoint)); | 
 |             mFlags.Set(Flags::kWBSBLELayerInitialized); | 
 |         } | 
 |     } | 
 |  | 
 | exit: | 
 |     if (err != CHIP_NO_ERROR) | 
 |     { | 
 |         DisableBLEService(err); | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::DisableBLEService(CHIP_ERROR err) | 
 | { | 
 |     ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format()); | 
 |     mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; | 
 |     // Stop all timers if the error is other than BLE adapter unavailable. In case of BLE adapter | 
 |     // beeing unavailable, we will keep timers running, as the adapter might become available in | 
 |     // the nearest future (e.g. WBS restart due to crash). By doing that we will ensure that BLE | 
 |     // adapter reappearance will not extend timeouts for the ongoing operations. | 
 |     if (err != BLE_ERROR_ADAPTER_UNAVAILABLE) | 
 |     { | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this); | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this); | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this); | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) | 
 | { | 
 |     ChipLogProgress(Ble, "Got notification regarding chip connection closure"); | 
 | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION | 
 |     if (mState == kState_NotInitialized) | 
 |     { | 
 |         // Close BLE GATT connections to disconnect WBS | 
 |         CloseConnection(conId); | 
 |         // In Non-Concurrent mode start the Wi-Fi, as BLE has been stopped | 
 |         DeviceLayer::ConnectivityMgrImpl().StartNonConcurrentWiFiManagement(); | 
 |     } | 
 | #endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION | 
 | } | 
 |  | 
 | void BLEManagerImpl::CheckNonConcurrentBleClosing() | 
 | { | 
 | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION | 
 |     if (mState == kState_Disconnecting) | 
 |     { | 
 |         DeviceLayer::DeviceControlServer::DeviceControlSvr().PostCloseAllBLEConnectionsToOperationalNetworkEvent(); | 
 |     } | 
 | #endif | 
 | } | 
 |  | 
 | /* | 
 | BluezAdvertisement::AdvertisingIntervals BLEManagerImpl::GetAdvertisingIntervals() const | 
 | { | 
 |     if (mFlags.Has(Flags::kFastAdvertisingEnabled)) | 
 |         return { CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX }; | 
 | #if CHIP_DEVICE_CONFIG_EXT_ADVERTISING | 
 |     if (mFlags.Has(Flags::kExtAdvertisingEnabled)) | 
 |         return { CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX }; | 
 | #endif | 
 |     return { CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX }; | 
 | } | 
 | */ | 
 | void BLEManagerImpl::HandleAdvertisingTimer(chip::System::Layer *, void * appState) | 
 | { | 
 |     auto * self = static_cast<BLEManagerImpl *>(appState); | 
 |  | 
 |     if (self->mFlags.Has(Flags::kFastAdvertisingEnabled)) | 
 |     { | 
 |         ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement"); | 
 |         self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); | 
 | #if CHIP_DEVICE_CONFIG_EXT_ADVERTISING | 
 |         self->mFlags.Clear(Flags::kExtAdvertisingEnabled); | 
 |         DeviceLayer::SystemLayer().StartTimer(kSlowAdvertiseTimeout, HandleAdvertisingTimer, self); | 
 |     } | 
 |     else | 
 |     { | 
 |         ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start extended advertisement"); | 
 |         self->mFlags.Set(Flags::kExtAdvertisingEnabled); | 
 |         // This will trigger advertising intervals update in the DriveBLEState() function. | 
 |         self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); | 
 | #endif | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::InitiateScan(BleScanState scanType) | 
 | { | 
 |     CHIP_ERROR err = CHIP_ERROR_INCORRECT_STATE; | 
 |  | 
 |     DriveBLEState(); | 
 |  | 
 |     VerifyOrExit(scanType != BleScanState::kNotScanning, | 
 |                  ChipLogError(Ble, "Invalid scan type requested: %d", to_underlying(scanType))); | 
 |     VerifyOrExit(!mDeviceScanner.IsScanning(), ChipLogError(Ble, "BLE scan already in progress")); | 
 |     VerifyOrExit(mFlags.Has(Flags::kWBSAdapterAvailable), err = BLE_ERROR_ADAPTER_UNAVAILABLE); | 
 |  | 
 |     mBLEScanConfig.mBleScanState = scanType; | 
 |  | 
 |     err = mDeviceScanner.Init(this); | 
 |     VerifyOrExit(err == CHIP_NO_ERROR, { | 
 |         mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; | 
 |         ChipLogError(Ble, "Failed to create BLE device scanner: %" CHIP_ERROR_FORMAT, err.Format()); | 
 |     }); | 
 |  | 
 |     err = mDeviceScanner.StartScan(); | 
 |     VerifyOrExit(err == CHIP_NO_ERROR, { | 
 |         mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; | 
 |         ChipLogError(Ble, "Failed to start BLE scan: %" CHIP_ERROR_FORMAT, err.Format()); | 
 |     }); | 
 |  | 
 |     err = DeviceLayer::SystemLayer().StartTimer(kNewConnectionScanTimeout, HandleScanTimer, this); | 
 |     VerifyOrExit(err == CHIP_NO_ERROR, { | 
 |         mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; | 
 |         mDeviceScanner.StopScan(); | 
 |         ChipLogError(Ble, "Failed to start BLE scan timeout: %" CHIP_ERROR_FORMAT, err.Format()); | 
 |     }); | 
 |  | 
 | exit: | 
 |     if (err != CHIP_NO_ERROR) | 
 |     { | 
 |         BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err); | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleScanTimer(chip::System::Layer *, void * appState) | 
 | { | 
 |     auto * manager = static_cast<BLEManagerImpl *>(appState); | 
 |     manager->OnScanError(CHIP_ERROR_TIMEOUT); | 
 |     manager->mDeviceScanner.StopScan(); | 
 | } | 
 |  | 
 | void BLEManagerImpl::CleanScanConfig() | 
 | { | 
 |     if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting) | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this); | 
 |  | 
 |     mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; | 
 | } | 
 |  | 
 | void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) | 
 | { | 
 |     mBLEScanConfig.mDiscriminator = connDiscriminator; | 
 |     mBLEScanConfig.mAppState      = appState; | 
 |  | 
 |     // Scan initiation performed async, to ensure that the BLE subsystem is initialized. | 
 |     DeviceLayer::SystemLayer().ScheduleLambda([this] { InitiateScan(BleScanState::kScanForDiscriminator); }); | 
 | } | 
 |  | 
 | CHIP_ERROR BLEManagerImpl::CancelConnection() | 
 | { | 
 |     if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting) | 
 |     { | 
 |         ChipLogProgress(Ble, "CancelConnection BleScanState::kConnecting"); | 
 |         mConnection.CancelConnect(); | 
 |     } | 
 |     // If in discovery mode, stop scan. | 
 |     else if (mBLEScanConfig.mBleScanState != BleScanState::kNotScanning) | 
 |     { | 
 |         ChipLogProgress(Ble, "CancelConnection  != BleScanState::kNotScanning"); | 
 |         DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this); | 
 |         mDeviceScanner.StopScan(); | 
 |     } | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEAdapterAdded(unsigned int aAdapterId, const char * aAdapterAddress) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEAdapterAdded, | 
 |                            .Platform = { .BLEAdapter = { .mAdapterId = aAdapterId } } }; | 
 |     Platform::CopyString(event.Platform.BLEAdapter.mAdapterAddress, aAdapterAddress); | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEAdapterRemoved(unsigned int aAdapterId, const char * aAdapterAddress) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEAdapterRemoved, | 
 |                            .Platform = { .BLEAdapter = { .mAdapterId = aAdapterId } } }; | 
 |     Platform::CopyString(event.Platform.BLEAdapter.mAdapterAddress, aAdapterAddress); | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(CHIP_ERROR error) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEPeripheralRegisterAppComplete, | 
 |                            .Platform = { .BLEPeripheralRegisterAppComplete = { .mError = error } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(CHIP_ERROR error) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEPeripheralAdvStartComplete, | 
 |                            .Platform = { .BLEPeripheralAdvStartComplete = { .mError = error } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(CHIP_ERROR error) | 
 | { | 
 |     ChipDeviceEvent event{ .Type     = DeviceEventType::kPlatformWebOSBLEPeripheralAdvStopComplete, | 
 |                            .Platform = { .BLEPeripheralAdvStopComplete = { .mError = error } } }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::NotifyBLEPeripheralAdvReleased() | 
 | { | 
 |     ChipDeviceEvent event{ .Type = DeviceEventType::kPlatformWebOSBLEPeripheralAdvReleased }; | 
 |     PlatformMgr().PostEventOrDie(&event); | 
 | } | 
 |  | 
 | void BLEManagerImpl::OnDeviceScanned(const pbnjson::JValue & device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) | 
 | { | 
 |     ChipLogProgress(Ble, "New device scanned: %s discriminator : %u", device["address"].asString().c_str(), | 
 |                     info.GetDeviceDiscriminator()); | 
 |  | 
 |     if (mBLEScanConfig.mBleScanState == BleScanState::kScanForDiscriminator) | 
 |     { | 
 |         auto isMatch = mBLEScanConfig.mDiscriminator.MatchesLongDiscriminator(info.GetDeviceDiscriminator()); | 
 |         VerifyOrReturn( | 
 |             isMatch, | 
 |             ChipLogError(Ble, "Skip connection: Device discriminator does not match: %u != %u", info.GetDeviceDiscriminator(), | 
 |                          mBLEScanConfig.mDiscriminator.IsShortDiscriminator() ? mBLEScanConfig.mDiscriminator.GetShortValue() | 
 |                                                                               : mBLEScanConfig.mDiscriminator.GetLongValue())); | 
 |         ChipLogProgress(Ble, "Device discriminator match. Attempting to connect."); | 
 |     } | 
 |     else if (mBLEScanConfig.mBleScanState == BleScanState::kScanForAddress) | 
 |     { | 
 |         auto isMatch = strcmp(device["address"].asString().c_str(), mBLEScanConfig.mAddress.c_str()) == 0; | 
 |         VerifyOrReturn(isMatch, | 
 |                        ChipLogError(Ble, "Skip connection: Device address does not match: %s != %s", | 
 |                                     device["address"].asString().c_str(), mBLEScanConfig.mAddress.c_str())); | 
 |         ChipLogProgress(Ble, "Device address match. Attempting to connect."); | 
 |     } | 
 |     else | 
 |     { | 
 |         // Internal consistency error | 
 |         ChipLogError(Ble, "Unknown discovery type. Ignoring scanned device."); | 
 |         return; | 
 |     } | 
 |     ChipLogProgress(Ble, "Device address match. Attempting to connect."); | 
 |     mBLEScanConfig.mBleScanState = BleScanState::kConnecting; | 
 |     mBLEScanConfig.mAddress      = device["address"].asString(); | 
 |     chip::DeviceLayer::PlatformMgr().LockChipStack(); | 
 |     // We StartScan in the ChipStack thread. | 
 |     // StopScan should also be performed in the ChipStack thread. | 
 |     // At the same time, the scan timer also needs to be canceled in the ChipStack thread. | 
 |     DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this); | 
 |     mDeviceScanner.StopScan(); | 
 |     // Stop scanning and then start connecting timer | 
 |     DeviceLayer::SystemLayer().StartTimer(kConnectTimeout, HandleConnectTimer, this); | 
 |     chip::DeviceLayer::PlatformMgr().UnlockChipStack(); | 
 |     CHIP_ERROR err = mConnection.ConnectDevice(mBLEScanConfig.mAddress, mEndpoint); | 
 |     VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Ble, "Device connection failed: %" CHIP_ERROR_FORMAT, err.Format())); | 
 |  | 
 |     ChipLogProgress(Ble, "New device connected: %s", mBLEScanConfig.mAddress.c_str()); | 
 | } | 
 |  | 
 | void BLEManagerImpl::HandleConnectTimer(chip::System::Layer *, void * appState) | 
 | { | 
 |     ChipLogProgress(Ble, "HandleConnectTimer "); | 
 |     auto * manager = static_cast<BLEManagerImpl *>(appState); | 
 |     manager->mConnection.CancelConnect(); | 
 |     BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_TIMEOUT); | 
 | } | 
 |  | 
 | void BLEManagerImpl::OnScanComplete() | 
 | { | 
 |     switch (mBLEScanConfig.mBleScanState) | 
 |     { | 
 |     case BleScanState::kNotScanning: | 
 |         ChipLogProgress(Ble, "Scan complete notification without an active scan."); | 
 |         break; | 
 |     case BleScanState::kScanForAddress: | 
 |     case BleScanState::kScanForDiscriminator: | 
 |         mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; | 
 |         ChipLogProgress(Ble, "Scan complete. No matching device found."); | 
 |         break; | 
 |     case BleScanState::kConnecting: | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | void BLEManagerImpl::OnScanError(CHIP_ERROR err) | 
 | { | 
 |     BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err); | 
 |     ChipLogError(Ble, "BLE scan error: %" CHIP_ERROR_FORMAT, err.Format()); | 
 | } | 
 |  | 
 | } // namespace Internal | 
 | } // namespace DeviceLayer | 
 | } // namespace chip |