3 * Copyright (c) 2020-2021 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * Provides an implementation of the BLEManager singleton object
21 * for Zephyr platforms.
24 #include <platform/internal/CHIPDeviceLayerInternal.h>
26 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
28 #include <platform/Zephyr/BLEManagerImpl.h>
30 #include <ble/CHIPBleServiceData.h>
31 #include <platform/internal/BLEManager.h>
32 #include <support/CodeUtils.h>
33 #include <support/logging/CHIPLogging.h>
35 #include <logging/log.h>
36 #include <sys/byteorder.h>
39 LOG_MODULE_DECLARE(chip);
41 using namespace ::chip;
42 using namespace ::chip::Ble;
43 using namespace ::chip::System;
46 namespace DeviceLayer {
51 const bt_uuid_128 UUID128_CHIPoBLEChar_RX =
52 BT_UUID_INIT_128(0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18);
53 const bt_uuid_128 UUID128_CHIPoBLEChar_TX =
54 BT_UUID_INIT_128(0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18);
55 bt_uuid_16 UUID16_CHIPoBLEService = BT_UUID_INIT_16(0xFEAF);
57 const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
60 const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
63 _bt_gatt_ccc CHIPoBLEChar_TX_CCC = BT_GATT_CCC_INITIALIZER(nullptr, BLEManagerImpl::HandleTXCCCWrite, nullptr);
67 BT_GATT_SERVICE_DEFINE(CHIPoBLE_Service,
68 BT_GATT_PRIMARY_SERVICE(&UUID16_CHIPoBLEService.uuid),
69 BT_GATT_CHARACTERISTIC(&UUID128_CHIPoBLEChar_RX.uuid,
70 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
71 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
72 nullptr, BLEManagerImpl::HandleRXWrite, nullptr),
73 BT_GATT_CHARACTERISTIC(&UUID128_CHIPoBLEChar_TX.uuid,
74 BT_GATT_CHRC_INDICATE,
76 nullptr, nullptr, nullptr),
77 BT_GATT_CCC_MANAGED(&CHIPoBLEChar_TX_CCC, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
82 // Index of the CCC descriptor in the CHIPoBLE_Service array of attributes.
83 // This value should be adjusted accordingly if the service declaration changes.
84 constexpr int kCHIPoBLE_CCC_AttributeIndex = 3;
86 } // unnamed namespace
88 BLEManagerImpl BLEManagerImpl::sInstance;
90 CHIP_ERROR BLEManagerImpl::_Init()
94 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
95 mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART);
98 memset(mSubscribedConns, 0, sizeof(mSubscribedConns));
100 err = bt_enable(NULL);
101 VerifyOrExit(err == CHIP_NO_ERROR, err = MapErrorZephyr(err));
103 memset(&mConnCallbacks, 0, sizeof(mConnCallbacks));
104 mConnCallbacks.connected = HandleConnect;
105 mConnCallbacks.disconnected = HandleDisconnect;
107 bt_conn_cb_register(&mConnCallbacks);
109 // Initialize the CHIP BleLayer.
110 err = BleLayer::Init(this, this, &SystemLayer);
113 PlatformMgr().ScheduleWork(DriveBLEState, 0);
119 void BLEManagerImpl::DriveBLEState(intptr_t arg)
121 BLEMgrImpl().DriveBLEState();
124 void BLEManagerImpl::DriveBLEState()
126 CHIP_ERROR err = CHIP_NO_ERROR;
128 ChipLogDetail(DeviceLayer, "In DriveBLEState");
130 // Perform any initialization actions that must occur after the CHIP task is running.
131 if (!mFlags.Has(Flags::kAsyncInitCompleted))
133 mFlags.Set(Flags::kAsyncInitCompleted);
135 // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled,
136 // disable CHIPoBLE advertising if the device is fully provisioned.
137 #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
138 if (ConfigurationMgr().IsFullyProvisioned())
140 mFlags.Clear(Flags::kAdvertisingEnabled);
141 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
143 #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
146 // If the application has enabled CHIPoBLE and BLE advertising...
147 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled &&
148 mFlags.Has(Flags::kAdvertisingEnabled)
149 #if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION
150 // and no connections are active...
151 && (NumConnections() == 0)
155 // Start/re-start advertising if not already advertising, or if the
156 // advertising state needs to be refreshed.
157 if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded))
159 err = StartAdvertising();
163 // Otherwise, stop advertising if currently active.
166 err = StopAdvertising();
171 if (err != CHIP_NO_ERROR)
173 ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
174 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
178 struct BLEManagerImpl::ServiceData
181 ChipBLEDeviceIdentificationInfo deviceIdInfo;
182 } __attribute__((packed));
184 CHIP_ERROR BLEManagerImpl::StartAdvertising(void)
188 const char * deviceName = bt_get_name();
189 const uint8_t advFlags = BT_LE_AD_LIMITED | BT_LE_AD_NO_BREDR;
190 bt_le_adv_param advParams = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, GetAdvertisingInterval(),
191 CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL, nullptr);
193 // Define advertising data
194 ServiceData serviceData;
195 bt_data ad[] = { BT_DATA(BT_DATA_FLAGS, &advFlags, sizeof(advFlags)),
196 BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)),
197 BT_DATA(BT_DATA_NAME_COMPLETE, deviceName, static_cast<uint8_t>(strlen(deviceName))) };
199 // Initialize service data
200 static_assert(sizeof(serviceData) == 9, "Size of BLE advertisement data changed! Was that intentional?");
201 chip::Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val);
202 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo);
205 // If necessary, inform the ThreadStackManager that CHIPoBLE advertising is about to start.
206 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
207 if (!mFlags.Has(Flags::kAdvertising))
209 ThreadStackMgr().OnCHIPoBLEAdvertisingStart();
211 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
213 // Restart advertising
214 err = bt_le_adv_stop();
215 VerifyOrExit(err == CHIP_NO_ERROR, err = MapErrorZephyr(err));
217 err = bt_le_adv_start(&advParams, ad, ARRAY_SIZE(ad), nullptr, 0u);
220 // No free connection objects for connectable advertiser. Advertise as non-connectable instead.
221 advParams.options &= ~BT_LE_ADV_OPT_CONNECTABLE;
222 err = bt_le_adv_start(&advParams, ad, ARRAY_SIZE(ad), nullptr, 0u);
225 VerifyOrExit(err == CHIP_NO_ERROR, err = MapErrorZephyr(err));
227 // Transition to the Advertising state...
228 if (!mFlags.Has(Flags::kAdvertising))
230 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started");
232 mFlags.Set(Flags::kAdvertising);
234 // Post a CHIPoBLEAdvertisingChange(Started) event.
236 ChipDeviceEvent advChange;
237 advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
238 advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started;
239 PlatformMgr().PostEvent(&advChange);
242 // Start timer to disable CHIPoBLE advertisement after timeout expiration
243 SystemLayer.StartTimer(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT, HandleBLEAdvertisementTimeout, this);
250 CHIP_ERROR BLEManagerImpl::StopAdvertising(void)
252 CHIP_ERROR err = CHIP_NO_ERROR;
254 err = bt_le_adv_stop();
255 VerifyOrExit(err == CHIP_NO_ERROR, err = MapErrorZephyr(err));
257 // Transition to the not Advertising state...
258 if (mFlags.Has(Flags::kAdvertising))
260 mFlags.Clear(Flags::kAdvertising);
262 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped");
264 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
265 // Directly inform the ThreadStackManager that CHIPoBLE advertising has stopped.
266 ThreadStackMgr().OnCHIPoBLEAdvertisingStop();
267 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
269 // Post a CHIPoBLEAdvertisingChange(Stopped) event.
271 ChipDeviceEvent advChange;
272 advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
273 advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped;
274 PlatformMgr().PostEvent(&advChange);
277 // Cancel timer event disabling CHIPoBLE advertisement after timeout expiration
278 SystemLayer.CancelTimer(HandleBLEAdvertisementTimeout, this);
285 CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val)
287 CHIP_ERROR err = CHIP_NO_ERROR;
289 VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
290 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
292 if (val != mServiceMode)
295 PlatformMgr().ScheduleWork(DriveBLEState, 0);
302 CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
304 CHIP_ERROR err = CHIP_NO_ERROR;
306 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
308 if (mFlags.Has(Flags::kAdvertisingEnabled) != val)
310 ChipLogDetail(DeviceLayer, "SetAdvertisingEnabled(%s)", val ? "true" : "false");
312 mFlags.Set(Flags::kAdvertisingEnabled, val);
313 PlatformMgr().ScheduleWork(DriveBLEState, 0);
320 CHIP_ERROR BLEManagerImpl::_SetFastAdvertisingEnabled(bool val)
322 CHIP_ERROR err = CHIP_NO_ERROR;
324 VerifyOrExit(mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
326 if (mFlags.Has(Flags::kFastAdvertisingEnabled) != val)
328 ChipLogDetail(DeviceLayer, "SetFastAdvertisingEnabled(%s)", val ? "true" : "false");
330 mFlags.Set(Flags::kFastAdvertisingEnabled, val);
331 PlatformMgr().ScheduleWork(DriveBLEState, 0);
338 CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
340 size_t len = bufSize - 1;
342 strncpy(buf, bt_get_name(), len);
345 return CHIP_NO_ERROR;
348 CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
350 if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported)
352 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
355 ChipLogDetail(DeviceLayer, "Device name set to: %s", deviceName);
356 return MapErrorZephyr(bt_set_name(deviceName));
359 CHIP_ERROR BLEManagerImpl::HandleGAPConnect(const ChipDeviceEvent * event)
361 const BleConnEventType * connEvent = &event->Platform.BleConnEvent;
363 if (connEvent->HciResult == BT_HCI_ERR_SUCCESS)
365 ChipLogProgress(DeviceLayer, "BLE connection established (ConnId: 0x%02" PRIx16 ")", bt_conn_index(connEvent->BtConn));
370 ChipLogProgress(DeviceLayer, "BLE connection failed (reason: 0x%02" PRIx16 ")", connEvent->HciResult);
373 ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%" PRIu16, NumConnections(), CONFIG_BT_MAX_CONN);
375 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
376 PlatformMgr().ScheduleWork(DriveBLEState, 0);
378 bt_conn_unref(connEvent->BtConn);
380 return CHIP_NO_ERROR;
383 CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(const ChipDeviceEvent * event)
385 const BleConnEventType * connEvent = &event->Platform.BleConnEvent;
387 ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (reason 0x%02" PRIx16 ")", connEvent->HciResult);
391 // If indications were enabled for this connection, record that they are now disabled and
392 // notify the BLE Layer of a disconnect.
393 if (UnsetSubscribed(connEvent->BtConn))
395 CHIP_ERROR disconReason;
396 switch (connEvent->HciResult)
398 case BT_HCI_ERR_REMOTE_USER_TERM_CONN:
399 // Do not treat proper connection termination as an error and exit.
400 VerifyOrExit(!ConfigurationMgr().IsFullyProvisioned(), );
401 disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
403 case BT_HCI_ERR_LOCALHOST_TERM_CONN:
404 disconReason = BLE_ERROR_APP_CLOSED_CONNECTION;
407 disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
410 HandleConnectionError(connEvent->BtConn, disconReason);
414 // Unref bt_conn before scheduling DriveBLEState.
415 bt_conn_unref(connEvent->BtConn);
417 ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%" PRIu16, NumConnections(), CONFIG_BT_MAX_CONN);
419 // Force a reconfiguration of advertising in case we switched to non-connectable mode when
420 // the BLE connection was established.
421 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
422 PlatformMgr().ScheduleWork(DriveBLEState, 0);
424 return CHIP_NO_ERROR;
427 CHIP_ERROR BLEManagerImpl::HandleTXCharCCCDWrite(const ChipDeviceEvent * event)
429 const BleCCCWriteEventType * writeEvent = &event->Platform.BleCCCWriteEvent;
431 ChipLogDetail(DeviceLayer, "ConnId: 0x%02" PRIx16 ", New CCCD value: 0x%04" PRIx16, bt_conn_index(writeEvent->BtConn),
434 // If the client has requested to enabled indications and if it is not yet subscribed
435 if (writeEvent->Value == BT_GATT_CCC_INDICATE && SetSubscribed(writeEvent->BtConn))
437 // Alert the BLE layer that CHIPoBLE "subscribe" has been received and increment the bt_conn reference counter.
438 HandleSubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
440 ChipLogProgress(DeviceLayer, "CHIPoBLE connection established (ConnId: 0x%02" PRIx16 ", GATT MTU: %" PRIu16 ")",
441 bt_conn_index(writeEvent->BtConn), GetMTU(writeEvent->BtConn));
443 // Post a CHIPoBLEConnectionEstablished event to the DeviceLayer and the application.
445 ChipDeviceEvent conEstEvent;
446 conEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
447 PlatformMgr().PostEvent(&conEstEvent);
452 if (UnsetSubscribed(writeEvent->BtConn))
454 HandleUnsubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
458 bt_conn_unref(writeEvent->BtConn);
460 return CHIP_NO_ERROR;
463 CHIP_ERROR BLEManagerImpl::HandleRXCharWrite(const ChipDeviceEvent * event)
465 const BleC1WriteEventType * c1WriteEvent = &event->Platform.BleC1WriteEvent;
467 ChipLogDetail(DeviceLayer, "Write request received for CHIPoBLE RX characteristic (ConnId 0x%02" PRIx16 ")",
468 bt_conn_index(c1WriteEvent->BtConn));
470 HandleWriteReceived(c1WriteEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX,
471 PacketBufferHandle::Adopt(c1WriteEvent->Data));
472 bt_conn_unref(c1WriteEvent->BtConn);
474 return CHIP_NO_ERROR;
477 CHIP_ERROR BLEManagerImpl::HandleTXComplete(const ChipDeviceEvent * event)
479 const BleC2IndDoneEventType * c2IndDoneEvent = &event->Platform.BleC2IndDoneEvent;
481 ChipLogDetail(DeviceLayer, "Indication for CHIPoBLE TX characteristic done (ConnId 0x%02" PRIx16 ", result 0x%02" PRIx16 ")",
482 bt_conn_index(c2IndDoneEvent->BtConn), c2IndDoneEvent->Result);
484 // Signal the BLE Layer that the outstanding indication is complete.
485 HandleIndicationConfirmation(c2IndDoneEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
486 bt_conn_unref(c2IndDoneEvent->BtConn);
488 return CHIP_NO_ERROR;
491 void BLEManagerImpl::HandleBLEAdvertisementTimeout(System::Layer * layer, void * param, System::Error error)
493 BLEMgr().SetAdvertisingEnabled(false);
494 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because of timeout expired");
497 void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
499 CHIP_ERROR err = CHIP_NO_ERROR;
503 case DeviceEventType::kPlatformZephyrBleConnected:
504 err = HandleGAPConnect(event);
507 case DeviceEventType::kPlatformZephyrBleDisconnected:
508 err = HandleGAPDisconnect(event);
511 case DeviceEventType::kPlatformZephyrBleCCCWrite:
512 err = HandleTXCharCCCDWrite(event);
515 case DeviceEventType::kPlatformZephyrBleC1WriteEvent:
516 err = HandleRXCharWrite(event);
519 case DeviceEventType::kPlatformZephyrBleC2IndDoneEvent:
520 err = HandleTXComplete(event);
523 case DeviceEventType::kFabricMembershipChange:
524 case DeviceEventType::kServiceProvisioningChange:
525 case DeviceEventType::kAccountPairingChange:
527 // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the
528 // device's provisioning state, then automatically disable CHIPoBLE advertising if the device
529 // is now fully provisioned.
530 #if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
531 if (ConfigurationMgr().IsFullyProvisioned())
533 mFlags.Clear(Flags::kAdvertisingEnabled);
534 ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
536 #endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
538 // Force the advertising state to be refreshed to reflect new provisioning state.
539 mFlags.Set(Flags::kAdvertisingRefreshNeeded);
549 if (err != CHIP_NO_ERROR)
551 ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
552 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
553 PlatformMgr().ScheduleWork(DriveBLEState, 0);
557 uint16_t BLEManagerImpl::_NumConnections(void)
562 bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
564 ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (ConnId %02" PRIx16 ")", bt_conn_index(conId));
565 return bt_conn_disconnect(conId, BT_HCI_ERR_REMOTE_USER_TERM_CONN) == CHIP_NO_ERROR;
568 uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
570 return bt_gatt_get_mtu(conId);
573 bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
575 ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
579 bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
581 ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
585 bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
586 PacketBufferHandle pBuf)
588 CHIP_ERROR err = CHIP_NO_ERROR;
589 uint8_t index = bt_conn_index(conId);
590 bt_gatt_indicate_params * params = &mIndicateParams[index];
592 VerifyOrExit(IsSubscribed(conId) == true, err = CHIP_ERROR_INVALID_ARGUMENT);
594 ChipLogDetail(DeviceLayer, "Sending indication for CHIPoBLE TX characteristic (ConnId %u, len %u)", index, pBuf->DataLength());
596 params->uuid = nullptr;
597 params->attr = &CHIPoBLE_Service.attrs[kCHIPoBLE_CCC_AttributeIndex];
598 params->func = HandleTXIndicated;
599 params->data = pBuf->Start();
600 params->len = pBuf->DataLength();
602 err = bt_gatt_indicate(conId, params);
603 VerifyOrExit(err == CHIP_NO_ERROR, err = MapErrorZephyr(err));
606 if (err != CHIP_NO_ERROR)
608 ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err));
611 return err == CHIP_NO_ERROR;
614 bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
615 PacketBufferHandle pBuf)
617 ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
621 bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
622 PacketBufferHandle pBuf)
624 ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
628 bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
629 const ChipBleUUID * svcId, const ChipBleUUID * charId)
631 ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
635 void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
637 // Intentionally empty.
640 bool BLEManagerImpl::IsSubscribed(bt_conn * conn)
642 return mSubscribedConns[bt_conn_index(conn)];
645 bool BLEManagerImpl::SetSubscribed(bt_conn * conn)
647 uint8_t index = bt_conn_index(conn);
648 bool isSubscribed = mSubscribedConns[index];
649 mSubscribedConns[index] = true;
651 // If we were not subscribed previously, increment the reference counter of the connection.
657 return !isSubscribed;
660 bool BLEManagerImpl::UnsetSubscribed(bt_conn * conn)
662 uint8_t index = bt_conn_index(conn);
663 bool isSubscribed = mSubscribedConns[index];
664 mSubscribedConns[index] = false;
666 // If we were subscribed previously, decrement the reference counter of the connection.
675 uint32_t BLEManagerImpl::GetAdvertisingInterval()
677 return (NumConnections() == 0 && !ConfigurationMgr().IsFullyProvisioned()) || mFlags.Has(Flags::kFastAdvertisingEnabled)
678 ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL
679 : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL;
682 ssize_t BLEManagerImpl::HandleRXWrite(struct bt_conn * conId, const struct bt_gatt_attr * attr, const void * buf, uint16_t len,
683 uint16_t offset, uint8_t flags)
685 ChipDeviceEvent event;
686 PacketBufferHandle packetBuf = PacketBufferHandle::NewWithData(buf, len);
688 // Unfortunately the Zephyr logging macros end up assigning uint16_t
689 // variables to uint16_t:10 fields, which triggers integer conversion
690 // warnings. And treating the Zephyr headers as system headers does not
691 // help, apparently. Just turn off that warning around this log call.
692 #pragma GCC diagnostic push
693 #pragma GCC diagnostic ignored "-Wconversion"
694 LOG_HEXDUMP_DBG(buf, len, "Rx char write");
695 #pragma GCC diagnostic pop
698 if (!packetBuf.IsNull())
700 // Arrange to post a CHIPoBLERXWriteEvent event to the CHIP queue.
701 event.Type = DeviceEventType::kPlatformZephyrBleC1WriteEvent;
702 event.Platform.BleC1WriteEvent.BtConn = bt_conn_ref(conId);
703 event.Platform.BleC1WriteEvent.Data = std::move(packetBuf).UnsafeRelease();
706 // If we failed to allocate a buffer, post a kPlatformZephyrBleOutOfBuffersEvent event.
709 event.Type = DeviceEventType::kPlatformZephyrBleOutOfBuffersEvent;
712 PlatformMgr().PostEvent(&event);
717 ssize_t BLEManagerImpl::HandleTXCCCWrite(struct bt_conn * conId, const struct bt_gatt_attr * attr, uint16_t value)
719 ChipDeviceEvent event;
721 if (value != BT_GATT_CCC_INDICATE && value != 0)
723 return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
726 event.Type = DeviceEventType::kPlatformZephyrBleCCCWrite;
727 event.Platform.BleCCCWriteEvent.BtConn = bt_conn_ref(conId);
728 event.Platform.BleCCCWriteEvent.Value = value;
730 PlatformMgr().PostEvent(&event);
732 return sizeof(value);
735 void BLEManagerImpl::HandleTXIndicated(struct bt_conn * conId, IndicationAttrType, uint8_t err)
737 ChipDeviceEvent event;
739 event.Type = DeviceEventType::kPlatformZephyrBleC2IndDoneEvent;
740 event.Platform.BleC2IndDoneEvent.BtConn = bt_conn_ref(conId);
741 event.Platform.BleC2IndDoneEvent.Result = err;
743 PlatformMgr().PostEvent(&event);
746 void BLEManagerImpl::HandleConnect(struct bt_conn * conId, uint8_t err)
748 ChipDeviceEvent event;
750 event.Type = DeviceEventType::kPlatformZephyrBleConnected;
751 event.Platform.BleConnEvent.BtConn = bt_conn_ref(conId);
752 event.Platform.BleConnEvent.HciResult = err;
754 PlatformMgr().PostEvent(&event);
757 void BLEManagerImpl::HandleDisconnect(struct bt_conn * conId, uint8_t reason)
759 ChipDeviceEvent event;
761 event.Type = DeviceEventType::kPlatformZephyrBleDisconnected;
762 event.Platform.BleConnEvent.BtConn = bt_conn_ref(conId);
763 event.Platform.BleConnEvent.HciResult = reason;
765 PlatformMgr().PostEvent(&event);
768 } // namespace Internal
769 } // namespace DeviceLayer
772 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE