blob: 55bb0bfad17f367faed6289ecaee89aa62c5344d [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2019 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Provides an implementation of the BLEManager singleton object
* for the MediaTek Genio platforms.
*/
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>
#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
#undef BT_ENABLE_HCI_SNOOP_LOG
#include <platform/CommissionableDataProvider.h>
#include <platform/internal/BLEManager.h>
#include "FreeRTOS.h"
#include "event_groups.h"
#include "timers.h"
#include <ble/Ble.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include "bt_callback_manager.h"
#include "bt_gap_le.h"
#include "bt_gatts.h"
#include "bt_init.h"
#include "bt_platform.h"
#include "bt_uuid.h"
#include "connection_info.h"
#ifdef BT_ENABLE_HCI_SNOOP_LOG
#include "bt_driver_btsnoop.h"
#endif
#include "gatt_service.h"
using namespace ::chip;
using namespace ::chip::Ble;
extern void (*CHIPoBLEProfile_read_callback)(uint16_t handle, void * data, uint16_t size);
extern void (*CHIPoBLEProfile_write_callback)(uint16_t handle, void * data, uint16_t size);
extern void (*CHIPoBLEProfile_ccc_callback)(uint16_t handle, void * data, uint16_t size);
namespace chip {
namespace DeviceLayer {
namespace Internal {
namespace {
#define CHIP_ADV_DATA_TYPE_FLAGS 0x01
#define CHIP_ADV_DATA_FLAGS 0x06
#define CHIP_ADV_DATA_TYPE_NAME 0x09
#define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16
#define CHIP_ADV_SHORT_UUID_LEN 2
#define MAX_ADV_DATA_LEN (31)
#define BLE_ADV_OTHER_LEN (9)
const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF };
#define EG_EVENT_BLE_POWER_ON_CNF (0x01)
#define EG_EVENT_BLE_ADV_CNF (0x02)
TimerHandle_t sbleAdvTimeoutTimer; // FreeRTOS sw timer.
EventGroupHandle_t xBleEventGroup;
} // namespace
BLEManagerImpl BLEManagerImpl::sInstance;
/***************************************************************************/
/**
* Setup the bluetooth init function.
*
* @return none
*
* All bluetooth specific initialization
******************************************************************************/
CHIP_ERROR BLEManagerImpl::_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
// Initialize the CHIP BleLayer.
ChipLogError(DeviceLayer, "BLE init start");
err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer());
ChipLogError(DeviceLayer, "BleLayer init complete");
SuccessOrExit(err);
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
CHIPoBLEProfile_write_callback = BLEManagerImpl::HandleRXCharWrite;
CHIPoBLEProfile_ccc_callback = BLEManagerImpl::HandleTXCharCCCDWrite;
xBleEventGroup = xEventGroupCreate();
if (xBleEventGroup == NULL)
{
ChipLogError(DeviceLayer, "Cannot create xBleEventGroup");
err = CHIP_ERROR_NO_MEMORY;
}
SuccessOrExit(err);
init_connection_info();
bt_create_task();
bt_callback_manager_register_callback(bt_callback_type_app_event,
(uint32_t) (MODULE_MASK_GAP | MODULE_MASK_GATT | MODULE_MASK_SYSTEM),
(void *) BleMatterAppEventCallback);
#ifdef BT_ENABLE_HCI_SNOOP_LOG
bt_driver_btsnoop_ctrl(1);
#endif
// Create FreeRTOS sw timer for BLE timeouts and interval change.
sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel
1, // == default timer period (mS)
false, // no timer reload (==one-shot)
(void *) this, // init timer id = ble obj context
BleAdvTimeoutHandler // timer callback handler
);
mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART);
mFlags.Set(Flags::kFastAdvertisingEnabled, true);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
exit:
return err;
}
uint16_t BLEManagerImpl::_NumConnections(void)
{
return num_connection_info();
}
#if 0
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);
if (val != mServiceMode)
{
mServiceMode = val;
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
exit:
return err;
}
#endif
CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
if (mFlags.Has(Flags::kAdvertisingEnabled) != val)
{
mFlags.Set(Flags::kAdvertisingEnabled, val);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
exit:
return err;
}
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::kRestartAdvertising);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
return CHIP_NO_ERROR;
}
CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
{
if (strlen(gatts_device_name) >= bufSize)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
strcpy(buf, gatts_device_name);
return CHIP_NO_ERROR;
}
CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
{
CHIP_ERROR err = CHIP_NO_ERROR;
if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
if (deviceName != NULL && deviceName[0] != 0)
{
if (strlen(deviceName) >= kMaxDeviceNameLength)
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
strcpy(gatts_device_name, deviceName);
}
else
{
gatts_device_name[0] = 0;
}
return CHIP_NO_ERROR;
}
void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
switch (event->Type)
{
case DeviceEventType::kCHIPoBLESubscribe: {
ChipDeviceEvent connEstEvent;
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLESubscribe");
HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID);
connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
PlatformMgr().PostEventOrDie(&connEstEvent);
}
break;
case DeviceEventType::kCHIPoBLEUnsubscribe: {
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLEUnsubscribe");
HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID);
}
break;
case DeviceEventType::kCHIPoBLEWriteReceived: {
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLEWriteReceived");
HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID,
PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
}
break;
case DeviceEventType::kCHIPoBLEConnectionError: {
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLEConnectionError");
HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
}
break;
case DeviceEventType::kCHIPoBLEIndicateConfirm: {
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLEIndicateConfirm, ConId %04x",
event->CHIPoBLEIndicateConfirm.ConId);
HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID);
}
break;
case DeviceEventType::kCHIPoBLENotifyConfirm: {
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent kCHIPoBLENotifyConfirm");
HandleTxConfirmationEvent(event->CHIPoBLENotifyConfirm.ConId);
}
break;
default:
ChipLogProgress(DeviceLayer, "_OnBlePlatformEvent default: event->Type = %d", event->Type);
break;
}
}
CHIP_ERROR BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId,
const ChipBleUUID * charId)
{
ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
CHIP_ERROR BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId,
const ChipBleUUID * charId)
{
ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
CHIP_ERROR BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
bt_hci_cmd_disconnect_t disconnect_para;
bt_status_t ret;
ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId);
disconnect_para.connection_handle = conId;
disconnect_para.reason = BT_HCI_STATUS_REMOTE_USER_TERMINATED_CONNECTION;
ret = bt_gap_le_disconnect(&disconnect_para);
err = MapBLEError(ret);
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "bt_gap_le_disconnect() failed: %s", ErrorStr(err));
}
return err;
}
uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
uint16_t mtu = (uint16_t) bt_gattc_get_mtu(conId);
ChipLogProgress(DeviceLayer, "GetMTU (con %u), returning %u", conId, mtu);
return mtu;
}
#define INDICATION_BUFFER_LENGTH (300)
CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle data)
{
uint8_t buf[INDICATION_BUFFER_LENGTH + 3] = { 0 };
bt_gattc_charc_value_notification_indication_t * req;
CHIP_ERROR err = CHIP_NO_ERROR;
ChipDeviceEvent event;
bt_status_t ret;
VerifyOrExit(UUIDsMatch(&Ble::CHIP_BLE_CHAR_2_UUID, charId), err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
ChipLogProgress(DeviceLayer, "SendIndication(): conId %d, len %d", conId, data->DataLength());
if (data->DataLength() > INDICATION_BUFFER_LENGTH)
{
ChipLogError(DeviceLayer, "SendIndication(): Exceed buffer length! conId %d, len %d", conId, data->DataLength());
err = CHIP_ERROR_NO_MEMORY;
goto exit;
}
req = (bt_gattc_charc_value_notification_indication_t *) buf;
req->attribute_value_length = 3 + data->DataLength();
req->att_req.opcode = BT_ATT_OPCODE_HANDLE_VALUE_INDICATION;
req->att_req.handle = 24;
memcpy(&req->att_req.attribute_value[0], data->Start(), data->DataLength());
ret = bt_gatts_send_charc_value_notification_indication(conId, req);
err = MapBLEError(ret);
SuccessOrExit(err);
exit:
return err;
}
void BLEManagerImpl::HandleRXCharWrite(uint16_t handle, void * data, uint16_t size)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle buf;
uint16_t writeLen = size;
// Copy the data to a packet buffer.
buf = System::PacketBufferHandle::NewWithData(data, writeLen, 0, 0);
VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
ChipLogDetail(DeviceLayer, "Write request/command received for CHIPoBLE RX characteristic (con %u, len %u)", handle,
buf->DataLength());
// Post an event to the CHIP queue to deliver the data into the CHIP stack.
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
event.CHIPoBLEWriteReceived.ConId = handle;
event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease();
err = PlatformMgr().PostEvent(&event);
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
}
}
void BLEManagerImpl::HandleTXCharCCCDWrite(uint16_t handle, void * data, uint16_t size)
{
CHIP_ERROR err = CHIP_NO_ERROR;
app_bt_connection_cb_t * bleConnState;
bool isDisabled;
ChipDeviceEvent event;
bleConnState = find_connection_info_by_handle(handle);
VerifyOrExit(bleConnState != NULL, err = CHIP_ERROR_NO_MEMORY);
VerifyOrExit(size == sizeof(uint16_t), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
// Determine if the client is enabling or disabling notification/indication.
isDisabled = (*(uint16_t *) data != 0x0002);
ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", *(uint16_t *) data);
ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", isDisabled ? "unsubscribe" : "subscribe");
if (!isDisabled)
{
// If indications are not already enabled for the connection...
if (!bleConnState->subscribed)
{
bleConnState->subscribed = 1;
// 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.
{
event.Type = DeviceEventType::kCHIPoBLESubscribe;
event.CHIPoBLESubscribe.ConId = handle;
err = PlatformMgr().PostEvent(&event);
}
}
}
else
{
bleConnState->subscribed = 0;
event.Type = DeviceEventType::kCHIPoBLEUnsubscribe;
event.CHIPoBLESubscribe.ConId = handle;
err = PlatformMgr().PostEvent(&event);
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err));
}
}
CHIP_ERROR BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle pBuf)
{
ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
// Nothing to do
}
void BLEManagerImpl::HandleTxConfirmationEvent(BLE_CONNECTION_OBJECT conId)
{
ChipDeviceEvent event;
ChipLogProgress(DeviceLayer, "Tx Confirmation received!!!");
event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
event.CHIPoBLEIndicateConfirm.ConId = conId;
PlatformMgr().PostEventOrDie(&event);
}
CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr)
{
switch (bleErr)
{
case BT_STATUS_SUCCESS:
return CHIP_NO_ERROR;
default:
return CHIP_ERROR(ChipError::Range::kPlatform, bleErr + CHIP_DEVICE_CONFIG_BLE_ERROR_MIN);
}
}
CHIP_ERROR BLEManagerImpl::StartAdvertising(void)
{
bt_hci_cmd_le_set_advertising_enable_t enable;
uint32_t deviceNameLength = 0;
ChipBLEDeviceIdentificationInfo deviceIdInfo;
uint8_t deviceIdInfoLength = sizeof(deviceIdInfo);
CHIP_ERROR err = CHIP_NO_ERROR;
int adv_name_len;
uint32_t index = 0;
bt_status_t ret;
bt_hci_cmd_le_set_advertising_parameters_t adv_param = { .advertising_interval_min =
CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN,
.advertising_interval_max =
CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX,
.advertising_type = BT_HCI_ADV_TYPE_CONNECTABLE_UNDIRECTED,
.own_address_type = BT_ADDR_PUBLIC,
.advertising_channel_map = 7,
.advertising_filter_policy = 0 };
bt_hci_cmd_le_set_advertising_data_t adv_data = {
.advertising_data_length = MAX_ADV_DATA_LEN,
};
if (mFlags.Has(Flags::kRestartAdvertising))
{
ChipLogProgress(DeviceLayer, "Stop advertising..");
enable.advertising_enable = BT_HCI_DISABLE;
ret = bt_gap_le_set_advertising(&enable, NULL, NULL, NULL);
if (BT_STATUS_SUCCESS == ret)
{
xEventGroupWaitBits(xBleEventGroup, EG_EVENT_BLE_ADV_CNF, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));
ChipLogProgress(DeviceLayer, "Advertising stopped.");
}
mFlags.Clear(Flags::kRestartAdvertising);
}
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
{
adv_param.advertising_interval_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN;
adv_param.advertising_interval_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX;
}
if (!mFlags.Has(Flags::kDeviceNameSet))
{
uint16_t discriminator = 0;
err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator);
snprintf(gatts_device_name, sizeof(gatts_device_name), "%s%04" PRIX32, CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX,
static_cast<uint32_t>(discriminator));
gatts_device_name[kMaxDeviceNameLength] = 0;
}
deviceNameLength = strlen(gatts_device_name);
VerifyOrExit(deviceNameLength < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT);
deviceNameLength =
deviceNameLength > MAX_ADV_DATA_LEN - BLE_ADV_OTHER_LEN - 1 ? MAX_ADV_DATA_LEN - BLE_ADV_OTHER_LEN - 1 : deviceNameLength;
ChipLogProgress(DeviceLayer, "Beginning advertising, interval(min,max)=(%d, %d), devName=%s, len=%lu",
adv_param.advertising_interval_min, adv_param.advertising_interval_max, gatts_device_name, deviceNameLength);
err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo);
SuccessOrExit(err);
static_assert(sizeof(deviceIdInfo) + CHIP_ADV_SHORT_UUID_LEN + 1 <= UINT8_MAX, "Our length won't fit in a uint8_t");
static_assert(2 + CHIP_ADV_SHORT_UUID_LEN + sizeof(deviceIdInfo) + 1 <= MAX_ADV_DATA_LEN, "Our buffer is not big enough");
adv_data.advertising_data[index++] = 0x02; // AD length
adv_data.advertising_data[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags
adv_data.advertising_data[index++] = CHIP_ADV_DATA_FLAGS; // AD value
adv_data.advertising_data[index++] = static_cast<uint8_t>(deviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1); // AD length
adv_data.advertising_data[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type : Service Data
adv_data.advertising_data[index++] = ShortUUID_CHIPoBLEService[0]; // AD value
adv_data.advertising_data[index++] = ShortUUID_CHIPoBLEService[1];
memcpy(&adv_data.advertising_data[index], (void *) &deviceIdInfo, deviceIdInfoLength); // AD value
index += deviceIdInfoLength;
adv_data.advertising_data[index++] = static_cast<uint8_t>(deviceNameLength + 1); // AD length
adv_data.advertising_data[index++] = CHIP_ADV_DATA_TYPE_NAME; // AD type : name
memcpy(&adv_data.advertising_data[index], gatts_device_name, deviceNameLength); // AD value
index += deviceNameLength;
enable.advertising_enable = BT_HCI_ENABLE;
ret = bt_gap_le_set_advertising(&enable, &adv_param, &adv_data, NULL);
err = MapBLEError(ret);
SuccessOrExit(err);
if ((xEventGroupWaitBits(xBleEventGroup, EG_EVENT_BLE_ADV_CNF, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000)) & EG_EVENT_BLE_ADV_CNF) ==
EG_EVENT_BLE_ADV_CNF)
{
ChipLogProgress(DeviceLayer, "Advertising started.");
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
{
StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
}
mFlags.Set(Flags::kAdvertising);
}
else
{
err = CHIP_ERROR_TIMEOUT;
}
exit:
return err;
}
CHIP_ERROR BLEManagerImpl::StopAdvertising(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
bt_status_t ret;
if (mFlags.Has(Flags::kAdvertising))
{
mFlags.Clear(Flags::kAdvertising).Clear(Flags::kRestartAdvertising);
mFlags.Set(Flags::kFastAdvertisingEnabled, true);
ChipLogProgress(DeviceLayer, "Stop advertising..");
bt_hci_cmd_le_set_advertising_enable_t enable = { BT_HCI_DISABLE };
ret = bt_gap_le_set_advertising(&enable, NULL, NULL, NULL);
err = MapBLEError(ret);
SuccessOrExit(err);
if ((xEventGroupWaitBits(xBleEventGroup, EG_EVENT_BLE_ADV_CNF, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000)) &
EG_EVENT_BLE_ADV_CNF) != EG_EVENT_BLE_ADV_CNF)
{
err = CHIP_ERROR_TIMEOUT;
}
SuccessOrExit(err);
ChipLogProgress(DeviceLayer, "Advertising stopped.");
CancelBleAdvTimeoutTimer();
}
exit:
return err;
}
void BLEManagerImpl::BleAdvTimeoutHandler(TimerHandle_t xTimer)
{
if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled))
{
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement");
BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
}
else if (BLEMgrImpl().mFlags.Has(Flags::kAdvertising))
{
// Advertisement time expired. Stop advertising
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Stop advertisement");
BLEMgr().SetAdvertisingEnabled(false);
}
}
void BLEManagerImpl::CancelBleAdvTimeoutTimer(void)
{
if (xTimerStop(sbleAdvTimeoutTimer, 0) == pdFAIL)
{
ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer");
}
}
void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs)
{
if (xTimerIsTimerActive(sbleAdvTimeoutTimer))
{
CancelBleAdvTimeoutTimer();
}
// timer is not active, change its period to required value (== restart).
// FreeRTOS- Block for a maximum of 100 ticks if the change period command
// cannot immediately be sent to the timer command queue.
if (xTimerChangePeriod(sbleAdvTimeoutTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS)
{
ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer");
}
}
bt_status_t BLEManagerImpl::BleMatterAppEventCallback(bt_msg_type_t msg, bt_status_t status, void * buff)
{
ChipLogProgress(DeviceLayer, "BleMatterAppEventCallback: msg %08x, status %08x", (unsigned int) msg, (unsigned int) status);
// PlatformMgr().LockChipStack();
switch (msg)
{
case BT_POWER_ON_CNF:
if (BT_STATUS_SUCCESS != bt_gatts_set_max_mtu(247))
{
ChipLogError(DeviceLayer, "Unable to set BT GATTS maximum mtu size!");
}
sInstance.mFlags.Set(Flags::kBLEStackInitialized);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
break;
case BT_GAP_LE_SET_ADVERTISING_CNF:
ChipLogProgress(DeviceLayer, "BT_GAP_LE_SET_ADVERTISING_CNF: Raise EG_EVENT_BLE_ADV_CNF");
xEventGroupSetBits(xBleEventGroup, EG_EVENT_BLE_ADV_CNF);
break;
case BT_GAP_LE_CONNECT_IND:
PlatformMgr().ScheduleWork(DriveBLEState, 0);
break;
case BT_GAP_LE_DISCONNECT_IND: {
bt_hci_evt_disconnect_complete_t * conn_evt = (bt_hci_evt_disconnect_complete_t *) buff;
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEConnectionError;
event.CHIPoBLEConnectionError.ConId = conn_evt->connection_handle;
switch (conn_evt->reason)
{
case BT_HCI_STATUS_REMOTE_USER_TERMINATED_CONNECTION:
case BT_HCI_STATUS_REMOTE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES:
case BT_HCI_STATUS_REMOTE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF:
event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
break;
case BT_HCI_STATUS_CONNECTION_TERMINATED_BY_LOCAL_HOST:
event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION;
break;
default:
event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
break;
}
ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %u)", conn_evt->connection_handle,
conn_evt->reason);
PlatformMgr().PostEventOrDie(&event);
// Arrange to re-enable connectable advertising in case it was disabled due to the
// maximum connection limit being reached.
sInstance.mFlags.Set(Flags::kRestartAdvertising);
sInstance.mFlags.Set(Flags::kFastAdvertisingEnabled);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
break;
case BT_GATTC_CHARC_VALUE_CONFIRMATION: {
bt_handle_t * connection_handle_p = (bt_handle_t *) buff;
ChipDeviceEvent event;
ChipLogProgress(DeviceLayer, "Tx Confirmation received");
event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
event.CHIPoBLEIndicateConfirm.ConId = *connection_handle_p;
PlatformMgr().PostEventOrDie(&event);
}
break;
default:
break;
}
// PlatformMgr().UnlockChipStack();
return BT_STATUS_SUCCESS;
}
void BLEManagerImpl::DriveBLEState(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
// Check if BLE stack is initialized
VerifyOrExit(mFlags.Has(Flags::kBLEStackInitialized), /* */);
// Start advertising if needed...
if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled) &&
NumConnections() < kMaxConnections)
{
// Start/re-start advertising if not already started, or if there is a pending change
// to the advertising configuration.
if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kRestartAdvertising))
{
err = StartAdvertising();
SuccessOrExit(err);
}
}
// Otherwise, stop advertising if it is enabled.
else if (mFlags.Has(Flags::kAdvertising))
{
err = StopAdvertising();
SuccessOrExit(err);
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
}
}
void BLEManagerImpl::DriveBLEState(intptr_t arg)
{
sInstance.DriveBLEState();
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE