3 * Copyright (c) 2020-2021 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * Provides an implementation of the BLEManager singleton object
22 * for the ESP32 (NimBLE) platform.
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
27 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
29 #include "sdkconfig.h"
31 #if CONFIG_BT_NIMBLE_ENABLED
33 #include <ble/CHIPBleServiceData.h>
34 #include <platform/internal/BLEManager.h>
35 #include <support/CodeUtils.h>
36 #include <support/logging/CHIPLogging.h>
37 #include <system/SystemTimer.h>
40 #include "esp_nimble_hci.h"
41 #include "host/ble_hs.h"
42 #include "host/ble_hs_pvcy.h"
43 #include "host/ble_uuid.h"
44 #include "host/util/util.h"
45 #include "nimble/nimble_port.h"
46 #include "nimble/nimble_port_freertos.h"
47 #include "services/gap/ble_svc_gap.h"
48 #include "services/gatt/ble_svc_gatt.h"
50 #define MAX_ADV_DATA_LEN 31
51 #define CHIP_ADV_DATA_TYPE_FLAGS 0x01
52 #define CHIP_ADV_DATA_FLAGS 0x06
53 #define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16
55 using namespace ::chip;
56 using namespace ::chip::Ble;
59 namespace DeviceLayer {
64 struct ESP32ChipServiceData
66 uint8_t ServiceUUID[2];
67 ChipBLEDeviceIdentificationInfo DeviceIdInfo;
70 const ble_uuid128_t UUID_CHIPoBLEService = {
71 BLE_UUID_TYPE_128, { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAF, 0xFE, 0x00, 0x00 }
73 const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFEAF };
75 const ble_uuid128_t UUID128_CHIPoBLEChar_RX = {
76 BLE_UUID_TYPE_128, { 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 }
78 const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
80 const ble_uuid128_t UUID_CHIPoBLEChar_RX = {
81 { BLE_UUID_TYPE_128 }, { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, 0x11 }
84 const ble_uuid128_t UUID128_CHIPoBLEChar_TX = {
85 BLE_UUID_TYPE_128, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 }
87 const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
89 const ble_uuid128_t UUID_CHIPoBLEChar_TX = {
90 { BLE_UUID_TYPE_128 }, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 }
93 } // unnamed namespace
95 BLEManagerImpl BLEManagerImpl::sInstance;
97 BLEManagerImpl::BLEManagerImpl() :
98 mAdvertiseTimerCallback(HandleAdvertisementTimer, this), mFastAdvertiseTimerCallback(HandleFastAdvertisementTimer, this)
101 const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTAttrs[] = {
102 { .type = BLE_GATT_SVC_TYPE_PRIMARY,
103 .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService),
105 (struct ble_gatt_chr_def[]){
107 .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX),
108 .access_cb = gatt_svr_chr_access,
109 .flags = BLE_GATT_CHR_F_WRITE,
110 .val_handle = &sInstance.mRXCharAttrHandle,
113 .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX),
114 .access_cb = gatt_svr_chr_access,
115 .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
116 .val_handle = &sInstance.mTXCharCCCDAttrHandle,
119 0, /* No more characteristics in this service */
124 0, /* No more services. */
128 CHIP_ERROR BLEManagerImpl::_Init()
132 // Initialize the Chip BleLayer.
133 err = BleLayer::Init(this, this, &SystemLayer);
136 mRXCharAttrHandle = 0;
137 mTXCharCCCDAttrHandle = 0;
138 mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART);
139 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
141 memset(mCons, 0, sizeof(mCons));
142 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
143 memset(mDeviceName, 0, sizeof(mDeviceName));
145 PlatformMgr().ScheduleWork(DriveBLEState, 0);
151 CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val)
153 CHIP_ERROR err = CHIP_NO_ERROR;
155 VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
156 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
158 if (val != mServiceMode)
161 PlatformMgr().ScheduleWork(DriveBLEState, 0);
168 CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
170 CHIP_ERROR err = CHIP_NO_ERROR;
172 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
176 mAdvertiseStartTime = System::Timer::GetCurrentEpoch();
177 SystemLayer.StartTimer(kAdvertiseTimeout, &mAdvertiseTimerCallback);
178 SystemLayer.StartTimer(kFastAdvertiseTimeout, &mFastAdvertiseTimerCallback);
181 mFlags.Set(Flags::kFastAdvertisingEnabled, val);
182 mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1);
183 mFlags.Set(Flags::kAdvertisingEnabled, val);
184 PlatformMgr().ScheduleWork(DriveBLEState, 0);
190 void BLEManagerImpl::HandleAdvertisementTimer(void * context)
192 static_cast<BLEManagerImpl *>(context)->HandleAdvertisementTimer();
195 void BLEManagerImpl::HandleAdvertisementTimer()
197 uint64_t currentTimestamp = System::Timer::GetCurrentEpoch();
199 if (currentTimestamp - mAdvertiseStartTime >= kAdvertiseTimeout)
201 mFlags.Set(Flags::kAdvertisingEnabled, 0);
202 PlatformMgr().ScheduleWork(DriveBLEState, 0);
206 void BLEManagerImpl::HandleFastAdvertisementTimer(void * context)
208 static_cast<BLEManagerImpl *>(context)->HandleFastAdvertisementTimer();
211 void BLEManagerImpl::HandleFastAdvertisementTimer()
213 uint64_t currentTimestamp = System::Timer::GetCurrentEpoch();
215 if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout)
217 mFlags.Set(Flags::kFastAdvertisingEnabled, 0);
218 mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1);
219 PlatformMgr().ScheduleWork(DriveBLEState, 0);
223 CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
227 case BLEAdvertisingMode::kFastAdvertising:
228 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
230 case BLEAdvertisingMode::kSlowAdvertising:
231 mFlags.Set(Flags::kFastAdvertisingEnabled, false);
234 return CHIP_ERROR_INVALID_ARGUMENT;
236 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
237 PlatformMgr().ScheduleWork(DriveBLEState, 0);
238 return CHIP_NO_ERROR;
241 CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
243 if (strlen(mDeviceName) >= bufSize)
245 return CHIP_ERROR_BUFFER_TOO_SMALL;
247 strcpy(buf, mDeviceName);
248 return CHIP_NO_ERROR;
251 CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
253 CHIP_ERROR err = CHIP_NO_ERROR;
255 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
256 if (deviceName != NULL && deviceName[0] != 0)
258 if (strlen(deviceName) >= kMaxDeviceNameLength)
260 return CHIP_ERROR_INVALID_ARGUMENT;
262 strcpy(mDeviceName, deviceName);
263 mFlags.Set(Flags::kUseCustomDeviceName);
268 mFlags.Clear(Flags::kUseCustomDeviceName);
275 void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
279 case DeviceEventType::kCHIPoBLESubscribe:
280 HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
282 ChipDeviceEvent connectionEvent;
283 connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
284 PlatformMgr().PostEvent(&connectionEvent);
288 case DeviceEventType::kCHIPoBLEUnsubscribe:
289 HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
292 case DeviceEventType::kCHIPoBLEWriteReceived:
293 HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX,
294 PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
297 case DeviceEventType::kCHIPoBLEIndicateConfirm:
298 HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
301 case DeviceEventType::kCHIPoBLEConnectionError:
302 HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
305 case DeviceEventType::kFabricMembershipChange:
306 case DeviceEventType::kServiceProvisioningChange:
307 case DeviceEventType::kAccountPairingChange:
308 case DeviceEventType::kWiFiConnectivityChange:
310 // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the
311 // device's provisioning state, then automatically disable CHIPoBLE advertising if the device
312 // is now fully provisioned.
313 #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
314 if (ConfigurationMgr().IsFullyProvisioned())
316 mFlags.Clear(Flags::kAdvertisingEnabled);
317 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
319 #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
321 // Force the advertising configuration to be refreshed to reflect new provisioning state.
322 ChipLogProgress(DeviceLayer, "Updating advertising data");
323 mFlags.Clear(Flags::kAdvertisingConfigured);
324 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
334 bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
336 ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported");
340 bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
342 ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported");
346 bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
350 ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId);
352 // Signal the ESP BLE layer to close the conneecction.
353 err = ble_gap_terminate(conId, BLE_ERR_REM_USER_CONN_TERM);
354 if (err != CHIP_NO_ERROR)
356 ChipLogError(DeviceLayer, "ble_gap_terminate() failed: %s", ErrorStr(err));
359 // Force a refresh of the advertising state.
360 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
361 mFlags.Clear(Flags::kAdvertisingConfigured);
362 PlatformMgr().ScheduleWork(DriveBLEState, 0);
364 return (err == CHIP_NO_ERROR);
367 uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
369 return ble_att_mtu(conId);
372 bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
373 PacketBufferHandle data)
375 CHIP_ERROR err = CHIP_NO_ERROR;
378 VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT);
380 ESP_LOGD(TAG, "Sending indication for CHIPoBLE TX characteristic (con %u, len %u)", conId, data->DataLength());
382 om = ble_hs_mbuf_from_flat(data->Start(), data->DataLength());
385 ChipLogError(DeviceLayer, "ble_hs_mbuf_from_flat failed:");
386 err = CHIP_ERROR_NO_MEMORY;
390 err = ble_gattc_notify_custom(conId, mTXCharCCCDAttrHandle, om);
391 if (err != CHIP_NO_ERROR)
393 ChipLogError(DeviceLayer, "ble_gattc_notify_custom() failed: %s", ErrorStr(err));
398 if (err != CHIP_NO_ERROR)
400 ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err));
406 bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
407 PacketBufferHandle pBuf)
409 ChipLogError(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported");
413 bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
414 PacketBufferHandle pBuf)
416 ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported");
420 bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
421 const ChipBleUUID * svcId, const ChipBleUUID * charId)
423 ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported");
427 void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {}
429 void BLEManagerImpl::DriveBLEState(void)
432 CHIP_ERROR err = CHIP_NO_ERROR;
434 // Perform any initialization actions that must occur after the Chip task is running.
435 if (!mFlags.Has(Flags::kAsyncInitCompleted))
437 mFlags.Set(Flags::kAsyncInitCompleted);
439 // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled,
440 // disable CHIPoBLE advertising if the device is fully provisioned.
441 #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
442 if (ConfigurationMgr().IsFullyProvisioned())
444 mFlags.Clear(Flags::kAdvertisingEnabled);
445 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
447 #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
450 // Initializes the ESP BLE layer if needed.
451 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kESPBLELayerInitialized))
453 err = InitESPBleLayer();
456 // Add delay of 500msec while NimBLE host task gets up and running
458 vTaskDelay(500 / portTICK_RATE_MS);
462 // If the application has enabled CHIPoBLE and BLE advertising...
463 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled &&
464 mFlags.Has(Flags::kAdvertisingEnabled)
465 #if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION
466 // and no connections are active...
467 && (_NumConnections() == 0)
471 // Start/re-start advertising if not already advertising, or if the advertising state of the
472 // ESP BLE layer needs to be refreshed.
473 if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded))
475 // Configure advertising data if it hasn't been done yet. This is an asynchronous step which
476 // must complete before advertising can be started. When that happens, this method will
477 // be called again, and execution will proceed to the code below.
478 if (!mFlags.Has(Flags::kAdvertisingConfigured))
480 err = ConfigureAdvertisingData();
481 if (err != CHIP_NO_ERROR)
483 ChipLogError(DeviceLayer, "Configure Adv Data failed: %s", ErrorStr(err));
488 // Start advertising. This is also an asynchronous step.
489 ESP_LOGD(TAG, "NimBLE start advertising...");
490 err = StartAdvertising();
491 if (err != CHIP_NO_ERROR)
493 ChipLogError(DeviceLayer, "Start advertising failed: %s", ErrorStr(err));
497 mFlags.Clear(Flags::kAdvertisingRefreshNeeded);
498 // Transition to the Advertising state...
499 if (!mFlags.Has(Flags::kAdvertising))
501 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started");
503 mFlags.Set(Flags::kAdvertising);
505 // Post a CHIPoBLEAdvertisingChange(Started) event.
507 ChipDeviceEvent advChange;
508 advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
509 advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started;
510 PlatformMgr().PostEvent(&advChange);
516 // Otherwise stop advertising if needed...
519 if (mFlags.Has(Flags::kAdvertising))
521 ret = ble_gap_adv_stop();
524 err = CHIP_ERROR_INTERNAL;
525 ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s", ErrorStr(err));
529 // mFlags.Clear(Flags::kAdvertisingRefreshNeeded);
531 // Transition to the not Advertising state...
532 if (mFlags.Has(Flags::kAdvertising))
534 mFlags.Clear(Flags::kAdvertising);
535 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
537 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped");
539 // Directly inform the ThreadStackManager that CHIPoBLE advertising has stopped.
540 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
541 ThreadStackMgr().OnCHIPoBLEAdvertisingStop();
542 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
544 // Post a CHIPoBLEAdvertisingChange(Stopped) event.
546 ChipDeviceEvent advChange;
547 advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
548 advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped;
549 PlatformMgr().PostEvent(&advChange);
557 // Stop the CHIPoBLE GATT service if needed.
558 if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kGATTServiceStarted))
560 // TODO: Not supported
564 if (err != CHIP_NO_ERROR)
566 ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
567 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
571 void BLEManagerImpl::bleprph_on_reset(int reason)
573 ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason);
576 void BLEManagerImpl::bleprph_on_sync(void)
578 sInstance.mFlags.Set(Flags::kESPBLELayerInitialized);
579 sInstance.mFlags.Set(Flags::kGATTServiceStarted);
580 ESP_LOGI(TAG, "BLE host-controller synced");
583 void BLEManagerImpl::bleprph_host_task(void * param)
585 ESP_LOGD(TAG, "BLE Host Task Started");
586 /* This function will return only when nimble_port_stop() is executed */
588 nimble_port_freertos_deinit();
591 CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void)
593 CHIP_ERROR err = CHIP_NO_ERROR;
595 VerifyOrExit(!mFlags.Has(Flags::kESPBLELayerInitialized), /* */);
597 for (int i = 0; i < kMaxConnections; i++)
599 mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED;
602 err = esp_nimble_hci_and_controller_init();
607 /* Initialize the NimBLE host configuration. */
608 ble_hs_cfg.reset_cb = bleprph_on_reset;
609 ble_hs_cfg.sync_cb = bleprph_on_sync;
610 ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
611 ble_hs_cfg.sm_bonding = 1;
612 ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
613 ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
615 // Register the CHIPoBLE GATT attributes with the ESP BLE layer if needed.
616 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled)
621 err = ble_gatts_count_cfg(CHIPoBLEGATTAttrs);
622 if (err != CHIP_NO_ERROR)
624 ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err));
628 err = ble_gatts_add_svcs(CHIPoBLEGATTAttrs);
629 if (err != CHIP_NO_ERROR)
631 ChipLogError(DeviceLayer, "ble_gatts_add_svcs failed: %s", ErrorStr(err));
636 nimble_port_freertos_init(bleprph_host_task);
642 CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void)
645 uint8_t advData[MAX_ADV_DATA_LEN];
648 // If a custom device name has not been specified, generate a CHIP-standard name based on the
649 // bottom digits of the Chip device id.
650 uint16_t discriminator;
651 SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator));
653 if (!mFlags.Has(Flags::kUseCustomDeviceName))
655 snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator);
656 mDeviceName[kMaxDeviceNameLength] = 0;
659 // Configure the BLE device name.
660 err = ble_svc_gap_device_name_set(mDeviceName);
661 if (err != CHIP_NO_ERROR)
663 ChipLogError(DeviceLayer, "ble_svc_gap_device_name_set() failed: %s", ErrorStr(err));
667 memset(advData, 0, sizeof(advData));
668 advData[index++] = 0x02; // length
669 advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags
670 advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value
671 advData[index++] = 0x0A; // length
672 advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID)
673 advData[index++] = static_cast<uint8_t>(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value
674 advData[index++] = static_cast<uint8_t>((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value
676 chip::Ble::ChipBLEDeviceIdentificationInfo deviceIdInfo;
677 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo);
678 if (err != CHIP_NO_ERROR)
680 ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err));
684 VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = BLE_ERROR_OUTBOUND_MESSAGE_TOO_BIG);
685 memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo));
686 index = static_cast<uint8_t>(index + sizeof(deviceIdInfo));
688 // Construct the Chip BLE Service Data to be sent in the scan response packet.
689 err = ble_gap_adv_set_data(advData, sizeof(advData));
690 if (err != CHIP_NO_ERROR)
692 ChipLogError(DeviceLayer, "ble_gap_adv_set_data failed: %s %d", ErrorStr(err), discriminator);
700 void BLEManagerImpl::HandleRXCharWrite(struct ble_gatt_char_context * param)
702 CHIP_ERROR err = CHIP_NO_ERROR;
703 uint16_t data_len = 0;
705 ESP_LOGI(TAG, "Write request received for CHIPoBLE RX characteristic con %u %u", param->conn_handle, param->attr_handle);
707 // Copy the data to a packet buffer.
708 data_len = OS_MBUF_PKTLEN(param->ctxt->om);
709 PacketBufferHandle buf = System::PacketBufferHandle::New(data_len, 0);
710 VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
711 VerifyOrExit(buf->AvailableDataLength() >= data_len, err = CHIP_ERROR_BUFFER_TOO_SMALL);
712 ble_hs_mbuf_to_flat(param->ctxt->om, buf->Start(), data_len, NULL);
713 buf->SetDataLength(data_len);
715 // Post an event to the Chip queue to deliver the data into the Chip stack.
717 ChipDeviceEvent event;
718 event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
719 event.CHIPoBLEWriteReceived.ConId = param->conn_handle;
720 event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease();
721 PlatformMgr().PostEvent(&event);
725 if (err != CHIP_NO_ERROR)
727 ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
731 void BLEManagerImpl::HandleTXCharRead(struct ble_gatt_char_context * param)
734 ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharRead() not supported");
737 void BLEManagerImpl::HandleTXCharCCCDRead(void * param)
740 ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharCCCDRead() not supported");
743 void BLEManagerImpl::HandleTXCharCCCDWrite(struct ble_gap_event * gapEvent)
745 CHIP_ERROR err = CHIP_NO_ERROR;
746 bool indicationsEnabled;
747 bool notificationsEnabled;
749 ChipLogProgress(DeviceLayer,
750 "Write request/command received for CHIPoBLE TX CCCD characteristic (con %" PRIu16
751 " ) indicate = %d notify = %d",
752 gapEvent->subscribe.conn_handle, gapEvent->subscribe.cur_indicate, gapEvent->subscribe.cur_notify);
754 // Determine if the client is enabling or disabling indications/notification.
755 indicationsEnabled = gapEvent->subscribe.cur_indicate;
756 notificationsEnabled = gapEvent->subscribe.cur_notify;
758 // If the client has requested to enabled indications/notifications
759 if (indicationsEnabled || notificationsEnabled)
761 // If indications are not already enabled for the connection...
762 if (!IsSubscribed(gapEvent->subscribe.conn_handle))
764 // Record that indications have been enabled for this connection. If this fails because
765 err = SetSubscribed(gapEvent->subscribe.conn_handle);
766 VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR);
773 // If indications had previously been enabled for this connection, record that they are no longer
775 UnsetSubscribed(gapEvent->subscribe.conn_handle);
778 // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on
779 // whether the client is enabling or disabling indications.
781 ChipDeviceEvent event;
782 event.Type = (indicationsEnabled || notificationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe
783 : DeviceEventType::kCHIPoBLEUnsubscribe;
784 event.CHIPoBLESubscribe.ConId = gapEvent->subscribe.conn_handle;
785 PlatformMgr().PostEvent(&event);
788 ChipLogProgress(DeviceLayer, "CHIPoBLE %s received",
789 (indicationsEnabled || notificationsEnabled) ? "subscribe" : "unsubscribe");
792 if (err != CHIP_NO_ERROR)
794 ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err));
795 // TODO: fail connection???
801 CHIP_ERROR BLEManagerImpl::HandleTXComplete(struct ble_gap_event * gapEvent)
803 ChipLogProgress(DeviceLayer, "Confirm received for CHIPoBLE TX characteristic indication (con %" PRIu16 ") status= %d ",
804 gapEvent->notify_tx.conn_handle, gapEvent->notify_tx.status);
806 // Signal the BLE Layer that the outstanding indication is complete.
807 if (gapEvent->notify_tx.status == 0 || gapEvent->notify_tx.status == BLE_HS_EDONE)
809 // Post an event to the Chip queue to process the indicate confirmation.
810 ChipDeviceEvent event;
811 event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
812 event.CHIPoBLEIndicateConfirm.ConId = gapEvent->notify_tx.conn_handle;
813 PlatformMgr().PostEvent(&event);
818 ChipDeviceEvent event;
819 event.Type = DeviceEventType::kCHIPoBLEConnectionError;
820 event.CHIPoBLEConnectionError.ConId = gapEvent->notify_tx.conn_handle;
821 event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
822 PlatformMgr().PostEvent(&event);
825 return CHIP_NO_ERROR;
828 uint16_t BLEManagerImpl::_NumConnections(void)
830 uint16_t numCons = 0;
831 for (uint16_t i = 0; i < kMaxConnections; i++)
833 if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED)
842 CHIP_ERROR BLEManagerImpl::HandleGAPConnect(struct ble_gap_event * gapEvent)
844 CHIP_ERROR err = CHIP_NO_ERROR;
845 ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %" PRIu16 ")", gapEvent->connect.conn_handle);
847 // Track the number of active GAP connections.
849 err = SetSubscribed(gapEvent->connect.conn_handle);
850 VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR);
853 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
854 mFlags.Clear(Flags::kAdvertisingConfigured);
860 CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(struct ble_gap_event * gapEvent)
862 ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (con %" PRIu16, " reason 0x%02 " PRIx8 ")",
863 gapEvent->disconnect.conn.conn_handle, gapEvent->disconnect.reason);
865 // Update the number of GAP connections.
871 if (UnsetSubscribed(gapEvent->disconnect.conn.conn_handle))
873 CHIP_ERROR disconReason;
874 switch (gapEvent->disconnect.reason)
876 case BLE_ERR_REM_USER_CONN_TERM:
877 disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
879 case BLE_ERR_CONN_TERM_LOCAL:
880 disconReason = BLE_ERROR_APP_CLOSED_CONNECTION;
883 disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
886 HandleConnectionError(gapEvent->disconnect.conn.conn_handle, disconReason);
889 // Force a reconfiguration of advertising in case we switched to non-connectable mode when
890 // the BLE connection was established.
891 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
892 mFlags.Clear(Flags::kAdvertisingConfigured);
894 return CHIP_NO_ERROR;
897 CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId)
899 uint16_t freeIndex = kMaxConnections;
901 for (uint16_t i = 0; i < kMaxConnections; i++)
903 if (mSubscribedConIds[i] == conId)
905 return CHIP_NO_ERROR;
907 else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex)
913 if (freeIndex < kMaxConnections)
915 mSubscribedConIds[freeIndex] = conId;
916 return CHIP_NO_ERROR;
920 return CHIP_ERROR_NO_MEMORY;
924 bool BLEManagerImpl::UnsetSubscribed(uint16_t conId)
926 for (uint16_t i = 0; i < kMaxConnections; i++)
928 if (mSubscribedConIds[i] == conId)
930 mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED;
937 bool BLEManagerImpl::IsSubscribed(uint16_t conId)
939 if (conId != BLE_CONNECTION_UNINITIALIZED)
941 for (uint16_t i = 0; i < kMaxConnections; i++)
943 if (mSubscribedConIds[i] == conId)
952 int BLEManagerImpl::ble_svr_gap_event(struct ble_gap_event * event, void * arg)
954 CHIP_ERROR err = CHIP_NO_ERROR;
958 case BLE_GAP_EVENT_CONNECT:
959 /* A new connection was established or a connection attempt failed */
960 err = sInstance.HandleGAPConnect(event);
964 case BLE_GAP_EVENT_DISCONNECT:
965 err = sInstance.HandleGAPDisconnect(event);
969 case BLE_GAP_EVENT_ADV_COMPLETE:
970 ESP_LOGD(TAG, "BLE_GAP_EVENT_ADV_COMPLETE event");
973 case BLE_GAP_EVENT_SUBSCRIBE:
974 if (event->subscribe.attr_handle == sInstance.mTXCharCCCDAttrHandle)
976 sInstance.HandleTXCharCCCDWrite(event);
981 case BLE_GAP_EVENT_NOTIFY_TX:
982 err = sInstance.HandleTXComplete(event);
986 case BLE_GAP_EVENT_MTU:
987 ESP_LOGD(TAG, "BLE_GAP_EVENT_MTU = %d channel id = %d", event->mtu.value, event->mtu.channel_id);
995 if (err != CHIP_NO_ERROR)
997 ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
998 sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
1001 // Schedule DriveBLEState() to run.
1002 PlatformMgr().ScheduleWork(DriveBLEState, 0);
1007 int BLEManagerImpl::gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg)
1009 struct ble_gatt_char_context param;
1010 CHIP_ERROR err = CHIP_NO_ERROR;
1012 memset(¶m, 0, sizeof(struct ble_gatt_char_context));
1016 case BLE_GATT_ACCESS_OP_READ_CHR:
1018 param.conn_handle = conn_handle;
1019 param.attr_handle = attr_handle;
1022 sInstance.HandleTXCharRead(¶m);
1025 case BLE_GATT_ACCESS_OP_READ_DSC:
1027 param.conn_handle = conn_handle;
1028 param.attr_handle = attr_handle;
1031 sInstance.HandleTXCharCCCDRead(¶m);
1034 case BLE_GATT_ACCESS_OP_WRITE_CHR:
1035 param.conn_handle = conn_handle;
1036 param.attr_handle = attr_handle;
1039 sInstance.HandleRXCharWrite(¶m);
1043 err = BLE_ATT_ERR_UNLIKELY;
1047 PlatformMgr().ScheduleWork(DriveBLEState, 0);
1052 CHIP_ERROR BLEManagerImpl::StartAdvertising(void)
1056 ble_gap_adv_params adv_params;
1057 memset(&adv_params, 0, sizeof(adv_params));
1058 uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
1060 adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
1062 // Inform the ThreadStackManager that CHIPoBLE advertising is about to start.
1063 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
1065 ThreadStackMgr().OnCHIPoBLEAdvertisingStart();
1067 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
1069 mFlags.Clear(Flags::kAdvertisingRefreshNeeded);
1071 // Advertise connectable if we haven't reached the maximum number of connections.
1072 size_t numCons = _NumConnections();
1073 bool connectable = (numCons < kMaxConnections);
1074 adv_params.conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON;
1076 // Advertise in fast mode if it is connectable advertisement and
1077 // the application has expressly requested fast advertising.
1078 if (connectable && mFlags.Has(Flags::kFastAdvertisingEnabled))
1080 adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN;
1081 adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX;
1085 adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN;
1086 adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX;
1089 ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable, device name %s)",
1090 (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-", mDeviceName);
1093 if (ble_gap_adv_active())
1095 /* Advertising is already active. Stop and restart with the new parameters */
1096 ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart");
1097 ret = ble_gap_adv_stop();
1100 ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %d, cannot restart", ret);
1101 return CHIP_ERROR_INTERNAL;
1106 ret = ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
1109 ChipLogError(DeviceLayer, "RPA not set: %d", ret);
1110 return CHIP_ERROR_INTERNAL;
1113 ret = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_svr_gap_event, NULL);
1117 return CHIP_NO_ERROR;
1121 ChipLogError(DeviceLayer, "ble_gap_adv_start() failed: %d", ret);
1122 return CHIP_ERROR_INTERNAL;
1127 void BLEManagerImpl::DriveBLEState(intptr_t arg)
1129 sInstance.DriveBLEState();
1132 } // namespace Internal
1133 } // namespace DeviceLayer
1136 #endif // CONFIG_BT_NIMBLE_ENABLED
1138 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE