3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2019 Nest Labs, Inc.
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 Silicon Labs EFR32 platforms.
25 /* this file behaves like a config.h, comes first */
26 #include <platform/internal/CHIPDeviceLayerInternal.h>
27 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
29 #include <platform/internal/BLEManager.h>
32 #include "sl_bt_api.h"
33 #include "sl_bt_stack_config.h"
34 #include "sl_bt_stack_init.h"
36 #include <ble/CHIPBleServiceData.h>
37 #include <platform/EFR32/freertos_bluetooth.h>
38 #include <support/CodeUtils.h>
39 #include <support/logging/CHIPLogging.h>
41 using namespace ::chip;
42 using namespace ::chip::Ble;
45 namespace DeviceLayer {
50 #define CHIP_ADV_DATA_TYPE_FLAGS 0x01
51 #define CHIP_ADV_DATA_TYPE_UUID 0x03
52 #define CHIP_ADV_DATA_TYPE_NAME 0x09
53 #define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16
55 #define CHIP_ADV_DATA_FLAGS 0x06
57 #define CHIP_ADV_DATA 0
58 #define CHIP_ADV_SCAN_RESPONSE_DATA 1
59 #define CHIP_ADV_SHORT_UUID_LEN 2
61 #define MAX_RESPONSE_DATA_LEN 31
62 #define MAX_ADV_DATA_LEN 31
64 // Timer Frequency used.
65 #define TIMER_CLK_FREQ ((uint32_t) 32768)
66 // Convert msec to timer ticks.
67 #define TIMER_MS_2_TIMERTICK(ms) ((TIMER_CLK_FREQ * ms) / 1000)
68 #define TIMER_S_2_TIMERTICK(s) (TIMER_CLK_FREQ * s)
70 #define BLE_MAX_BUFFER_SIZE (3076)
71 #define BLE_MAX_ADVERTISERS (1)
72 #define BLE_CONFIG_MAX_PERIODIC_ADVERTISING_SYNC (0)
73 #define BLE_CONFIG_MAX_SOFTWARE_TIMERS (4)
74 #define BLE_CONFIG_MIN_TX_POWER (-30)
75 #define BLE_CONFIG_MAX_TX_POWER (80)
76 #define BLE_CONFIG_RF_PATH_GAIN_TX (0)
77 #define BLE_CONFIG_RF_PATH_GAIN_RX (0)
79 TimerHandle_t sbleAdvTimeoutTimer; // FreeRTOS sw timer.
81 /* Bluetooth stack configuration parameters (see "UG136: Silicon Labs Bluetooth C Application Developer's Guide" for
82 * details on each parameter) */
83 static sl_bt_configuration_t config;
85 StackType_t bluetoothEventStack[CHIP_DEVICE_CONFIG_BLE_APP_TASK_STACK_SIZE / sizeof(StackType_t)];
86 StaticTask_t bluetoothEventTaskStruct;
87 static TaskHandle_t BluetoothEventTaskHandle;
89 const uint8_t UUID_CHIPoBLEService[] = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
90 0x00, 0x10, 0x00, 0x00, 0xAF, 0xFE, 0x00, 0x00 };
91 const uint8_t ShortUUID_CHIPoBLEService[] = { 0xAF, 0xFE };
92 const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
94 const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
99 BLEManagerImpl BLEManagerImpl::sInstance;
101 /***************************************************************************/
103 * Setup the bluetooth init function.
107 * All bluetooth specific initialization
108 * code should be here like sl_bt_init_stack(),
109 * sl_bt_init_multiprotocol() and so on.
110 ******************************************************************************/
111 extern "C" sl_status_t initialize_bluetooth()
113 sl_status_t ret = sl_bt_init_stack(&config);
114 sl_bt_class_system_init();
115 sl_bt_class_advertiser_init();
116 sl_bt_class_gap_init();
117 sl_bt_class_scanner_init();
118 sl_bt_class_connection_init();
119 sl_bt_class_gatt_init();
120 sl_bt_class_gatt_server_init();
121 sl_bt_class_nvm_init();
122 sl_bt_class_sm_init();
123 sl_bt_init_multiprotocol();
127 static void initBleConfig(void)
129 memset(&config, 0, sizeof(sl_bt_configuration_t));
130 config.config_flags = SL_BT_CONFIG_FLAG_RTOS; /* Check flag options from UG136 */
131 config.bluetooth.max_connections = BLE_LAYER_NUM_BLE_ENDPOINTS; /* Maximum number of simultaneous connections */
132 config.bluetooth.max_advertisers = BLE_MAX_ADVERTISERS;
133 config.bluetooth.max_periodic_sync = BLE_CONFIG_MAX_PERIODIC_ADVERTISING_SYNC;
134 config.bluetooth.max_buffer_memory = BLE_MAX_BUFFER_SIZE;
135 config.gattdb = &bg_gattdb_data; /* Pointer to GATT database */
136 config.scheduler_callback = BluetoothLLCallback;
137 config.stack_schedule_callback = BluetoothUpdate;
138 config.max_timers = BLE_CONFIG_MAX_SOFTWARE_TIMERS;
139 config.rf.tx_gain = BLE_CONFIG_RF_PATH_GAIN_TX;
140 config.rf.rx_gain = BLE_CONFIG_RF_PATH_GAIN_RX;
141 config.rf.tx_min_power = BLE_CONFIG_MIN_TX_POWER;
142 config.rf.tx_max_power = BLE_CONFIG_MAX_TX_POWER;
144 config.pa.config_enable = 1; /* Set this to be a valid PA config */
145 #if defined(FEATURE_PA_INPUT_FROM_VBAT)
146 config.pa.input = SL_BT_RADIO_PA_INPUT_VBAT; /* Configure PA input to VBAT */
148 config.pa.input = SL_BT_RADIO_PA_INPUT_DCDC; /* Configure PA input to DCDC */
149 #endif // defined(FEATURE_PA_INPUT_FROM_VBAT)
150 #endif // (HAL_PA_ENABLE)
153 CHIP_ERROR BLEManagerImpl::_Init()
158 // Initialize the CHIP BleLayer.
159 err = BleLayer::Init(this, this, &SystemLayer);
162 memset(mBleConnections, 0, sizeof(mBleConnections));
163 memset(mIndConfId, kUnusedIndex, sizeof(mIndConfId));
164 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
168 // Start Bluetooth Link Layer and stack tasks
170 bluetooth_start(CHIP_DEVICE_CONFIG_BLE_LL_TASK_PRIORITY, CHIP_DEVICE_CONFIG_BLE_STACK_TASK_PRIORITY, initialize_bluetooth);
172 VerifyOrExit(ret == bg_err_success, err = MapBLEError(ret));
174 // Create the Bluetooth Application task
175 BluetoothEventTaskHandle =
176 xTaskCreateStatic(bluetoothStackEventHandler, /* Function that implements the task. */
177 CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME, /* Text name for the task. */
178 ArraySize(bluetoothEventStack), /* Number of indexes in the xStack array. */
179 this, /* Parameter passed into the task. */
180 CHIP_DEVICE_CONFIG_BLE_APP_TASK_PRIORITY, /* Priority at which the task is created. */
181 bluetoothEventStack, /* Pointer to task heap */
182 &bluetoothEventTaskStruct); /* Variable that holds the task struct */
184 // Create FreeRTOS sw timer for BLE timeouts and interval change.
185 sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel
186 1, // == default timer period (mS)
187 false, // no timer reload (==one-shot)
188 (void *) this, // init timer id = ble obj context
189 BleAdvTimeoutHandler // timer callback handler
192 mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART);
193 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
194 PlatformMgr().ScheduleWork(DriveBLEState, 0);
200 uint16_t BLEManagerImpl::_NumConnections(void)
202 uint16_t numCons = 0;
203 for (uint16_t i = 0; i < kMaxConnections; i++)
205 if (mBleConnections[i].allocated)
214 void BLEManagerImpl::bluetoothStackEventHandler(void * p_arg)
216 EventBits_t flags = 0;
220 // wait for Bluetooth stack events, do not consume set flag
221 flags = xEventGroupWaitBits(bluetooth_event_flags, /* The event group being tested. */
222 BLUETOOTH_EVENT_FLAG_EVT_WAITING, /* The bits within the event group to wait for. */
223 pdFALSE, /* Dont clear flags before returning */
224 pdFALSE, /* Any flag will do, dont wait for all flags to be set */
225 portMAX_DELAY); /* Wait for maximum duration for bit to be set */
227 if (flags & BLUETOOTH_EVENT_FLAG_EVT_WAITING)
229 flags &= ~BLUETOOTH_EVENT_FLAG_EVT_WAITING;
230 xEventGroupClearBits(bluetooth_event_flags, BLUETOOTH_EVENT_FLAG_EVT_WAITING);
232 // As this is running in a separate thread, we need to block CHIP from operating,
233 // until the events are handled.
234 PlatformMgr().LockChipStack();
236 // handle bluetooth events
237 switch (SL_BT_MSG_ID(bluetooth_evt->header))
239 case sl_bt_evt_system_boot_id: {
240 ChipLogProgress(DeviceLayer, "Bluetooth stack booted: v%d.%d.%d-b%d\n", bluetooth_evt->data.evt_system_boot.major,
241 bluetooth_evt->data.evt_system_boot.minor, bluetooth_evt->data.evt_system_boot.patch,
242 bluetooth_evt->data.evt_system_boot.build);
243 sInstance.HandleBootEvent();
247 case sl_bt_evt_connection_opened_id: {
248 sInstance.HandleConnectEvent(bluetooth_evt);
251 case sl_bt_evt_connection_parameters_id: {
252 // ChipLogProgress(DeviceLayer, "Connection parameter ID received. Nothing to do");
255 case sl_bt_evt_connection_phy_status_id: {
256 // ChipLogProgress(DeviceLayer, "PHY update procedure is completed");
259 case sl_bt_evt_connection_closed_id: {
260 sInstance.HandleConnectionCloseEvent(bluetooth_evt);
264 /* This event indicates that a remote GATT client is attempting to write a value of an
265 * attribute in to the local GATT database, where the attribute was defined in the GATT
266 * XML firmware configuration file to have type="user". */
267 case sl_bt_evt_gatt_server_attribute_value_id: {
268 sInstance.HandleWriteEvent(bluetooth_evt);
272 case sl_bt_evt_gatt_mtu_exchanged_id: {
273 sInstance.UpdateMtu(bluetooth_evt);
277 // confirmation of indication received from remote GATT client
278 case sl_bt_evt_gatt_server_characteristic_status_id: {
279 sl_bt_gatt_server_characteristic_status_flag_t StatusFlags;
281 StatusFlags = (sl_bt_gatt_server_characteristic_status_flag_t)
282 bluetooth_evt->data.evt_gatt_server_characteristic_status.status_flags;
284 if (sl_bt_gatt_server_confirmation == StatusFlags)
286 sInstance.HandleTxConfirmationEvent(bluetooth_evt);
288 else if ((bluetooth_evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_CHIPoBLEChar_Tx) &&
289 (bluetooth_evt->data.evt_gatt_server_characteristic_status.status_flags == gatt_server_client_config))
291 sInstance.HandleTXCharCCCDWrite(bluetooth_evt);
296 /* Software Timer event */
297 case sl_bt_evt_system_soft_timer_id: {
298 sInstance.HandleSoftTimerEvent(bluetooth_evt);
303 ChipLogProgress(DeviceLayer, "evt_UNKNOWN id = %08x", SL_BT_MSG_ID(bluetooth_evt->header));
308 PlatformMgr().UnlockChipStack();
310 vRaiseEventFlagBasedOnContext(bluetooth_event_flags, BLUETOOTH_EVENT_FLAG_EVT_HANDLED);
314 CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val)
316 CHIP_ERROR err = CHIP_NO_ERROR;
318 VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
319 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
321 if (val != mServiceMode)
324 PlatformMgr().ScheduleWork(DriveBLEState, 0);
331 CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
333 CHIP_ERROR err = CHIP_NO_ERROR;
335 VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
337 if (mFlags.Has(Flags::kAdvertisingEnabled) != val)
339 mFlags.Set(Flags::kAdvertisingEnabled, val);
340 PlatformMgr().ScheduleWork(DriveBLEState, 0);
347 CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
351 case BLEAdvertisingMode::kFastAdvertising:
352 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
354 case BLEAdvertisingMode::kSlowAdvertising:
355 mFlags.Set(Flags::kFastAdvertisingEnabled, false);
358 return CHIP_ERROR_INVALID_ARGUMENT;
360 mFlags.Set(Flags::kRestartAdvertising);
361 PlatformMgr().ScheduleWork(DriveBLEState, 0);
362 return CHIP_NO_ERROR;
365 CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
367 if (strlen(mDeviceName) >= bufSize)
369 return CHIP_ERROR_BUFFER_TOO_SMALL;
371 strcpy(buf, mDeviceName);
372 return CHIP_NO_ERROR;
375 CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
378 CHIP_ERROR err = CHIP_NO_ERROR;
379 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported)
381 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
383 if (deviceName != NULL && deviceName[0] != 0)
385 if (strlen(deviceName) >= kMaxDeviceNameLength)
387 return CHIP_ERROR_INVALID_ARGUMENT;
389 strcpy(mDeviceName, deviceName);
390 mFlags.Set(Flags::kDeviceNameSet);
391 ChipLogProgress(DeviceLayer, "Setting device name to : \"%s\"", deviceName);
392 static_assert(kMaxDeviceNameLength <= UINT16_MAX, "deviceName length might not fit in a uint8_t");
393 ret = sl_bt_gatt_server_write_attribute_value(gattdb_device_name, 0, strlen(deviceName), (uint8_t *) deviceName);
394 if (ret != SL_STATUS_OK)
396 err = MapBLEError(ret);
397 ChipLogError(DeviceLayer, "sl_bt_gatt_server_write_attribute_value() failed: %s", ErrorStr(err));
405 return CHIP_NO_ERROR;
408 void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
412 case DeviceEventType::kCHIPoBLESubscribe: {
413 ChipDeviceEvent connEstEvent;
415 ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLESubscribe");
416 HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
417 connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
418 PlatformMgr().PostEvent(&connEstEvent);
422 case DeviceEventType::kCHIPoBLEUnsubscribe: {
423 ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe");
424 HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
428 case DeviceEventType::kCHIPoBLEWriteReceived: {
429 ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived");
430 HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
431 PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
435 case DeviceEventType::kCHIPoBLEConnectionError: {
436 ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError");
437 HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
441 case DeviceEventType::kCHIPoBLEIndicateConfirm: {
442 ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm");
443 HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
448 ChipLogProgress(DeviceLayer, "_OnPlatformEvent default: event->Type = %d", event->Type);
453 bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
455 ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported");
459 bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
461 ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported");
465 bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
467 CHIP_ERROR err = CHIP_NO_ERROR;
470 ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId);
472 ret = sl_bt_connection_close(conId);
473 err = MapBLEError(ret);
475 if (err != CHIP_NO_ERROR)
477 ChipLogError(DeviceLayer, "sl_bt_connection_close() failed: %s", ErrorStr(err));
480 return (err == CHIP_NO_ERROR);
483 uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
485 CHIPoBLEConState * conState = const_cast<BLEManagerImpl *>(this)->GetConnectionState(conId);
486 return (conState != NULL) ? conState->mtu : 0;
489 bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
490 PacketBufferHandle data)
492 CHIP_ERROR err = CHIP_NO_ERROR;
493 CHIPoBLEConState * conState = GetConnectionState(conId);
495 uint16_t cId = (UUIDsMatch(&ChipUUID_CHIPoBLEChar_RX, charId) ? gattdb_CHIPoBLEChar_Rx : gattdb_CHIPoBLEChar_Tx);
496 uint8_t timerHandle = GetTimerHandle(conId, true);
498 VerifyOrExit(((conState != NULL) && (conState->subscribed != 0)), err = CHIP_ERROR_INVALID_ARGUMENT);
499 VerifyOrExit(timerHandle != kMaxConnections, err = CHIP_ERROR_NO_MEMORY);
501 // start timer for light indication confirmation. Long delay for spake2 indication
502 sl_bt_system_set_soft_timer(TIMER_S_2_TIMERTICK(6), timerHandle, true);
504 ret = sl_bt_gatt_server_send_indication(conId, cId, (data->DataLength()), data->Start());
506 err = MapBLEError(ret);
509 if (err != CHIP_NO_ERROR)
511 ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err));
517 bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
518 PacketBufferHandle pBuf)
520 ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported");
524 bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
525 PacketBufferHandle pBuf)
527 ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported");
531 bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
532 const ChipBleUUID * svcId, const ChipBleUUID * charId)
534 ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported");
538 void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
543 CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr)
548 return CHIP_NO_ERROR;
549 case SL_STATUS_BT_ATT_INVALID_ATT_LENGTH:
550 return CHIP_ERROR_INVALID_STRING_LENGTH;
551 case SL_STATUS_INVALID_PARAMETER:
552 return CHIP_ERROR_INVALID_ARGUMENT;
554 return (CHIP_ERROR) bleErr + CHIP_DEVICE_CONFIG_EFR32_BLE_ERROR_MIN;
558 void BLEManagerImpl::DriveBLEState(void)
560 CHIP_ERROR err = CHIP_NO_ERROR;
562 // Check if BLE stack is initialized
563 VerifyOrExit(mFlags.Has(Flags::kEFRBLEStackInitialized), /* */);
565 // Start advertising if needed...
566 if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled) &&
567 NumConnections() < kMaxConnections)
569 // Start/re-start advertising if not already started, or if there is a pending change
570 // to the advertising configuration.
571 if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kRestartAdvertising))
573 err = StartAdvertising();
578 // Otherwise, stop advertising if it is enabled.
579 else if (mFlags.Has(Flags::kAdvertising))
581 err = StopAdvertising();
586 if (err != CHIP_NO_ERROR)
588 ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
589 mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
593 CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void)
596 ChipBLEDeviceIdentificationInfo mDeviceIdInfo;
598 uint8_t responseData[MAX_RESPONSE_DATA_LEN];
599 uint8_t advData[MAX_ADV_DATA_LEN];
601 uint32_t mDeviceNameLength = 0;
602 uint8_t mDeviceIdInfoLength = 0;
604 VerifyOrExit((kMaxDeviceNameLength + 1) < UINT8_MAX, err = CHIP_ERROR_INVALID_ARGUMENT);
606 memset(responseData, 0, MAX_RESPONSE_DATA_LEN);
607 memset(advData, 0, MAX_ADV_DATA_LEN);
609 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(mDeviceIdInfo);
612 if (!mFlags.Has(Flags::kDeviceNameSet))
614 snprintf(mDeviceName, sizeof(mDeviceName), "%s%04" PRIX32, CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, (uint32_t) 0);
616 mDeviceName[kMaxDeviceNameLength] = 0;
617 mDeviceNameLength = strlen(mDeviceName);
619 VerifyOrExit(mDeviceNameLength < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT);
621 ret = sl_bt_gatt_server_write_attribute_value(gattdb_device_name, 0, mDeviceNameLength, (uint8_t *) mDeviceName);
622 if (ret != SL_STATUS_OK)
624 err = MapBLEError(ret);
625 ChipLogError(DeviceLayer, "sl_bt_gatt_server_write_attribute_value() failed: %s", ErrorStr(err));
630 mDeviceNameLength = strlen(mDeviceName); // Device Name length + length field
631 VerifyOrExit(mDeviceNameLength < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT);
633 mDeviceIdInfoLength = sizeof(mDeviceIdInfo); // Servicedatalen + length+ UUID (Short)
634 static_assert(sizeof(mDeviceIdInfo) + CHIP_ADV_SHORT_UUID_LEN + 1 <= UINT8_MAX, "Our length won't fit in a uint8_t");
635 static_assert(2 + CHIP_ADV_SHORT_UUID_LEN + sizeof(mDeviceIdInfo) + 1 <= MAX_ADV_DATA_LEN, "Our buffer is not big enough");
638 advData[index++] = 0x02; // length
639 advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags
640 advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value
641 advData[index++] = static_cast<uint8_t>(mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1); // AD length
642 advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type : Service Data
643 advData[index++] = ShortUUID_CHIPoBLEService[0]; // AD value
644 advData[index++] = ShortUUID_CHIPoBLEService[1];
645 memcpy(&advData[index], (void *) &mDeviceIdInfo, mDeviceIdInfoLength); // AD value
646 index += mDeviceIdInfoLength;
648 advData[index++] = static_cast<uint8_t>(mDeviceNameLength + 1); // length
649 advData[index++] = CHIP_ADV_DATA_TYPE_NAME; // AD type : name
650 memcpy(&advData[index], mDeviceName, mDeviceNameLength); // AD value
651 index += mDeviceNameLength;
653 if (0xff != advertising_set_handle)
655 sl_bt_advertiser_delete_set(advertising_set_handle);
656 advertising_set_handle = 0xff;
659 ret = sl_bt_advertiser_create_set(&advertising_set_handle);
660 if (ret != SL_STATUS_OK)
662 err = MapBLEError(ret);
663 ChipLogError(DeviceLayer, "sl_bt_advertiser_create_set() failed: %s", ErrorStr(err));
666 ret = sl_bt_advertiser_set_data(advertising_set_handle, CHIP_ADV_DATA, index, (uint8_t *) advData);
668 if (ret != SL_STATUS_OK)
670 err = MapBLEError(ret);
671 ChipLogError(DeviceLayer, "sl_bt_advertiser_set_data() failed: %s", ErrorStr(err));
677 responseData[index++] = CHIP_ADV_SHORT_UUID_LEN + 1; // AD length
678 responseData[index++] = CHIP_ADV_DATA_TYPE_UUID; // AD type : uuid
679 responseData[index++] = ShortUUID_CHIPoBLEService[0]; // AD value
680 responseData[index++] = ShortUUID_CHIPoBLEService[1];
682 ret = sl_bt_advertiser_set_data(advertising_set_handle, CHIP_ADV_SCAN_RESPONSE_DATA, index, (uint8_t *) responseData);
684 if (ret != SL_STATUS_OK)
686 err = MapBLEError(ret);
687 ChipLogError(DeviceLayer, "sl_bt_advertiser_set_data() failed: %s", ErrorStr(err));
691 err = MapBLEError(ret);
697 CHIP_ERROR BLEManagerImpl::StartAdvertising(void)
701 const uint8_t kResolvableRandomAddrType = 2; // Private resolvable random address type
702 bd_addr unusedBdAddr; // We can ignore this field when setting random address.
703 uint32_t interval_min;
704 uint32_t interval_max;
705 uint32_t BleAdvTimeoutMs;
706 uint16_t numConnectionss = NumConnections();
707 uint8_t connectableAdv =
708 (numConnectionss < kMaxConnections) ? sl_bt_advertiser_connectable_scannable : sl_bt_advertiser_scannable_non_connectable;
710 // If already advertising, stop it, before changing values
711 if (mFlags.Has(Flags::kAdvertising))
713 sl_bt_advertiser_stop(sInstance.advertising_set_handle);
717 ChipLogDetail(DeviceLayer, "Start BLE advertissement");
718 // If necessary, inform the ThreadStackManager that CHIPoBLE advertising is about to start.
719 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
720 ThreadStackMgr().OnCHIPoBLEAdvertisingStart();
721 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
724 err = ConfigureAdvertisingData();
727 sl_bt_advertiser_set_random_address(advertising_set_handle, kResolvableRandomAddrType, unusedBdAddr, &unusedBdAddr);
730 mFlags.Clear(Flags::kRestartAdvertising);
732 if (mFlags.Has(Flags::kFastAdvertisingEnabled))
734 interval_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN;
735 interval_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX;
736 BleAdvTimeoutMs = CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME;
740 interval_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN;
741 interval_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX;
742 BleAdvTimeoutMs = CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT;
745 ret = sl_bt_advertiser_set_timing(advertising_set_handle, interval_min, interval_max, 0, 0);
746 err = MapBLEError(ret);
749 ret = sl_bt_advertiser_start(advertising_set_handle, sl_bt_advertiser_user_data, connectableAdv);
751 if (SL_STATUS_OK == ret)
753 StartBleAdvTimeoutTimer(BleAdvTimeoutMs);
754 mFlags.Set(Flags::kAdvertising);
757 err = MapBLEError(ret);
763 CHIP_ERROR BLEManagerImpl::StopAdvertising(void)
765 CHIP_ERROR err = CHIP_NO_ERROR;
768 if (mFlags.Has(Flags::kAdvertising))
770 mFlags.Clear(Flags::kAdvertising).Clear(Flags::kRestartAdvertising);
771 mFlags.Set(Flags::kFastAdvertisingEnabled, true);
773 ret = sl_bt_advertiser_stop(advertising_set_handle);
774 sl_bt_advertiser_delete_set(advertising_set_handle);
775 advertising_set_handle = 0xff;
776 err = MapBLEError(ret);
779 CancelBleAdvTimeoutTimer();
780 // If necessary, inform the ThreadStackManager that CHIPoBLE advertising has stopped
781 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
782 ThreadStackMgr().OnCHIPoBLEAdvertisingStop();
783 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
790 void BLEManagerImpl::UpdateMtu(volatile sl_bt_msg_t * evt)
792 CHIPoBLEConState * bleConnState = GetConnectionState(evt->data.evt_gatt_mtu_exchanged.connection);
793 if (bleConnState != NULL)
795 // bleConnState->MTU is a 10-bit field inside a uint16_t. We're
796 // assigning to it from a uint16_t, and compilers warn about
797 // possibly not fitting. There's no way to suppress that warning
798 // via explicit cast; we have to disable the warning around the
801 // TODO: https://github.com/project-chip/connectedhomeip/issues/2569
802 // tracks making this safe with a check or explaining why no check
804 #pragma GCC diagnostic push
805 #pragma GCC diagnostic ignored "-Wconversion"
806 bleConnState->mtu = evt->data.evt_gatt_mtu_exchanged.mtu;
807 #pragma GCC diagnostic pop
812 void BLEManagerImpl::HandleBootEvent(void)
814 mFlags.Set(Flags::kEFRBLEStackInitialized);
815 PlatformMgr().ScheduleWork(DriveBLEState, 0);
818 void BLEManagerImpl::HandleConnectEvent(volatile sl_bt_msg_t * evt)
820 sl_bt_evt_connection_opened_t * conn_evt = (sl_bt_evt_connection_opened_t *) &(evt->data);
821 uint8_t connHandle = conn_evt->connection;
822 uint8_t bondingHandle = conn_evt->bonding;
824 ChipLogProgress(DeviceLayer, "Connect Event for handle : %d", connHandle);
826 AddConnection(connHandle, bondingHandle);
828 PlatformMgr().ScheduleWork(DriveBLEState, 0);
831 void BLEManagerImpl::HandleConnectionCloseEvent(volatile sl_bt_msg_t * evt)
833 sl_bt_evt_connection_closed_t * conn_evt = (sl_bt_evt_connection_closed_t *) &(evt->data);
834 uint8_t connHandle = conn_evt->connection;
836 ChipLogProgress(DeviceLayer, "Disconnect Event for handle : %d", connHandle);
838 if (RemoveConnection(connHandle))
840 ChipDeviceEvent event;
841 event.Type = DeviceEventType::kCHIPoBLEConnectionError;
842 event.CHIPoBLEConnectionError.ConId = connHandle;
844 switch (conn_evt->reason)
846 case bg_err_bt_remote_user_terminated:
847 case bg_err_bt_remote_device_terminated_connection_due_to_low_resources:
848 case bg_err_bt_remote_powering_off:
849 event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
852 case bg_err_bt_connection_terminated_by_local_host:
853 event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION;
857 event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
861 ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %u)", connHandle, conn_evt->reason);
863 PlatformMgr().PostEvent(&event);
865 // Arrange to re-enable connectable advertising in case it was disabled due to the
866 // maximum connection limit being reached.
867 mFlags.Set(Flags::kRestartAdvertising);
868 mFlags.Set(Flags::kFastAdvertisingEnabled);
869 PlatformMgr().ScheduleWork(DriveBLEState, 0);
873 void BLEManagerImpl::HandleWriteEvent(volatile sl_bt_msg_t * evt)
875 uint16_t attribute = evt->data.evt_gatt_server_user_write_request.characteristic;
877 ChipLogProgress(DeviceLayer, "Char Write Req, char : %d", attribute);
879 if (gattdb_CHIPoBLEChar_Rx == attribute)
881 HandleRXCharWrite(evt);
885 void BLEManagerImpl::HandleTXCharCCCDWrite(volatile sl_bt_msg_t * evt)
887 CHIP_ERROR err = CHIP_NO_ERROR;
888 CHIPoBLEConState * bleConnState;
889 bool indicationsEnabled;
890 ChipDeviceEvent event;
892 bleConnState = GetConnectionState(evt->data.evt_gatt_server_user_write_request.connection);
894 VerifyOrExit(bleConnState != NULL, err = CHIP_ERROR_NO_MEMORY);
896 // Determine if the client is enabling or disabling indications.
897 indicationsEnabled = (evt->data.evt_gatt_server_characteristic_status.client_config_flags == gatt_indication);
899 ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", indicationsEnabled ? "subscribe" : "unsubscribe");
901 if (indicationsEnabled)
903 // If indications are not already enabled for the connection...
904 if (!bleConnState->subscribed)
906 bleConnState->subscribed = 1;
907 // Post an event to the CHIP queue to process either a CHIPoBLE Subscribe or Unsubscribe based on
908 // whether the client is enabling or disabling indications.
910 event.Type = DeviceEventType::kCHIPoBLESubscribe;
911 event.CHIPoBLESubscribe.ConId = evt->data.evt_gatt_server_user_write_request.connection;
912 PlatformMgr().PostEvent(&event);
918 bleConnState->subscribed = 0;
919 event.Type = DeviceEventType::kCHIPoBLEUnsubscribe;
920 event.CHIPoBLESubscribe.ConId = evt->data.evt_gatt_server_user_write_request.connection;
921 PlatformMgr().PostEvent(&event);
925 if (err != CHIP_NO_ERROR)
927 ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err));
931 void BLEManagerImpl::HandleRXCharWrite(volatile sl_bt_msg_t * evt)
933 CHIP_ERROR err = CHIP_NO_ERROR;
934 System::PacketBufferHandle buf;
935 uint16_t writeLen = evt->data.evt_gatt_server_user_write_request.value.len;
936 uint8_t * data = (uint8_t *) evt->data.evt_gatt_server_user_write_request.value.data;
938 // Copy the data to a packet buffer.
939 buf = System::PacketBufferHandle::NewWithData(data, writeLen, 0, 0);
940 VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
942 ChipLogDetail(DeviceLayer, "Write request/command received for CHIPoBLE RX characteristic (con %" PRIu16 ", len %" PRIu16 ")",
943 evt->data.evt_gatt_server_user_write_request.connection, buf->DataLength());
945 // Post an event to the CHIP queue to deliver the data into the CHIP stack.
947 ChipDeviceEvent event;
948 event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
949 event.CHIPoBLEWriteReceived.ConId = evt->data.evt_gatt_server_user_write_request.connection;
950 event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease();
951 PlatformMgr().PostEvent(&event);
955 if (err != CHIP_NO_ERROR)
957 ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
961 void BLEManagerImpl::HandleTxConfirmationEvent(volatile sl_bt_msg_t * evt)
963 ChipDeviceEvent event;
964 uint8_t timerHandle = sInstance.GetTimerHandle(evt->data.evt_gatt_server_characteristic_status.connection);
966 ChipLogProgress(DeviceLayer, "Tx Confirmation received");
968 // stop indication confirmation timer
969 if (timerHandle < kMaxConnections)
971 ChipLogProgress(DeviceLayer, " stop soft timer");
972 sl_bt_system_set_soft_timer(0, timerHandle, false);
975 event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
976 event.CHIPoBLEIndicateConfirm.ConId = evt->data.evt_gatt_server_characteristic_status.connection;
977 PlatformMgr().PostEvent(&event);
980 void BLEManagerImpl::HandleSoftTimerEvent(volatile sl_bt_msg_t * evt)
982 // BLE Manager starts soft timers with timer handles less than kMaxConnections
983 // If we receive a callback for unknown timer handle ignore this.
984 if (evt->data.evt_system_soft_timer.handle < kMaxConnections)
986 ChipLogProgress(DeviceLayer, "BLEManagerImpl::HandleSoftTimerEvent CHIPOBLE_PROTOCOL_ABORT");
987 ChipDeviceEvent event;
988 event.Type = DeviceEventType::kCHIPoBLEConnectionError;
989 event.CHIPoBLEConnectionError.ConId = mIndConfId[evt->data.evt_system_soft_timer.handle];
990 sInstance.mIndConfId[evt->data.evt_system_soft_timer.handle] = kUnusedIndex;
991 event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
992 PlatformMgr().PostEvent(&event);
996 bool BLEManagerImpl::RemoveConnection(uint8_t connectionHandle)
998 CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true);
1001 if (bleConnState != NULL)
1003 memset(bleConnState, 0, sizeof(CHIPoBLEConState));
1010 void BLEManagerImpl::AddConnection(uint8_t connectionHandle, uint8_t bondingHandle)
1012 CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true);
1014 if (bleConnState != NULL)
1016 memset(bleConnState, 0, sizeof(CHIPoBLEConState));
1017 bleConnState->allocated = 1;
1018 bleConnState->connectionHandle = connectionHandle;
1019 bleConnState->bondingHandle = bondingHandle;
1023 BLEManagerImpl::CHIPoBLEConState * BLEManagerImpl::GetConnectionState(uint8_t connectionHandle, bool allocate)
1025 uint8_t freeIndex = kMaxConnections;
1027 for (uint8_t i = 0; i < kMaxConnections; i++)
1029 if (mBleConnections[i].allocated == 1)
1031 if (mBleConnections[i].connectionHandle == connectionHandle)
1033 return &mBleConnections[i];
1037 else if (i < freeIndex)
1045 if (freeIndex < kMaxConnections)
1047 return &mBleConnections[freeIndex];
1050 ChipLogError(DeviceLayer, "Failed to allocate CHIPoBLEConState");
1056 uint8_t BLEManagerImpl::GetTimerHandle(uint8_t connectionHandle, bool allocate)
1058 uint8_t freeIndex = kMaxConnections;
1060 for (uint8_t i = 0; i < kMaxConnections; i++)
1062 if (mIndConfId[i] == connectionHandle)
1075 if (freeIndex < kMaxConnections)
1077 mIndConfId[freeIndex] = connectionHandle;
1081 ChipLogError(DeviceLayer, "Failed to Save Conn Handle for indication");
1087 void BLEManagerImpl::BleAdvTimeoutHandler(TimerHandle_t xTimer)
1089 if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled))
1091 ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertissment");
1092 BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
1094 else if (BLEMgrImpl().mFlags.Has(Flags::kAdvertising))
1096 // Advertisement time expired. Stop advertising
1097 ChipLogDetail(DeviceLayer, "bleAdv Timeout : Stop advertissement");
1098 BLEMgr().SetAdvertisingEnabled(false);
1102 void BLEManagerImpl::CancelBleAdvTimeoutTimer(void)
1104 if (xTimerStop(sbleAdvTimeoutTimer, 0) == pdFAIL)
1106 ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer");
1110 void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs)
1112 if (xTimerIsTimerActive(sbleAdvTimeoutTimer))
1114 CancelBleAdvTimeoutTimer();
1117 // timer is not active, change its period to required value (== restart).
1118 // FreeRTOS- Block for a maximum of 100 ticks if the change period command
1119 // cannot immediately be sent to the timer command queue.
1120 if (xTimerChangePeriod(sbleAdvTimeoutTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS)
1122 ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer");
1126 void BLEManagerImpl::DriveBLEState(intptr_t arg)
1128 sInstance.DriveBLEState();
1131 } // namespace Internal
1132 } // namespace DeviceLayer
1134 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE