From 6318fa7d59122a7ae1e16fc0453f38637c398344 Mon Sep 17 00:00:00 2001 From: Wang Qixiang Date: Fri, 30 Apr 2021 16:40:24 +0800 Subject: [PATCH] request change by @dhrishi --- .../all-clusters-app/esp32/sdkconfig.defaults | 2 +- src/platform/ESP32/nimble/BLEManagerImpl.cpp | 2042 +++++++++-------- 2 files changed, 1023 insertions(+), 1021 deletions(-) diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults b/examples/all-clusters-app/esp32/sdkconfig.defaults index 22ce3b51ef571e..9c42e49e895c08 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults @@ -30,7 +30,7 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY=y + #enable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=y diff --git a/src/platform/ESP32/nimble/BLEManagerImpl.cpp b/src/platform/ESP32/nimble/BLEManagerImpl.cpp index d551b64f839fa4..9a27916197933c 100644 --- a/src/platform/ESP32/nimble/BLEManagerImpl.cpp +++ b/src/platform/ESP32/nimble/BLEManagerImpl.cpp @@ -56,1096 +56,1098 @@ using namespace ::chip; using namespace ::chip::Ble; namespace chip { -namespace DeviceLayer { -namespace Internal { - -namespace { - -struct ESP32ChipServiceData -{ - uint8_t ServiceUUID[2]; - ChipBLEDeviceIdentificationInfo DeviceIdInfo; -}; - -const ble_uuid128_t UUID_CHIPoBLEService = { - BLE_UUID_TYPE_128, { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xF6, 0xFF, 0x00, 0x00 } -}; -const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFFF6 }; - -const ble_uuid128_t UUID128_CHIPoBLEChar_RX = { - BLE_UUID_TYPE_128, { 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } -}; -const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x11 } }; -const ble_uuid128_t UUID_CHIPoBLEChar_RX = { - { BLE_UUID_TYPE_128 }, { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, 0x11 } -}; - -const ble_uuid128_t UUID128_CHIPoBLEChar_TX = { - BLE_UUID_TYPE_128, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } -}; -const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x12 } }; -const ble_uuid128_t UUID_CHIPoBLEChar_TX = { - { BLE_UUID_TYPE_128 }, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } -}; - -} // unnamed namespace - -BLEManagerImpl BLEManagerImpl::sInstance; - -BLEManagerImpl::BLEManagerImpl() : - mAdvertiseTimerCallback(HandleAdvertisementTimer, this), mFastAdvertiseTimerCallback(HandleFastAdvertisementTimer, this) -{} - -const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTAttrs[] = { - { .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), - .characteristics = - (struct ble_gatt_chr_def[]){ - { - .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX), - .access_cb = gatt_svr_chr_access, - .flags = BLE_GATT_CHR_F_WRITE, - .val_handle = &sInstance.mRXCharAttrHandle, - }, - { - .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), - .access_cb = gatt_svr_chr_access, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, - .val_handle = &sInstance.mTXCharCCCDAttrHandle, - }, - { - 0, /* No more characteristics in this service */ - }, - } }, - - { - 0, /* No more services. */ - }, -}; - -CHIP_ERROR BLEManagerImpl::_Init() -{ - CHIP_ERROR err; - - // Initialize the Chip BleLayer. - err = BleLayer::Init(this, this, &SystemLayer); - SuccessOrExit(err); - - mRXCharAttrHandle = 0; - mTXCharCCCDAttrHandle = 0; - mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); - mFlags.Set(Flags::kFastAdvertisingEnabled, true); - mNumGAPCons = 0; - memset(mCons, 0, sizeof(mCons)); - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; - memset(mDeviceName, 0, sizeof(mDeviceName)); - - PlatformMgr().ScheduleWork(DriveBLEState, 0); + namespace DeviceLayer { + namespace Internal { + + namespace { + + struct ESP32ChipServiceData + { + uint8_t ServiceUUID[2]; + ChipBLEDeviceIdentificationInfo DeviceIdInfo; + }; + + const ble_uuid128_t UUID_CHIPoBLEService = { + BLE_UUID_TYPE_128, { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xF6, 0xFF, 0x00, 0x00 } + }; + const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFFF6 }; + + const ble_uuid128_t UUID128_CHIPoBLEChar_RX = { + BLE_UUID_TYPE_128, { 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } + }; + const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x11 } }; + const ble_uuid128_t UUID_CHIPoBLEChar_RX = { + { BLE_UUID_TYPE_128 }, { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, 0x11 } + }; + + const ble_uuid128_t UUID128_CHIPoBLEChar_TX = { + BLE_UUID_TYPE_128, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } + }; + const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x12 } }; + const ble_uuid128_t UUID_CHIPoBLEChar_TX = { + { BLE_UUID_TYPE_128 }, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } + }; + + } // unnamed namespace + + BLEManagerImpl BLEManagerImpl::sInstance; + + BLEManagerImpl::BLEManagerImpl() : + mAdvertiseTimerCallback(HandleAdvertisementTimer, this), mFastAdvertiseTimerCallback(HandleFastAdvertisementTimer, this) + {} + + const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTAttrs[] = { + { .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), + .characteristics = + (struct ble_gatt_chr_def[]){ + { + .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX), + .access_cb = gatt_svr_chr_access, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = &sInstance.mRXCharAttrHandle, + }, + { + .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), + .access_cb = gatt_svr_chr_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .val_handle = &sInstance.mTXCharCCCDAttrHandle, + }, + { + 0, /* No more characteristics in this service */ + }, + } }, + + { + 0, /* No more services. */ + }, + }; + + CHIP_ERROR BLEManagerImpl::_Init() + { + CHIP_ERROR err; + + // Initialize the Chip BleLayer. + err = BleLayer::Init(this, this, &SystemLayer); + SuccessOrExit(err); + + mRXCharAttrHandle = 0; + mTXCharCCCDAttrHandle = 0; + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + mNumGAPCons = 0; + memset(mCons, 0, sizeof(mCons)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + memset(mDeviceName, 0, sizeof(mDeviceName)); + + PlatformMgr().ScheduleWork(DriveBLEState, 0); exit: - return err; -} + return err; + } -CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val) -{ - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val) + { + CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - if (val != mServiceMode) - { - mServiceMode = val; - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } + if (val != mServiceMode) + { + mServiceMode = val; + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } exit: - return err; -} + return err; + } -CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) -{ - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) + { + CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - if (val) - { - mAdvertiseStartTime = System::Timer::GetCurrentEpoch(); - SystemLayer.StartTimer(kAdvertiseTimeout, &mAdvertiseTimerCallback); - SystemLayer.StartTimer(kFastAdvertiseTimeout, &mFastAdvertiseTimerCallback); - } + if (val) + { + mAdvertiseStartTime = System::Timer::GetCurrentEpoch(); + SystemLayer.StartTimer(kAdvertiseTimeout, &mAdvertiseTimerCallback); + SystemLayer.StartTimer(kFastAdvertiseTimeout, &mFastAdvertiseTimerCallback); + } - mFlags.Set(Flags::kFastAdvertisingEnabled, val); - mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); - mFlags.Set(Flags::kAdvertisingEnabled, val); - PlatformMgr().ScheduleWork(DriveBLEState, 0); + mFlags.Set(Flags::kFastAdvertisingEnabled, val); + mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); exit: - return err; -} - -void BLEManagerImpl::HandleAdvertisementTimer(void * context) -{ - static_cast(context)->HandleAdvertisementTimer(); -} - -void BLEManagerImpl::HandleAdvertisementTimer() -{ - uint64_t currentTimestamp = System::Timer::GetCurrentEpoch(); - - if (currentTimestamp - mAdvertiseStartTime >= kAdvertiseTimeout) - { - mFlags.Set(Flags::kAdvertisingEnabled, 0); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } -} - -void BLEManagerImpl::HandleFastAdvertisementTimer(void * context) -{ - static_cast(context)->HandleFastAdvertisementTimer(); -} - -void BLEManagerImpl::HandleFastAdvertisementTimer() -{ - uint64_t currentTimestamp = System::Timer::GetCurrentEpoch(); - - if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout) - { - mFlags.Set(Flags::kFastAdvertisingEnabled, 0); - mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } -} - -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; -} - -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 != NULL && deviceName[0] != 0) - { - if (strlen(deviceName) >= kMaxDeviceNameLength) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - strcpy(mDeviceName, deviceName); - mFlags.Set(Flags::kUseCustomDeviceName); - } - else - { - mDeviceName[0] = 0; - mFlags.Clear(Flags::kUseCustomDeviceName); - } + return err; + } + + void BLEManagerImpl::HandleAdvertisementTimer(void * context) + { + static_cast(context)->HandleAdvertisementTimer(); + } + + void BLEManagerImpl::HandleAdvertisementTimer() + { + uint64_t currentTimestamp = System::Timer::GetCurrentEpoch(); + + if (currentTimestamp - mAdvertiseStartTime >= kAdvertiseTimeout) + { + mFlags.Set(Flags::kAdvertisingEnabled, 0); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + } + + void BLEManagerImpl::HandleFastAdvertisementTimer(void * context) + { + static_cast(context)->HandleFastAdvertisementTimer(); + } + + void BLEManagerImpl::HandleFastAdvertisementTimer() + { + uint64_t currentTimestamp = System::Timer::GetCurrentEpoch(); + + if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout) + { + mFlags.Set(Flags::kFastAdvertisingEnabled, 0); + mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + } + + 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; + } + + 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 != NULL && deviceName[0] != 0) + { + if (strlen(deviceName) >= kMaxDeviceNameLength) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + strcpy(mDeviceName, deviceName); + mFlags.Set(Flags::kUseCustomDeviceName); + } + else + { + mDeviceName[0] = 0; + mFlags.Clear(Flags::kUseCustomDeviceName); + } exit: - return err; -} - -void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) -{ - switch (event->Type) - { - case DeviceEventType::kCHIPoBLESubscribe: - HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - { - ChipDeviceEvent connectionEvent; - connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; - PlatformMgr().PostEvent(&connectionEvent); - } - break; - - case DeviceEventType::kCHIPoBLEUnsubscribe: - HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - break; - - case DeviceEventType::kCHIPoBLEWriteReceived: - HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, - PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); - break; - - case DeviceEventType::kCHIPoBLEIndicateConfirm: - HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - break; - - case DeviceEventType::kCHIPoBLEConnectionError: - HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); - break; - - case DeviceEventType::kFabricMembershipChange: - case DeviceEventType::kServiceProvisioningChange: - case DeviceEventType::kAccountPairingChange: - case DeviceEventType::kWiFiConnectivityChange: - - // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the - // device's provisioning state, then automatically disable CHIPoBLE advertising if the device - // is now fully provisioned. + return err; + } + + void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) + { + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + { + ChipDeviceEvent connectionEvent; + connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgr().PostEvent(&connectionEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + break; + + case DeviceEventType::kCHIPoBLEConnectionError: + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + break; + + case DeviceEventType::kFabricMembershipChange: + case DeviceEventType::kServiceProvisioningChange: + case DeviceEventType::kAccountPairingChange: + case DeviceEventType::kWiFiConnectivityChange: + + // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the + // device's provisioning state, then automatically disable CHIPoBLE advertising if the device + // is now fully provisioned. #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - if (ConfigurationMgr().IsFullyProvisioned()) - { - mFlags.Clear(Flags::kAdvertisingEnabled); - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); - } + if (ConfigurationMgr().IsFullyProvisioned()) + { + mFlags.Clear(Flags::kAdvertisingEnabled); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); + } #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - // Force the advertising configuration to be refreshed to reflect new provisioning state. - ChipLogProgress(DeviceLayer, "Updating advertising data"); - mFlags.Clear(Flags::kAdvertisingConfigured); - mFlags.Set(Flags::kAdvertisingRefreshNeeded); - - DriveBLEState(); - break; - - default: - break; - } -} - -bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); - return false; -} - -bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); - return false; -} - -bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) -{ - CHIP_ERROR err; - - ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); - - // Signal the ESP BLE layer to close the conneecction. - err = MapBLEError(ble_gap_terminate(conId, BLE_ERR_REM_USER_CONN_TERM)); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_gap_terminate() failed: %s", ErrorStr(err)); - } - - // Force a refresh of the advertising state. - mFlags.Set(Flags::kAdvertisingRefreshNeeded); - mFlags.Clear(Flags::kAdvertisingConfigured); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - - return (err == CHIP_NO_ERROR); -} - -uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const -{ - return ble_att_mtu(conId); -} - -bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBufferHandle data) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - struct os_mbuf * om; - - VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); - - ESP_LOGD(TAG, "Sending indication for CHIPoBLE TX characteristic (con %u, len %u)", conId, data->DataLength()); - - om = ble_hs_mbuf_from_flat(data->Start(), data->DataLength()); - if (om == NULL) - { - ChipLogError(DeviceLayer, "ble_hs_mbuf_from_flat failed:"); - err = CHIP_ERROR_NO_MEMORY; - ExitNow(); - } - - err = MapBLEError(ble_gattc_notify_custom(conId, mTXCharCCCDAttrHandle, om)); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_gattc_notify_custom() failed: %s", ErrorStr(err)); - ExitNow(); - } + // Force the advertising configuration to be refreshed to reflect new provisioning state. + ChipLogProgress(DeviceLayer, "Updating advertising data"); + mFlags.Clear(Flags::kAdvertisingConfigured); + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + + DriveBLEState(); + break; + + default: + break; + } + } + + bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) + { + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); + return false; + } + + bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) + { + ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); + return false; + } + + bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) + { + CHIP_ERROR err; + + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); + + // Signal the ESP BLE layer to close the conneecction. + err = MapBLEError(ble_gap_terminate(conId, BLE_ERR_REM_USER_CONN_TERM)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_terminate() failed: %s", ErrorStr(err)); + } + + // Force a refresh of the advertising state. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + + return (err == CHIP_NO_ERROR); + } + + uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const + { + return ble_att_mtu(conId); + } + + bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle data) + { + CHIP_ERROR err = CHIP_NO_ERROR; + struct os_mbuf * om; + + VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); + + ESP_LOGD(TAG, "Sending indication for CHIPoBLE TX characteristic (con %u, len %u)", conId, data->DataLength()); + + om = ble_hs_mbuf_from_flat(data->Start(), data->DataLength()); + if (om == NULL) + { + ChipLogError(DeviceLayer, "ble_hs_mbuf_from_flat failed:"); + err = CHIP_ERROR_NO_MEMORY; + ExitNow(); + } + + err = MapBLEError(ble_gattc_notify_custom(conId, mTXCharCCCDAttrHandle, om)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gattc_notify_custom() failed: %s", ErrorStr(err)); + ExitNow(); + } exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err)); - return false; - } - return true; -} - -bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBufferHandle pBuf) -{ - ChipLogError(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); - return false; -} - -bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBufferHandle pBuf) -{ - ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported"); - return false; -} - -bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, - const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported"); - return false; -} - -void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {} - -CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) -{ - switch (bleErr) - { - case ESP_OK: - return CHIP_NO_ERROR; - case BLE_HS_EMSGSIZE: - return CHIP_ERROR_INVALID_MESSAGE_LENGTH; - case BLE_HS_ENOMEM: - case ESP_ERR_NO_MEM: - return CHIP_ERROR_NO_MEMORY; - case BLE_HS_ENOTCONN: - return CHIP_ERROR_NOT_CONNECTED; - case BLE_HS_ENOTSUP: - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - case BLE_HS_EAPP: - return CHIP_ERROR_READ_FAILED; - case BLE_HS_EBADDATA: - return CHIP_ERROR_DATA_NOT_ALIGNED; - case BLE_HS_ETIMEOUT: - return CHIP_ERROR_TIMEOUT; - case BLE_HS_ENOADDR: - return CHIP_ERROR_INVALID_ADDRESS; - case ESP_ERR_INVALID_ARG: - return CHIP_ERROR_INVALID_ARGUMENT; - default: - return CHIP_DEVICE_CONFIG_ESP32_BLE_ERROR_MIN + (CHIP_ERROR) bleErr; - } -} -void BLEManagerImpl::DriveBLEState(void) -{ - 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 CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, - // disable CHIPoBLE advertising if the device is fully provisioned. + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err)); + return false; + } + return true; + } + + bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); + return false; + } + + bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported"); + return false; + } + + bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, + const ChipBleUUID * svcId, const ChipBleUUID * charId) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported"); + return false; + } + + void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {} + + CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) + { + switch (bleErr) + { + case ESP_OK: + return CHIP_NO_ERROR; + case BLE_HS_EMSGSIZE: + return CHIP_ERROR_INVALID_MESSAGE_LENGTH; + case BLE_HS_ENOMEM: + case ESP_ERR_NO_MEM: + return CHIP_ERROR_NO_MEMORY; + case BLE_HS_ENOTCONN: + return CHIP_ERROR_NOT_CONNECTED; + case BLE_HS_ENOTSUP: + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + case BLE_HS_EAPP: + return CHIP_ERROR_READ_FAILED; + case BLE_HS_EBADDATA: + return CHIP_ERROR_DATA_NOT_ALIGNED; + case BLE_HS_ETIMEOUT: + return CHIP_ERROR_TIMEOUT; + case BLE_HS_ENOADDR: + return CHIP_ERROR_INVALID_ADDRESS; + case ESP_ERR_INVALID_ARG: + return CHIP_ERROR_INVALID_ARGUMENT; + default: + return CHIP_DEVICE_CONFIG_ESP32_BLE_ERROR_MIN + (CHIP_ERROR) bleErr; + } + } + void BLEManagerImpl::DriveBLEState(void) + { + 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 CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, + // disable CHIPoBLE advertising if the device is fully provisioned. #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - if (ConfigurationMgr().IsFullyProvisioned()) - { - mFlags.Clear(Flags::kAdvertisingEnabled); - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); - } + if (ConfigurationMgr().IsFullyProvisioned()) + { + mFlags.Clear(Flags::kAdvertisingEnabled); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); + } #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - } - - // Initializes the ESP BLE layer if needed. - if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kESPBLELayerInitialized)) - { - err = InitESPBleLayer(); - SuccessOrExit(err); - - // Add delay of 500msec while NimBLE host task gets up and running - { - vTaskDelay(500 / portTICK_RATE_MS); - } - } - - // If the application has enabled CHIPoBLE and BLE advertising... - if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && - mFlags.Has(Flags::kAdvertisingEnabled) + } + + // Initializes the ESP BLE layer if needed. + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kESPBLELayerInitialized)) + { + err = InitESPBleLayer(); + SuccessOrExit(err); + + // Add delay of 500msec while NimBLE host task gets up and running + { + vTaskDelay(500 / portTICK_RATE_MS); + } + } + + // 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) + // and no connections are active... + && (_NumConnections() == 0) #endif - ) - { - // Start/re-start advertising if not already advertising, or if the advertising state of the - // ESP BLE layer needs to be refreshed. - if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded)) - { - // Configure advertising data if it hasn't been done yet. This is an asynchronous step which - // must complete before advertising can be started. When that happens, this method will - // be called again, and execution will proceed to the code below. - if (!mFlags.Has(Flags::kAdvertisingConfigured)) - { - err = ConfigureAdvertisingData(); + ) + { + // Start/re-start advertising if not already advertising, or if the advertising state of the + // ESP BLE layer needs to be refreshed. + if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded)) + { + // Configure advertising data if it hasn't been done yet. This is an asynchronous step which + // must complete before advertising can be started. When that happens, this method will + // be called again, and execution will proceed to the code below. + if (!mFlags.Has(Flags::kAdvertisingConfigured)) + { + err = ConfigureAdvertisingData(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Configure Adv Data failed: %s", ErrorStr(err)); + ExitNow(); + } + } + + // Start advertising. This is also an asynchronous step. + ESP_LOGD(TAG, "NimBLE start advertising..."); + err = StartAdvertising(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Start advertising failed: %s", ErrorStr(err)); + ExitNow(); + } + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + // 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; + PlatformMgr().PostEvent(&advChange); + } + } + } + } + + // Otherwise stop advertising if needed... + else + { + if (mFlags.Has(Flags::kAdvertising)) + { + if (ble_gap_adv_active()) + { + err = MapBLEError(ble_gap_adv_stop()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s", ErrorStr(err)); + ExitNow(); + } + } + // mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + + // 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; + PlatformMgr().PostEvent(&advChange); + } + } + + ExitNow(); + } + } + + // Stop the CHIPoBLE GATT service if needed. + if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kGATTServiceStarted)) + { + // TODO: Not supported + } + +exit: if (err != CHIP_NO_ERROR) { - ChipLogError(DeviceLayer, "Configure Adv Data failed: %s", ErrorStr(err)); - ExitNow(); + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; } } - // Start advertising. This is also an asynchronous step. - ESP_LOGD(TAG, "NimBLE start advertising..."); - err = StartAdvertising(); - if (err != CHIP_NO_ERROR) + void BLEManagerImpl::bleprph_on_reset(int reason) { - ChipLogError(DeviceLayer, "Start advertising failed: %s", ErrorStr(err)); - ExitNow(); + ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); } - mFlags.Clear(Flags::kAdvertisingRefreshNeeded); - // Transition to the Advertising state... - if (!mFlags.Has(Flags::kAdvertising)) + void BLEManagerImpl::bleprph_on_sync(void) { - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); + sInstance.mFlags.Set(Flags::kESPBLELayerInitialized); + sInstance.mFlags.Set(Flags::kGATTServiceStarted); + ESP_LOGI(TAG, "BLE host-controller synced"); + } + + void BLEManagerImpl::bleprph_host_task(void * param) + { + ESP_LOGD(TAG, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + nimble_port_freertos_deinit(); + } + + CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void) + { + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(!mFlags.Has(Flags::kESPBLELayerInitialized), /* */); + + for (int i = 0; i < kMaxConnections; i++) + { + mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; + } + + err = MapBLEError(esp_nimble_hci_and_controller_init()); + SuccessOrExit(err); - mFlags.Set(Flags::kAdvertising); + nimble_port_init(); - // Post a CHIPoBLEAdvertisingChange(Started) event. + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = bleprph_on_reset; + ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + ble_hs_cfg.sm_bonding = 1; + ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; + ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; + + // Register the CHIPoBLE GATT attributes with the ESP BLE layer if needed. + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled) { - ChipDeviceEvent advChange; - advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; - advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; - PlatformMgr().PostEvent(&advChange); + ble_svc_gap_init(); + ble_svc_gatt_init(); + + err = MapBLEError(ble_gatts_count_cfg(CHIPoBLEGATTAttrs)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err)); + ExitNow(); + } + + err = MapBLEError(ble_gatts_add_svcs(CHIPoBLEGATTAttrs)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_add_svcs failed: %s", ErrorStr(err)); + ExitNow(); + } } + + nimble_port_freertos_init(bleprph_host_task); + +exit: + return err; } - } - } - - // Otherwise stop advertising if needed... - else - { - if (mFlags.Has(Flags::kAdvertising)) - { - if (ble_gap_adv_active()) + + CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) { - err = MapBLEError(ble_gap_adv_stop()); + CHIP_ERROR err; + uint8_t advData[MAX_ADV_DATA_LEN]; + uint8_t index = 0; + + // If a custom device name has not been specified, generate a CHIP-standard name based on the + // bottom digits of the Chip device id. + uint16_t discriminator; + SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator)); + + if (!mFlags.Has(Flags::kUseCustomDeviceName)) + { + snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + mDeviceName[kMaxDeviceNameLength] = 0; + } + + // Configure the BLE device name. + err = MapBLEError(ble_svc_gap_device_name_set(mDeviceName)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_svc_gap_device_name_set() failed: %s", ErrorStr(err)); + ExitNow(); + } + + memset(advData, 0, sizeof(advData)); + advData[index++] = 0x02; // length + advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags + advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value + advData[index++] = 0x0A; // length + advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) + advData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value + advData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value + + chip::Ble::ChipBLEDeviceIdentificationInfo deviceIdInfo; + err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); if (err != CHIP_NO_ERROR) { - ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s", ErrorStr(err)); + ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err)); ExitNow(); } + + VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = BLE_ERROR_OUTBOUND_MESSAGE_TOO_BIG); + memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo)); + index = static_cast(index + sizeof(deviceIdInfo)); + + // Construct the Chip BLE Service Data to be sent in the scan response packet. + err = MapBLEError(ble_gap_adv_set_data(advData, sizeof(advData))); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_adv_set_data failed: %s %d", ErrorStr(err), discriminator); + ExitNow(); + } + +exit: + return err; } - // mFlags.Clear(Flags::kAdvertisingRefreshNeeded); - // Transition to the not Advertising state... - if (mFlags.Has(Flags::kAdvertising)) + void BLEManagerImpl::HandleRXCharWrite(struct ble_gatt_char_context * param) { - mFlags.Clear(Flags::kAdvertising); - mFlags.Set(Flags::kFastAdvertisingEnabled, true); + CHIP_ERROR err = CHIP_NO_ERROR; + uint16_t data_len = 0; - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); + ESP_LOGI(TAG, "Write request received for CHIPoBLE RX characteristic con %u %u", param->conn_handle, param->attr_handle); - // Post a CHIPoBLEAdvertisingChange(Stopped) event. + // Copy the data to a packet buffer. + data_len = OS_MBUF_PKTLEN(param->ctxt->om); + PacketBufferHandle buf = System::PacketBufferHandle::New(data_len, 0); + VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(buf->AvailableDataLength() >= data_len, err = CHIP_ERROR_BUFFER_TOO_SMALL); + ble_hs_mbuf_to_flat(param->ctxt->om, buf->Start(), data_len, NULL); + buf->SetDataLength(data_len); + + // Post an event to the Chip queue to deliver the data into the Chip stack. { - ChipDeviceEvent advChange; - advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; - advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; - PlatformMgr().PostEvent(&advChange); + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + event.CHIPoBLEWriteReceived.ConId = param->conn_handle; + event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + PlatformMgr().PostEvent(&event); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); } } - ExitNow(); - } - } + void BLEManagerImpl::HandleTXCharRead(struct ble_gatt_char_context * param) + { + /* Not supported */ + ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharRead() not supported"); + } - // Stop the CHIPoBLE GATT service if needed. - if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kGATTServiceStarted)) - { - // TODO: Not supported - } + void BLEManagerImpl::HandleTXCharCCCDRead(void * param) + { + /* Not Supported */ + ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharCCCDRead() not supported"); + } -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; - } -} - -void BLEManagerImpl::bleprph_on_reset(int reason) -{ - ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); -} - -void BLEManagerImpl::bleprph_on_sync(void) -{ - sInstance.mFlags.Set(Flags::kESPBLELayerInitialized); - sInstance.mFlags.Set(Flags::kGATTServiceStarted); - ESP_LOGI(TAG, "BLE host-controller synced"); -} - -void BLEManagerImpl::bleprph_host_task(void * param) -{ - ESP_LOGD(TAG, "BLE Host Task Started"); - /* This function will return only when nimble_port_stop() is executed */ - nimble_port_run(); - nimble_port_freertos_deinit(); -} - -CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(!mFlags.Has(Flags::kESPBLELayerInitialized), /* */); - - for (int i = 0; i < kMaxConnections; i++) - { - mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; - } - - err = MapBLEError(esp_nimble_hci_and_controller_init()); - SuccessOrExit(err); - - nimble_port_init(); - - /* Initialize the NimBLE host configuration. */ - ble_hs_cfg.reset_cb = bleprph_on_reset; - ble_hs_cfg.sync_cb = bleprph_on_sync; - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - ble_hs_cfg.sm_bonding = 1; - ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; - ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; - - // Register the CHIPoBLE GATT attributes with the ESP BLE layer if needed. - if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled) - { - ble_svc_gap_init(); - ble_svc_gatt_init(); - - err = MapBLEError(ble_gatts_count_cfg(CHIPoBLEGATTAttrs)); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err)); - ExitNow(); - } - - err = MapBLEError(ble_gatts_add_svcs(CHIPoBLEGATTAttrs)); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_gatts_add_svcs failed: %s", ErrorStr(err)); - ExitNow(); - } - } - - nimble_port_freertos_init(bleprph_host_task); + void BLEManagerImpl::HandleTXCharCCCDWrite(struct ble_gap_event * gapEvent) + { + CHIP_ERROR err = CHIP_NO_ERROR; + bool indicationsEnabled; + bool notificationsEnabled; -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) -{ - CHIP_ERROR err; - uint8_t advData[MAX_ADV_DATA_LEN]; - uint8_t index = 0; - - // If a custom device name has not been specified, generate a CHIP-standard name based on the - // bottom digits of the Chip device id. - uint16_t discriminator; - SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator)); - - if (!mFlags.Has(Flags::kUseCustomDeviceName)) - { - snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); - mDeviceName[kMaxDeviceNameLength] = 0; - } - - // Configure the BLE device name. - err = MapBLEError(ble_svc_gap_device_name_set(mDeviceName)); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_svc_gap_device_name_set() failed: %s", ErrorStr(err)); - ExitNow(); - } - - memset(advData, 0, sizeof(advData)); - advData[index++] = 0x02; // length - advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags - advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value - advData[index++] = 0x0A; // length - advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) - advData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value - advData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value - - chip::Ble::ChipBLEDeviceIdentificationInfo deviceIdInfo; - err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err)); - ExitNow(); - } - - VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = BLE_ERROR_OUTBOUND_MESSAGE_TOO_BIG); - memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo)); - index = static_cast(index + sizeof(deviceIdInfo)); - - // Construct the Chip BLE Service Data to be sent in the scan response packet. - err = MapBLEError(ble_gap_adv_set_data(advData, sizeof(advData))); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "ble_gap_adv_set_data failed: %s %d", ErrorStr(err), discriminator); - ExitNow(); - } + ChipLogProgress(DeviceLayer, + "Write request/command received for CHIPoBLE TX CCCD characteristic (con %" PRIu16 + " ) indicate = %d notify = %d", + gapEvent->subscribe.conn_handle, gapEvent->subscribe.cur_indicate, gapEvent->subscribe.cur_notify); -exit: - return err; -} - -void BLEManagerImpl::HandleRXCharWrite(struct ble_gatt_char_context * param) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t data_len = 0; - - ESP_LOGI(TAG, "Write request received for CHIPoBLE RX characteristic con %u %u", param->conn_handle, param->attr_handle); - - // Copy the data to a packet buffer. - data_len = OS_MBUF_PKTLEN(param->ctxt->om); - PacketBufferHandle buf = System::PacketBufferHandle::New(data_len, 0); - VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY); - VerifyOrExit(buf->AvailableDataLength() >= data_len, err = CHIP_ERROR_BUFFER_TOO_SMALL); - ble_hs_mbuf_to_flat(param->ctxt->om, buf->Start(), data_len, NULL); - buf->SetDataLength(data_len); - - // Post an event to the Chip queue to deliver the data into the Chip stack. - { - ChipDeviceEvent event; - event.Type = DeviceEventType::kCHIPoBLEWriteReceived; - event.CHIPoBLEWriteReceived.ConId = param->conn_handle; - event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); - PlatformMgr().PostEvent(&event); - } + // Determine if the client is enabling or disabling indications/notification. + indicationsEnabled = gapEvent->subscribe.cur_indicate; + notificationsEnabled = gapEvent->subscribe.cur_notify; -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); - } -} - -void BLEManagerImpl::HandleTXCharRead(struct ble_gatt_char_context * param) -{ - /* Not supported */ - ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharRead() not supported"); -} - -void BLEManagerImpl::HandleTXCharCCCDRead(void * param) -{ - /* Not Supported */ - ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharCCCDRead() not supported"); -} - -void BLEManagerImpl::HandleTXCharCCCDWrite(struct ble_gap_event * gapEvent) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - bool indicationsEnabled; - bool notificationsEnabled; - - ChipLogProgress(DeviceLayer, - "Write request/command received for CHIPoBLE TX CCCD characteristic (con %" PRIu16 - " ) indicate = %d notify = %d", - gapEvent->subscribe.conn_handle, gapEvent->subscribe.cur_indicate, gapEvent->subscribe.cur_notify); - - // Determine if the client is enabling or disabling indications/notification. - indicationsEnabled = gapEvent->subscribe.cur_indicate; - notificationsEnabled = gapEvent->subscribe.cur_notify; - - // If the client has requested to enabled indications/notifications - if (indicationsEnabled || notificationsEnabled) - { - // If indications are not already enabled for the connection... - if (!IsSubscribed(gapEvent->subscribe.conn_handle)) - { - // Record that indications have been enabled for this connection. If this fails because - err = SetSubscribed(gapEvent->subscribe.conn_handle); - VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); - SuccessOrExit(err); - } - } - - else - { - // If indications had previously been enabled for this connection, record that they are no longer - // enabled. - UnsetSubscribed(gapEvent->subscribe.conn_handle); - } - - // 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; - event.Type = (indicationsEnabled || notificationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe - : DeviceEventType::kCHIPoBLEUnsubscribe; - event.CHIPoBLESubscribe.ConId = gapEvent->subscribe.conn_handle; - PlatformMgr().PostEvent(&event); - } - - ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", - (indicationsEnabled || notificationsEnabled) ? "subscribe" : "unsubscribe"); + // If the client has requested to enabled indications/notifications + if (indicationsEnabled || notificationsEnabled) + { + // If indications are not already enabled for the connection... + if (!IsSubscribed(gapEvent->subscribe.conn_handle)) + { + // Record that indications have been enabled for this connection. If this fails because + err = SetSubscribed(gapEvent->subscribe.conn_handle); + VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); + SuccessOrExit(err); + } + } -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); - // TODO: fail connection??? - } - - return; -} - -CHIP_ERROR BLEManagerImpl::HandleTXComplete(struct ble_gap_event * gapEvent) -{ - ChipLogProgress(DeviceLayer, "Confirm received for CHIPoBLE TX characteristic indication (con %" PRIu16 ") status= %d ", - gapEvent->notify_tx.conn_handle, gapEvent->notify_tx.status); - - // Signal the BLE Layer that the outstanding indication is complete. - if (gapEvent->notify_tx.status == 0 || gapEvent->notify_tx.status == BLE_HS_EDONE) - { - // Post an event to the Chip queue to process the indicate confirmation. - ChipDeviceEvent event; - event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; - event.CHIPoBLEIndicateConfirm.ConId = gapEvent->notify_tx.conn_handle; - PlatformMgr().PostEvent(&event); - } - - else - { - ChipDeviceEvent event; - event.Type = DeviceEventType::kCHIPoBLEConnectionError; - event.CHIPoBLEConnectionError.ConId = gapEvent->notify_tx.conn_handle; - event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; - PlatformMgr().PostEvent(&event); - } - - return CHIP_NO_ERROR; -} - -uint16_t BLEManagerImpl::_NumConnections(void) -{ - uint16_t numCons = 0; - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED) - { - numCons++; - } - } - - return numCons; -} - -CHIP_ERROR BLEManagerImpl::HandleGAPConnect(struct ble_gap_event * gapEvent) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %" PRIu16 ")", gapEvent->connect.conn_handle); - - // Track the number of active GAP connections. - mNumGAPCons++; - err = SetSubscribed(gapEvent->connect.conn_handle); - VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); - SuccessOrExit(err); - - mFlags.Set(Flags::kAdvertisingRefreshNeeded); - mFlags.Clear(Flags::kAdvertisingConfigured); + else + { + // If indications had previously been enabled for this connection, record that they are no longer + // enabled. + UnsetSubscribed(gapEvent->subscribe.conn_handle); + } + + // 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; + event.Type = (indicationsEnabled || notificationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe + : DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = gapEvent->subscribe.conn_handle; + PlatformMgr().PostEvent(&event); + } + + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", + (indicationsEnabled || notificationsEnabled) ? "subscribe" : "unsubscribe"); exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(struct ble_gap_event * gapEvent) -{ - ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (con %" PRIu16, " reason 0x%02 " PRIx8 ")", - gapEvent->disconnect.conn.conn_handle, gapEvent->disconnect.reason); - - // Update the number of GAP connections. - if (mNumGAPCons > 0) - { - mNumGAPCons--; - } - - if (UnsetSubscribed(gapEvent->disconnect.conn.conn_handle)) - { - CHIP_ERROR disconReason; - switch (gapEvent->disconnect.reason) - { - case BLE_ERR_REM_USER_CONN_TERM: - disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; - break; - case BLE_ERR_CONN_TERM_LOCAL: - disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; - break; - default: - disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; - break; - } - HandleConnectionError(gapEvent->disconnect.conn.conn_handle, disconReason); - } - - // Force a reconfiguration of advertising in case we switched to non-connectable mode when - // the BLE connection was established. - mFlags.Set(Flags::kAdvertisingRefreshNeeded); - mFlags.Clear(Flags::kAdvertisingConfigured); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) -{ - uint16_t freeIndex = kMaxConnections; - - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) - { - return CHIP_NO_ERROR; - } - else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex) - { - freeIndex = i; - } - } - - if (freeIndex < kMaxConnections) - { - mSubscribedConIds[freeIndex] = conId; - return CHIP_NO_ERROR; - } - else - { - return CHIP_ERROR_NO_MEMORY; - } -} - -bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) -{ - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) - { - mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; - return true; - } - } - return false; -} - -bool BLEManagerImpl::IsSubscribed(uint16_t conId) -{ - if (conId != BLE_CONNECTION_UNINITIALIZED) - { - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); + // TODO: fail connection??? + } + + return; + } + + CHIP_ERROR BLEManagerImpl::HandleTXComplete(struct ble_gap_event * gapEvent) { - return true; + ChipLogProgress(DeviceLayer, "Confirm received for CHIPoBLE TX characteristic indication (con %" PRIu16 ") status= %d ", + gapEvent->notify_tx.conn_handle, gapEvent->notify_tx.status); + + // Signal the BLE Layer that the outstanding indication is complete. + if (gapEvent->notify_tx.status == 0 || gapEvent->notify_tx.status == BLE_HS_EDONE) + { + // Post an event to the Chip queue to process the indicate confirmation. + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + event.CHIPoBLEIndicateConfirm.ConId = gapEvent->notify_tx.conn_handle; + PlatformMgr().PostEvent(&event); + } + + else + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEConnectionError; + event.CHIPoBLEConnectionError.ConId = gapEvent->notify_tx.conn_handle; + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + PlatformMgr().PostEvent(&event); + } + + return CHIP_NO_ERROR; } - } - } - return false; -} - -int BLEManagerImpl::ble_svr_gap_event(struct ble_gap_event * event, void * arg) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - switch (event->type) - { - case BLE_GAP_EVENT_CONNECT: - /* A new connection was established or a connection attempt failed */ - err = sInstance.HandleGAPConnect(event); - SuccessOrExit(err); - break; - - case BLE_GAP_EVENT_DISCONNECT: - err = sInstance.HandleGAPDisconnect(event); - SuccessOrExit(err); - break; - - case BLE_GAP_EVENT_ADV_COMPLETE: - ESP_LOGD(TAG, "BLE_GAP_EVENT_ADV_COMPLETE event"); - break; - - case BLE_GAP_EVENT_SUBSCRIBE: - if (event->subscribe.attr_handle == sInstance.mTXCharCCCDAttrHandle) - { - sInstance.HandleTXCharCCCDWrite(event); - } - - break; - - case BLE_GAP_EVENT_NOTIFY_TX: - err = sInstance.HandleTXComplete(event); - SuccessOrExit(err); - break; - - case BLE_GAP_EVENT_MTU: - ESP_LOGD(TAG, "BLE_GAP_EVENT_MTU = %d channel id = %d", event->mtu.value, event->mtu.channel_id); - break; - - default: - break; - } + + uint16_t BLEManagerImpl::_NumConnections(void) + { + uint16_t numCons = 0; + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED) + { + numCons++; + } + } + + return numCons; + } + + CHIP_ERROR BLEManagerImpl::HandleGAPConnect(struct ble_gap_event * gapEvent) + { + CHIP_ERROR err = CHIP_NO_ERROR; + ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %" PRIu16 ")", gapEvent->connect.conn_handle); + + // Track the number of active GAP connections. + mNumGAPCons++; + err = SetSubscribed(gapEvent->connect.conn_handle); + VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); + SuccessOrExit(err); + + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); - sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; - } - - // Schedule DriveBLEState() to run. - PlatformMgr().ScheduleWork(DriveBLEState, 0); - - return err; -} - -int BLEManagerImpl::gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg) -{ - struct ble_gatt_char_context param; - CHIP_ERROR err = CHIP_NO_ERROR; - - memset(¶m, 0, sizeof(struct ble_gatt_char_context)); - - switch (ctxt->op) - { - case BLE_GATT_ACCESS_OP_READ_CHR: - - param.conn_handle = conn_handle; - param.attr_handle = attr_handle; - param.ctxt = ctxt; - param.arg = arg; - sInstance.HandleTXCharRead(¶m); - break; - - case BLE_GATT_ACCESS_OP_READ_DSC: - - param.conn_handle = conn_handle; - param.attr_handle = attr_handle; - param.ctxt = ctxt; - param.arg = arg; - sInstance.HandleTXCharCCCDRead(¶m); - break; - - case BLE_GATT_ACCESS_OP_WRITE_CHR: - param.conn_handle = conn_handle; - param.attr_handle = attr_handle; - param.ctxt = ctxt; - param.arg = arg; - sInstance.HandleRXCharWrite(¶m); - break; - - default: - err = BLE_ATT_ERR_UNLIKELY; - break; - } - - PlatformMgr().ScheduleWork(DriveBLEState, 0); - - return err; -} - -CHIP_ERROR BLEManagerImpl::StartAdvertising(void) -{ - CHIP_ERROR err; - ble_gap_adv_params adv_params; - memset(&adv_params, 0, sizeof(adv_params)); - uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; - - adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; - - mFlags.Clear(Flags::kAdvertisingRefreshNeeded); - - // Advertise connectable if we haven't reached the maximum number of connections. - size_t numCons = _NumConnections(); - bool connectable = (numCons < kMaxConnections); - adv_params.conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON; - - // Advertise in fast mode if it is connectable advertisement and - // the application has expressly requested fast advertising. - if (connectable && mFlags.Has(Flags::kFastAdvertisingEnabled)) - { - adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; - adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_FAST_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; - } - - ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable, device name %s)", - (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-", mDeviceName); - - { - if (ble_gap_adv_active()) - { - /* Advertising is already active. Stop and restart with the new parameters */ - ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); - err = MapBLEError(ble_gap_adv_stop()); - if (err != CHIP_NO_ERROR) + return err; + } + + CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(struct ble_gap_event * gapEvent) + { + ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (con %" PRIu16, " reason 0x%02 " PRIx8 ")", + gapEvent->disconnect.conn.conn_handle, gapEvent->disconnect.reason); + + // Update the number of GAP connections. + if (mNumGAPCons > 0) + { + mNumGAPCons--; + } + + if (UnsetSubscribed(gapEvent->disconnect.conn.conn_handle)) + { + CHIP_ERROR disconReason; + switch (gapEvent->disconnect.reason) + { + case BLE_ERR_REM_USER_CONN_TERM: + disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + break; + case BLE_ERR_CONN_TERM_LOCAL: + disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; + break; + default: + disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + break; + } + HandleConnectionError(gapEvent->disconnect.conn.conn_handle, disconReason); + } + + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + + return CHIP_NO_ERROR; + } + + CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) + { + uint16_t freeIndex = kMaxConnections; + + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + return CHIP_NO_ERROR; + } + else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex) + { + freeIndex = i; + } + } + + if (freeIndex < kMaxConnections) + { + mSubscribedConIds[freeIndex] = conId; + return CHIP_NO_ERROR; + } + else + { + return CHIP_ERROR_NO_MEMORY; + } + } + + bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) + { + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; + return true; + } + } + return false; + } + + bool BLEManagerImpl::IsSubscribed(uint16_t conId) + { + if (conId != BLE_CONNECTION_UNINITIALIZED) + { + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + return true; + } + } + } + return false; + } + + int BLEManagerImpl::ble_svr_gap_event(struct ble_gap_event * event, void * arg) { - ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %d, cannot restart", ErrorStr(err)); + CHIP_ERROR err = CHIP_NO_ERROR; + + switch (event->type) + { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + err = sInstance.HandleGAPConnect(event); + SuccessOrExit(err); + break; + + case BLE_GAP_EVENT_DISCONNECT: + err = sInstance.HandleGAPDisconnect(event); + SuccessOrExit(err); + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + ESP_LOGD(TAG, "BLE_GAP_EVENT_ADV_COMPLETE event"); + break; + + case BLE_GAP_EVENT_SUBSCRIBE: + if (event->subscribe.attr_handle == sInstance.mTXCharCCCDAttrHandle) + { + sInstance.HandleTXCharCCCDWrite(event); + } + + break; + + case BLE_GAP_EVENT_NOTIFY_TX: + err = sInstance.HandleTXComplete(event); + SuccessOrExit(err); + break; + + case BLE_GAP_EVENT_MTU: + ESP_LOGD(TAG, "BLE_GAP_EVENT_MTU = %d channel id = %d", event->mtu.value, event->mtu.channel_id); + break; + + default: + break; + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } + + // Schedule DriveBLEState() to run. + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return err; } - } - else - { - err = MapBLEError(ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA)); - if (err != CHIP_NO_ERROR) + + int BLEManagerImpl::gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg) { - ChipLogError(DeviceLayer, "RPA not set: %d", ErrorStr(err)); + struct ble_gatt_char_context param; + CHIP_ERROR err = CHIP_NO_ERROR; + + memset(¶m, 0, sizeof(struct ble_gatt_char_context)); + + switch (ctxt->op) + { + case BLE_GATT_ACCESS_OP_READ_CHR: + + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleTXCharRead(¶m); + break; + + case BLE_GATT_ACCESS_OP_READ_DSC: + + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleTXCharCCCDRead(¶m); + break; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleRXCharWrite(¶m); + break; + + default: + err = BLE_ATT_ERR_UNLIKELY; + break; + } + + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return err; } - } - err = MapBLEError(ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_svr_gap_event, NULL)); - if (err == CHIP_NO_ERROR) - { - return CHIP_NO_ERROR; - } - else - { - ChipLogError(DeviceLayer, "ble_gap_adv_start() failed: %d", ErrorStr(err)); - return err; - } - } -} - -void BLEManagerImpl::DriveBLEState(intptr_t arg) -{ - sInstance.DriveBLEState(); -} - -} // namespace Internal -} // namespace DeviceLayer + + CHIP_ERROR BLEManagerImpl::StartAdvertising(void) + { + CHIP_ERROR err; + ble_gap_adv_params adv_params; + memset(&adv_params, 0, sizeof(adv_params)); + uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; + + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + + // Advertise connectable if we haven't reached the maximum number of connections. + size_t numCons = _NumConnections(); + bool connectable = (numCons < kMaxConnections); + adv_params.conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON; + + // Advertise in fast mode if it is connectable advertisement and + // the application has expressly requested fast advertising. + if (connectable && mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_FAST_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; + } + + ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable, device name %s)", + (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-", mDeviceName); + + { + if (ble_gap_adv_active()) + { + /* Advertising is already active. Stop and restart with the new parameters */ + ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); + err = MapBLEError(ble_gap_adv_stop()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %d, cannot restart", ErrorStr(err)); + return err; + } + } +#if MYNEWT_VAL_BLE_HOST_BASED_PRIVACY + else + { + err = MapBLEError(ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "RPA not set: %d", ErrorStr(err)); + return err; + } + } +#endif + err = MapBLEError(ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_svr_gap_event, NULL)); + if (err == CHIP_NO_ERROR) + { + return CHIP_NO_ERROR; + } + else + { + ChipLogError(DeviceLayer, "ble_gap_adv_start() failed: %d", ErrorStr(err)); + return err; + } + } + } + + void BLEManagerImpl::DriveBLEState(intptr_t arg) + { + sInstance.DriveBLEState(); + } + + } // namespace Internal + } // namespace DeviceLayer } // namespace chip #endif // CONFIG_BT_NIMBLE_ENABLED