diff --git a/src/platform/telink/BLEManagerImpl.cpp b/src/platform/telink/BLEManagerImpl.cpp index d8f838142b245e..5f7fc1c09c77c4 100644 --- a/src/platform/telink/BLEManagerImpl.cpp +++ b/src/platform/telink/BLEManagerImpl.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2020-2022 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. @@ -167,28 +167,72 @@ K_THREAD_DEFINE(chipBleThread, CHIP_BLE_THREAD_STACK_SIZE, BLEManagerImpl::BleEn CHIP_ERROR BLEManagerImpl::_Init() { - CHIP_ERROR err = CHIP_NO_ERROR; - ThreadConnectivityReady = false; - /* Initialize the CHIP BleLayer. */ - err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); - SuccessOrExit(err); - - /* Set number of connections to zero */ - mNumConnections = 0; + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + mGAPConns = 0; - /* Unsubscribe all connections */ memset(mSubscribedConns, 0, sizeof(mSubscribedConns)); - /* Enable CHIP over BLE service */ - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + // Initialize the CHIP BleLayer. + ReturnErrorOnFailure(BleLayer::Init(this, this, &DeviceLayer::SystemLayer())); - /* Suspend BLE Task */ + // Suspend BLE Task k_thread_suspend(chipBleThread); + return CHIP_NO_ERROR; +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + BLEMgrImpl().DriveBLEState(); +} + +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); + } + + // If the application has enabled CHIPoBLE and BLE advertising... + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && + mFlags.Has(Flags::kAdvertisingEnabled) +#if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION + // and no connections are active... + && (NumConnections() == 0) +#endif + ) + { + // Start/re-start advertising if not already advertising, or if the + // advertising state needs to be refreshed. + if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded)) + { + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + err = StartAdvertising(); + SuccessOrExit(err); + } + } + else + { + if (mFlags.Has(Flags::kAdvertising)) + { + err = StopAdvertising(); + SuccessOrExit(err); + } + } + exit: - return err; + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format()); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } } int BLEManagerImpl::RxWriteCallback(uint16_t connHandle, void * p) @@ -543,13 +587,15 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) { CHIP_ERROR err = CHIP_NO_ERROR; - if (val) - { - err = StartAdvertising(); - } - else + VerifyOrReturnError(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, + CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (mFlags.Has(Flags::kAdvertisingEnabled) != val) { - err = StopAdvertising(); + ChipLogDetail(DeviceLayer, "CHIPoBLE advertising set to %s", val ? "on" : "off"); + + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); } return err; @@ -616,7 +662,29 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) return CHIP_ERROR_INCORRECT_STATE; } - mFlags.Set(Flags::kAdvertising); + // Transition to the Advertising state... + if (!mFlags.Has(Flags::kAdvertising)) + { + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); + + mFlags.Set(Flags::kAdvertising); + + // Post a CHIPoBLEAdvertisingChange(Started) event. + { + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&advChange)); + } + + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + // Start timer to change advertising interval. + DeviceLayer::SystemLayer().StartTimer( + System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME), + HandleBLEAdvertisementIntervalChange, this); + } + } /* Start BLE Task */ k_thread_resume(chipBleThread); @@ -632,7 +700,7 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising(void) { ChipLogProgress(DeviceLayer, "Thread provisioned. Advertisement already stopped at this stage"); - return CHIP_NO_ERROR; + return CHIP_ERROR_INCORRECT_STATE; } /* Disable advertisement */ @@ -644,14 +712,44 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising(void) return CHIP_ERROR_INCORRECT_STATE; } - mFlags.Clear(Flags::kAdvertising); + // Transition to the not Advertising state... + if (mFlags.Has(Flags::kAdvertising)) + { + mFlags.Clear(Flags::kAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); + + // Post a CHIPoBLEAdvertisingChange(Stopped) event. + { + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&advChange)); + } + + // Cancel timer event changing CHIPoBLE advertisement interval + DeviceLayer::SystemLayer().CancelTimer(HandleBLEAdvertisementIntervalChange, this); + } return CHIP_NO_ERROR; } -/// @todo: implementation 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); + PlatformMgr().ScheduleWork(DriveBLEState, 0); return CHIP_NO_ERROR; } @@ -698,6 +796,12 @@ CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * devName) return CHIP_NO_ERROR; } +void BLEManagerImpl::HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param) +{ + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to slow"); +} + void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -747,6 +851,8 @@ void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Fail to handle 0x%04x event. Error: %s", event->Type, ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + PlatformMgr().ScheduleWork(DriveBLEState, 0); } } @@ -822,7 +928,7 @@ void BLEManagerImpl::SwitchToIeee802154(void) ChipLogProgress(DeviceLayer, "BLEManagerImpl::Switch to IEEE802154"); /* Stop BLE */ - StopAdvertising(); + _SetAdvertisingEnabled(false); /* Stop BLE task */ k_thread_suspend(chipBleThread); @@ -845,7 +951,7 @@ void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {} uint16_t BLEManagerImpl::_NumConnections(void) { - return mNumConnections; + return mGAPConns; } /// @todo implement multicinnection subscription @@ -876,36 +982,41 @@ CHIP_ERROR BLEManagerImpl::HandleGAPConnect(const ChipDeviceEvent * event) { const BleConnEventType * connEvent = &event->Platform.BleConnEvent; - /* Increase number of connections */ - mNumConnections++; - ChipLogProgress(DeviceLayer, "BLE connection established (ConnId: 0x%02x)", connEvent->connHandle); + mGAPConns++; ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", NumConnections(), kMaxConnections); + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; } CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(const ChipDeviceEvent * event) { const BleConnEventType * connEvent = &event->Platform.BleConnEvent; - ChipDeviceEvent disconnectEvent; - - /* Decrease number of connections */ - mNumConnections--; ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (reason 0x%02x)", connEvent->HciResult); + + mGAPConns--; + ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", NumConnections(), kMaxConnections); - /* Unsubscribe */ + // Unsubscribe if (UnsetSubscribed(connEvent->connHandle)) { HandleUnsubscribeReceived(connEvent->connHandle, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); } - /* Send Connection close event */ + ChipDeviceEvent disconnectEvent; disconnectEvent.Type = DeviceEventType::kCHIPoBLEConnectionClosed; ReturnErrorOnFailure(PlatformMgr().PostEvent(&disconnectEvent)); + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; } @@ -926,6 +1037,11 @@ CHIP_ERROR BLEManagerImpl::HandleDisconnectRequest(const ChipDeviceEvent * event return CHIP_ERROR_INCORRECT_STATE; } + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; } diff --git a/src/platform/telink/BLEManagerImpl.h b/src/platform/telink/BLEManagerImpl.h index 86aae895197582..d1b79718b347b7 100644 --- a/src/platform/telink/BLEManagerImpl.h +++ b/src/platform/telink/BLEManagerImpl.h @@ -107,7 +107,7 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla CHIPoBLEServiceMode mServiceMode; BitFlags mFlags; char mDeviceName[kMaxDeviceNameLength + 1]; - uint16_t mNumConnections; + uint16_t mGAPConns; bool mSubscribedConns[kMaxConnections]; uint8_t mAdvDataBuf[kMaxAdvertisementDataSetSize]; uint8_t mScanRespDataBuf[kMaxAdvertisementDataSetSize]; @@ -144,6 +144,8 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla /* Callbacks from BLE stack*/ static void DriveBLEState(intptr_t arg); + static void HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param); + /* Handlers for stack events */ static void CancelBleAdvTimeoutTimer(void); static void StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs);