blob: 4c9048a3f68192abdac02ff4e5f52d190f3d22c5 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2020 Nest Labs, Inc.
* All rights reserved.
*
* 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 K32W platforms.
*/
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/CommissionableDataProvider.h>
#include <crypto/CHIPCryptoPAL.h>
#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
#include <ble/Ble.h>
#include "board.h"
#include "gatt_db_app_interface.h"
#include "gatt_db_handles.h"
#include "stdio.h"
#include "timers.h"
#if defined(CPU_JN518X) && defined(chip_with_low_power) && (chip_with_low_power == 1)
#include "PWR_Configuration.h"
#endif
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
#include <platform/DeviceInstanceInfoProvider.h>
#include <setup_payload/AdditionalDataPayloadGenerator.h>
#endif
/*******************************************************************************
* Local data types
*******************************************************************************/
extern "C" bool_t Ble_ConfigureHostStackConfig(void);
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
extern "C" void PWR_DisallowDeviceToSleep(void);
extern "C" void PWR_AllowDeviceToSleep(void);
#endif
using namespace ::chip;
using namespace ::chip::Ble;
namespace chip {
namespace DeviceLayer {
namespace Internal {
namespace {
/*******************************************************************************
* Macros & Constants definitions
*******************************************************************************/
/* Timeout of BLE commands */
#define CHIP_BLE_KW_EVNT_TIMEOUT 1000 / portTICK_PERIOD_MS
/** BLE advertisement state changed */
#define CHIP_BLE_KW_EVNT_ADV_CHANGED 0x0001
/** BLE advertisement command failed */
#define CHIP_BLE_KW_EVNT_ADV_FAILED 0x0002
/** BLE advertisement setup failed */
#define CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED 0x0004
/** BLE advertisement parameters setup complete */
#define CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE 0x0008
/** BLE advertisement data setup complete */
#define CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE 0x0010
/** BLE random address set */
#define CHIP_BLE_KW_EVNT_RND_ADDR_SET 0x0020
/** BLE Initialization complete */
#define CHIP_BLE_KW_EVNT_INIT_COMPLETE 0x0040
/** BLE Received a handle value confirmation from the client */
#define CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED 0x0080
/** BLE send indication failed */
#define CHIP_BLE_KW_EVNT_INDICATION_FAILED 0x0100
/** TX Power Level Set */
#define CHIP_BLE_KW_EVNT_POWER_LEVEL_SET 0x0200
/** Maximal time of connection without activity */
#define CHIP_BLE_KW_CONN_TIMEOUT 60000
/** Maximum number of pending BLE events */
#define CHIP_BLE_EVENT_QUEUE_MAX_ENTRIES 10
#define LOOP_EV_BLE (0x08)
/* controller task configuration */
#define CONTROLLER_TASK_PRIORITY (6U)
#define CONTROLLER_TASK_STACK_SIZE (gControllerTaskStackSize_c / sizeof(StackType_t))
/* host task configuration */
#define HOST_TASK_PRIORITY (4U)
#define HOST_TASK_STACK_SIZE (gHost_TaskStackSize_c / sizeof(StackType_t))
/* advertising configuration */
#define BLEKW_ADV_MAX_NO (2)
#define BLEKW_SCAN_RSP_MAX_NO (2)
#define BLEKW_MAX_ADV_DATA_LEN (31)
#define CHIP_ADV_SHORT_UUID_LEN (2)
/* FreeRTOS sw timer */
TimerHandle_t sbleAdvTimeoutTimer;
/* Queue used to synchronize asynchronous messages from the KW BLE tasks */
QueueHandle_t sBleEventQueue;
/* Used to manage asynchronous events from BLE Stack: e.g.: GAP setup finished */
EventGroupHandle_t sEventGroup;
TimerHandle_t connectionTimeout;
const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF };
const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
0x9D, 0x11 } };
const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
0x9D, 0x12 } };
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
static bool bleAppStopInProgress;
#endif
BLEManagerCommon * sImplInstance = nullptr;
} // namespace
CHIP_ERROR BLEManagerCommon::_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
EventBits_t eventBits;
uint16_t attChipRxHandle[1] = { (uint16_t) value_chipoble_rx };
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
uint16_t attChipC3Handle[1] = { (uint16_t) value_chipoble_c3 };
#endif
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
// Check if BLE stack is initialized
VerifyOrExit(!mFlags.Has(Flags::kK32WBLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE);
// Initialize the Chip BleLayer.
err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer());
SuccessOrExit(err);
/* Initialization of message wait events -
* used for receiving BLE Stack events */
sEventGroup = xEventGroupCreate();
VerifyOrExit(sEventGroup != NULL, err = CHIP_ERROR_INCORRECT_STATE);
/* Prepare callback input queue.*/
sBleEventQueue = xQueueCreate(CHIP_BLE_EVENT_QUEUE_MAX_ENTRIES, sizeof(blekw_msg_t *));
VerifyOrExit(sBleEventQueue != NULL, err = CHIP_ERROR_INCORRECT_STATE);
/* Create the connection timeout timer. */
connectionTimeout =
xTimerCreate("bleTimeoutTmr", pdMS_TO_TICKS(CHIP_BLE_KW_CONN_TIMEOUT), pdFALSE, (void *) 0, blekw_connection_timeout_cb);
VerifyOrExit(connectionTimeout != NULL, err = CHIP_ERROR_INCORRECT_STATE);
sImplInstance = GetImplInstance();
/* BLE platform code initialization */
SuccessOrExit(err = InitHostController(&blekw_generic_cb));
/* Register the GATT server callback */
VerifyOrExit(GattServer_RegisterCallback(blekw_gatt_server_cb) == gBleSuccess_c, err = CHIP_ERROR_INCORRECT_STATE);
/* Wait until BLE Stack is ready */
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_INIT_COMPLETE, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT);
VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_INIT_COMPLETE, err = CHIP_ERROR_INCORRECT_STATE);
#if BLE_HIGH_TX_POWER
/* Set Adv Power */
Gap_SetTxPowerLevel(gAdvertisingPowerLeveldBm_c, gTxPowerAdvChannel_c);
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT);
VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE);
/* Set Connect Power */
Gap_SetTxPowerLevel(gConnectPowerLeveldBm_c, gTxPowerConnChannel_c);
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT);
VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE);
#endif
#if defined(CPU_JN518X) && defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_ChangeDeepSleepMode(cPWR_PowerDown_RamRet);
#endif
GattServer_RegisterHandlesForWriteNotifications(1, attChipRxHandle);
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
VerifyOrExit(GattServer_RegisterHandlesForReadNotifications(1, attChipC3Handle) == gBleSuccess_c,
err = CHIP_ERROR_INCORRECT_STATE);
#endif
mFlags.Set(Flags::kK32WBLEStackInitialized);
mFlags.Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? true : false);
mFlags.Set(Flags::kFastAdvertisingEnabled);
// Create FreeRTOS sw timer for BLE timeouts and interval change.
sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel
pdMS_TO_TICKS(100), // == default timer period (mS)
false, // no timer reload (==one-shot)
(void *) this, // init timer id = ble obj context
BleAdvTimeoutHandler // timer callback handler
);
VerifyOrExit(sbleAdvTimeoutTimer != NULL, err = CHIP_ERROR_INCORRECT_STATE);
exit:
return err;
}
uint16_t BLEManagerCommon::_NumConnections(void)
{
return static_cast<uint16_t>(mDeviceConnected == true);
}
bool BLEManagerCommon::_IsAdvertisingEnabled(void)
{
return mFlags.Has(Flags::kAdvertisingEnabled);
}
bool BLEManagerCommon::_IsAdvertising(void)
{
return mFlags.Has(Flags::kAdvertising);
}
CHIP_ERROR BLEManagerCommon::_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 BLEManagerCommon::_SetAdvertisingMode(BLEAdvertisingMode mode)
{
switch (mode)
{
case BLEAdvertisingMode::kFastAdvertising:
mFlags.Set(Flags::kFastAdvertisingEnabled);
break;
case BLEAdvertisingMode::kSlowAdvertising: {
// We are in FreeRTOS timer service context, which is a default daemon task and has
// the highest priority. Stop advertising should be scheduled to run from Matter task.
mFlags.Clear(Flags::kFastAdvertisingEnabled);
PlatformMgr().ScheduleWork(StopAdvertisingPriorToSwitchingMode, 0);
break;
}
default:
return CHIP_ERROR_INVALID_ARGUMENT;
}
mFlags.Set(Flags::kRestartAdvertising);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
return CHIP_NO_ERROR;
}
CHIP_ERROR BLEManagerCommon::_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 BLEManagerCommon::_SetDeviceName(const char * deviceName)
{
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;
}
memset(mDeviceName, 0, kMaxDeviceNameLength);
strcpy(mDeviceName, deviceName);
mFlags.Set(Flags::kDeviceNameSet);
ChipLogProgress(DeviceLayer, "Setting device name to : \"%s\"", deviceName);
}
else
{
mDeviceName[0] = 0;
mFlags.Clear(Flags::kDeviceNameSet);
}
return CHIP_NO_ERROR;
}
void BLEManagerCommon::_OnPlatformEvent(const ChipDeviceEvent * event)
{
switch (event->Type)
{
case DeviceEventType::kCHIPoBLESubscribe:
ChipDeviceEvent connEstEvent;
HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
PlatformMgr().PostEventOrDie(&connEstEvent);
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::kCHIPoBLEConnectionError:
HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
break;
case DeviceEventType::kCHIPoBLEIndicateConfirm:
HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
break;
default:
break;
}
}
bool BLEManagerCommon::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
ChipLogProgress(DeviceLayer, "BLEManagerCommon::SubscribeCharacteristic() not supported");
return false;
}
bool BLEManagerCommon::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
ChipLogProgress(DeviceLayer, "BLEManagerCommon::UnsubscribeCharacteristic() not supported");
return false;
}
bool BLEManagerCommon::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
return blekw_stop_connection_internal(conId);
}
uint16_t BLEManagerCommon::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
uint16_t tempMtu = 0;
(void) Gatt_GetMtu(conId, &tempMtu);
return tempMtu;
}
bool BLEManagerCommon::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle pBuf)
{
ChipLogProgress(DeviceLayer, "BLEManagerCommon::SendWriteRequest() not supported");
return false;
}
bool BLEManagerCommon::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle pBuf)
{
ChipLogProgress(DeviceLayer, "BLEManagerCommon::SendReadRequest() not supported");
return false;
}
bool BLEManagerCommon::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
ChipLogProgress(DeviceLayer, "BLEManagerCommon::SendReadResponse() not supported");
return false;
}
void BLEManagerCommon::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
BLEMgrImpl().CloseConnection(conId);
}
bool BLEManagerCommon::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle data)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint16_t cId = (UUIDsMatch(&ChipUUID_CHIPoBLEChar_TX, charId) ? value_chipoble_tx : 0);
ChipDeviceEvent event;
if (cId != 0)
{
if (blekw_send_event(conId, cId, data->Start(), data->DataLength()) != BLE_OK)
{
err = CHIP_ERROR_SENDING_BLOCKED;
}
else
{
event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
event.CHIPoBLEIndicateConfirm.ConId = conId;
err = PlatformMgr().PostEvent(&event);
}
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "BLEManagerCommon::SendIndication() failed: %s", ErrorStr(err));
return false;
}
return true;
}
return false;
}
BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_send_event(int8_t connection_handle, uint16_t handle, uint8_t * data,
uint32_t len)
{
EventBits_t eventBits;
#if CHIP_DEVICE_CHIP0BLE_DEBUG
ChipLogProgress(DeviceLayer, "Trying to send event.");
#endif
if (connection_handle < 0 || handle <= 0)
{
ChipLogProgress(DeviceLayer, "BLE Event - Bad Handle");
return BLE_E_FAIL;
}
if (len > 0 && data == NULL)
{
ChipLogProgress(DeviceLayer, "BLE Event - Invalid Data");
return BLE_E_FAIL;
}
/************* Send the indication *************/
xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED | CHIP_BLE_KW_EVNT_INDICATION_FAILED);
if (GattServer_SendInstantValueIndication(connection_handle, handle, len, data) != gBleSuccess_c)
{
ChipLogProgress(DeviceLayer, "BLE Event - Can't sent indication");
return BLE_E_FAIL;
}
/* Wait until BLE Stack is ready */
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED | CHIP_BLE_KW_EVNT_INDICATION_FAILED, pdTRUE,
pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT);
if (eventBits & CHIP_BLE_KW_EVNT_INDICATION_FAILED)
{
ChipLogProgress(DeviceLayer, "BLE Event - Sent Failed");
return BLE_E_FAIL;
}
#if CHIP_DEVICE_CHIP0BLE_DEBUG
ChipLogProgress(DeviceLayer, "BLE Event - Sent :-) ");
#endif
return BLE_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_start_advertising(gapAdvertisingParameters_t * adv_params,
gapAdvertisingData_t * adv, gapScanResponseData_t * scnrsp)
{
EventBits_t eventBits;
/************* Set the advertising parameters *************/
xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE);
/* Set the advertising parameters */
if (Gap_SetAdvertisingParameters(adv_params) != gBleSuccess_c)
{
vTaskDelay(1);
/* Retry, just to make sure before giving up and sending an error. */
if (Gap_SetAdvertisingParameters(adv_params) != gBleSuccess_c)
{
return BLE_E_SET_ADV_PARAMS;
}
}
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE,
pdTRUE, pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT);
if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE))
{
return BLE_E_ADV_PARAMS_FAILED;
}
/************* Set the advertising data *************/
xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE);
/* Set the advertising data */
if (Gap_SetAdvertisingData(adv, scnrsp) != gBleSuccess_c)
{
return BLE_E_SET_ADV_DATA;
}
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE,
pdTRUE, pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT);
if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE))
{
return BLE_E_ADV_SETUP_FAILED;
}
/************* Start the advertising *************/
xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED);
if (gBleSuccess_c != Gap_CreateRandomDeviceAddress(NULL, NULL))
{
return BLE_E_SET_ADV_PARAMS;
}
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_RND_ADDR_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT);
if (!(eventBits & CHIP_BLE_KW_EVNT_RND_ADDR_SET))
{
return BLE_E_ADV_PARAMS_FAILED;
}
/* Start the advertising */
if (Gap_StartAdvertising(blekw_gap_advertising_cb, blekw_gap_connection_cb) != gBleSuccess_c)
{
return BLE_E_START_ADV;
}
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_DisallowDeviceToSleep();
#endif
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED, pdTRUE, pdFALSE,
CHIP_BLE_KW_EVNT_TIMEOUT);
if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_CHANGED))
{
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_AllowDeviceToSleep();
#endif
return BLE_E_START_ADV_FAILED;
}
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_AllowDeviceToSleep();
#endif
return BLE_OK;
}
BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_stop_advertising(void)
{
EventBits_t eventBits;
bleResult_t res;
xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED);
/* Stop the advertising data */
res = Gap_StopAdvertising();
if (res != gBleSuccess_c)
{
ChipLogProgress(DeviceLayer, "Failed to stop advertising %d", res);
return BLE_E_STOP;
}
eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED, pdTRUE, pdFALSE,
CHIP_BLE_KW_EVNT_TIMEOUT);
if (eventBits & CHIP_BLE_KW_EVNT_ADV_FAILED)
{
ChipLogProgress(DeviceLayer, "Stop advertising flat out failed.");
return BLE_E_ADV_FAILED;
}
else if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_CHANGED))
{
ChipLogProgress(DeviceLayer, "Stop advertising event timeout.");
return BLE_E_ADV_CHANGED;
}
return BLE_OK;
}
CHIP_ERROR BLEManagerCommon::ConfigureAdvertisingData(void)
{
ble_err_t err;
CHIP_ERROR chipErr;
uint16_t discriminator;
uint16_t advInterval = 0;
gapAdvertisingData_t adv = { 0 };
gapAdStructure_t adv_data[BLEKW_ADV_MAX_NO] = { { 0 } };
gapAdStructure_t scan_rsp_data[BLEKW_SCAN_RSP_MAX_NO] = { { 0 } };
uint8_t advPayload[BLEKW_MAX_ADV_DATA_LEN] = { 0 };
gapScanResponseData_t scanRsp = { 0 };
gapAdvertisingParameters_t adv_params = { 0 };
uint8_t chipAdvDataFlags = (gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c);
uint8_t chipOverBleService[2];
ChipBLEDeviceIdentificationInfo mDeviceIdInfo = { 0 };
uint8_t mDeviceIdInfoLength = 0;
chipErr = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator);
if (chipErr != CHIP_NO_ERROR)
{
return chipErr;
}
if (!mFlags.Has(Flags::kDeviceNameSet))
{
memset(mDeviceName, 0, kMaxDeviceNameLength);
snprintf(mDeviceName, kMaxDeviceNameLength, "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator);
}
/**************** Prepare advertising data *******************************************/
adv.cNumAdStructures = BLEKW_ADV_MAX_NO;
chipErr = ConfigurationMgr().GetBLEDeviceIdentificationInfo(mDeviceIdInfo);
SuccessOrExit(chipErr);
mDeviceIdInfoLength = sizeof(mDeviceIdInfo);
if ((mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1) > BLEKW_MAX_ADV_DATA_LEN)
{
return CHIP_ERROR_INCORRECT_STATE;
}
adv_data[0].length = 0x02;
adv_data[0].adType = gAdFlags_c;
adv_data[0].aData = (uint8_t *) (&chipAdvDataFlags);
adv_data[1].length = static_cast<uint8_t>(mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1);
adv_data[1].adType = gAdServiceData16bit_c;
memcpy(advPayload, ShortUUID_CHIPoBLEService, CHIP_ADV_SHORT_UUID_LEN);
memcpy(&advPayload[CHIP_ADV_SHORT_UUID_LEN], (void *) &mDeviceIdInfo, mDeviceIdInfoLength);
adv_data[1].aData = advPayload;
adv.aAdStructures = adv_data;
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
ReturnErrorOnFailure(EncodeAdditionalDataTlv());
#endif
/**************** Prepare scan response data *******************************************/
scanRsp.cNumAdStructures = BLEKW_SCAN_RSP_MAX_NO;
scan_rsp_data[0].length = static_cast<uint8_t>(strlen(mDeviceName) + 1);
scan_rsp_data[0].adType = gAdCompleteLocalName_c;
scan_rsp_data[0].aData = (uint8_t *) mDeviceName;
scan_rsp_data[1].length = sizeof(chipOverBleService) + 1;
scan_rsp_data[1].adType = gAdComplete16bitServiceList_c;
chipOverBleService[0] = ShortUUID_CHIPoBLEService[0];
chipOverBleService[1] = ShortUUID_CHIPoBLEService[1];
scan_rsp_data[1].aData = (uint8_t *) chipOverBleService;
scanRsp.aAdStructures = scan_rsp_data;
/**************** Prepare advertising parameters *************************************/
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
{
advInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX;
}
else
{
advInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX;
}
advInterval = (uint16_t) (advInterval * 0.625F);
adv_params.minInterval = adv_params.maxInterval = advInterval;
adv_params.advertisingType = gAdvConnectableUndirected_c;
adv_params.ownAddressType = gBleAddrTypeRandom_c;
adv_params.peerAddressType = gBleAddrTypePublic_c;
memset(adv_params.peerAddress, 0, gcBleDeviceAddressSize_c);
adv_params.channelMap = (gapAdvertisingChannelMapFlags_t) (gAdvChanMapFlag37_c | gAdvChanMapFlag38_c | gAdvChanMapFlag39_c);
adv_params.filterPolicy = gProcessAll_c;
err = blekw_start_advertising(&adv_params, &adv, &scanRsp);
if (err == BLE_OK)
{
ChipLogProgress(DeviceLayer, "Started Advertising at %d ms", advInterval);
}
else
{
ChipLogProgress(DeviceLayer, "Advertising error 0x%x!", err);
mFlags.Clear(Flags::kAdvertising);
return CHIP_ERROR_INCORRECT_STATE;
}
exit:
return chipErr;
}
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
CHIP_ERROR BLEManagerCommon::EncodeAdditionalDataTlv()
{
CHIP_ERROR err = CHIP_NO_ERROR;
BitFlags<AdditionalDataFields> dataFields;
AdditionalDataPayloadGeneratorParams params;
#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID)
uint8_t rotatingDeviceIdUniqueId[ConfigurationManager::kRotatingDeviceIDUniqueIDLength] = {};
MutableByteSpan rotatingDeviceIdUniqueIdSpan(rotatingDeviceIdUniqueId);
err = DeviceLayer::GetDeviceInstanceInfoProvider()->GetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdSpan);
SuccessOrExit(err);
err = ConfigurationMgr().GetLifetimeCounter(params.rotatingDeviceIdLifetimeCounter);
SuccessOrExit(err);
params.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan;
dataFields.Set(AdditionalDataFields::RotatingDeviceId);
#endif /* CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */
err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(params, sImplInstance->c3AdditionalDataBufferHandle,
dataFields);
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data (%s)", __func__);
}
return err;
}
void BLEManagerCommon::HandleC3ReadRequest(blekw_msg_t * msg)
{
bleResult_t result;
blekw_att_read_data_t * att_rd_data = (blekw_att_read_data_t *) msg->data.data;
deviceId_t deviceId = att_rd_data->device_id;
uint16_t handle = att_rd_data->handle;
uint16_t length = sImplInstance->c3AdditionalDataBufferHandle->DataLength();
const uint8_t * data = (const uint8_t *) sImplInstance->c3AdditionalDataBufferHandle->Start();
result = GattDb_WriteAttribute(handle, length, data);
if (result != gBleSuccess_c)
{
ChipLogError(DeviceLayer, "Failed to write C3 characteristic: %d", result);
}
result = GattServer_SendAttributeReadStatus(deviceId, handle, gAttErrCodeNoError_c);
if (result != gBleSuccess_c)
{
ChipLogError(DeviceLayer, "Failed to send response to C3 read request: %d", result);
}
}
#endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */
CHIP_ERROR BLEManagerCommon::StartAdvertising(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
mFlags.Set(Flags::kAdvertising);
mFlags.Clear(Flags::kRestartAdvertising);
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
{
StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT);
}
err = ConfigureAdvertisingData();
if (err == CHIP_NO_ERROR)
/* schedule NFC emulation stop */
{
ChipDeviceEvent advChange;
advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started;
err = PlatformMgr().PostEvent(&advChange);
}
return err;
}
CHIP_ERROR BLEManagerCommon::StopAdvertising(void)
{
CHIP_ERROR error = CHIP_NO_ERROR;
if (mFlags.Has(Flags::kAdvertising))
{
mFlags.Clear(Flags::kAdvertising);
mFlags.Clear(Flags::kRestartAdvertising);
if (!mDeviceConnected)
{
ble_err_t err = blekw_stop_advertising();
VerifyOrReturnError(err == BLE_OK, CHIP_ERROR_INCORRECT_STATE);
CancelBleAdvTimeoutTimer();
}
#if CONFIG_CHIP_NFC_COMMISSIONING
/* schedule NFC emulation stop */
ChipDeviceEvent advChange;
advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange;
advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped;
error = PlatformMgr().PostEvent(&advChange);
#endif
}
return error;
}
void BLEManagerCommon::DriveBLEState(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
// Check if BLE stack is initialized
VerifyOrExit(mFlags.Has(Flags::kK32WBLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE);
// Start advertising if needed...
if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled))
{
// 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);
// Reset to fast advertising mode only if SetBLEAdvertisingEnabled(false) was called (usually from app).
mFlags.Set(Flags::kFastAdvertisingEnabled);
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
}
}
void BLEManagerCommon::DriveBLEState(intptr_t arg)
{
sImplInstance->DriveBLEState();
}
void BLEManagerCommon::StopAdvertisingPriorToSwitchingMode(intptr_t arg)
{
if (CHIP_NO_ERROR != sImplInstance->StopAdvertising())
{
ChipLogProgress(DeviceLayer, "Failed to stop advertising");
}
}
void BLEManagerCommon::DoBleProcessing(void)
{
blekw_msg_t * msg = NULL;
while ((xQueueReceive(sBleEventQueue, &msg, 0) == pdTRUE) && msg)
{
if (msg->type == BLE_KW_MSG_ERROR)
{
if (msg->data.u8 == BLE_KW_MSG_2M_UPGRADE_ERROR)
{
ChipLogProgress(DeviceLayer,
"Warning. BLE is using 1Mbps. Couldn't upgrade to 2Mbps, "
"maybe the peer is missing 2Mbps support.");
}
else
{
ChipLogProgress(DeviceLayer, "BLE Error: %d.\n", msg->data.u8);
}
}
else if (msg->type == BLE_KW_MSG_CONNECTED)
{
sImplInstance->HandleConnectEvent(msg);
}
else if (msg->type == BLE_KW_MSG_DISCONNECTED)
{
sImplInstance->HandleConnectionCloseEvent(msg);
}
else if (msg->type == BLE_KW_MSG_MTU_CHANGED)
{
blekw_start_connection_timeout();
ChipLogProgress(DeviceLayer, "BLE MTU size has been changed to %d.", msg->data.u16);
}
else if (msg->type == BLE_KW_MSG_ATT_WRITTEN || msg->type == BLE_KW_MSG_ATT_LONG_WRITTEN ||
msg->type == BLE_KW_MSG_ATT_CCCD_WRITTEN)
{
sImplInstance->HandleWriteEvent(msg);
}
else if (msg->type == BLE_KW_MSG_ATT_READ)
{
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
blekw_att_read_data_t * att_rd_data = (blekw_att_read_data_t *) msg->data.data;
if (value_chipoble_c3 == att_rd_data->handle)
sImplInstance->HandleC3ReadRequest(msg);
#endif
}
else if (msg->type == BLE_KW_MSG_FORCE_DISCONNECT)
{
sImplInstance->HandleForceDisconnect();
}
/* Free the message from the queue */
free(msg);
msg = NULL;
}
}
void BLEManagerCommon::RegisterAppCallbacks(BLECallbackDelegate::GapGenericCallback gapCallback,
BLECallbackDelegate::GattServerCallback gattCallback)
{
callbackDelegate.gapCallback = gapCallback;
callbackDelegate.gattCallback = gattCallback;
}
void BLEManagerCommon::HandleConnectEvent(blekw_msg_t * msg)
{
uint8_t deviceId = msg->data.u8;
ChipLogProgress(DeviceLayer, "BLE is connected with device: %d.\n", deviceId);
#if gClkUseFro32K && defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_DisallowDeviceToSleep();
#endif
mDeviceId = deviceId;
mDeviceConnected = true;
blekw_start_connection_timeout();
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
void BLEManagerCommon::HandleConnectionCloseEvent(blekw_msg_t * msg)
{
uint8_t deviceId = msg->data.u8;
ChipLogProgress(DeviceLayer, "BLE is disconnected with device: %d.\n", deviceId);
#if gClkUseFro32K && defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_AllowDeviceToSleep();
#endif
mDeviceConnected = false;
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEConnectionClosed;
event.CHIPoBLEConnectionError.ConId = deviceId;
event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
CancelBleAdvTimeoutTimer();
PlatformMgr().PostEventOrDie(&event);
mFlags.Set(Flags::kRestartAdvertising);
mFlags.Set(Flags::kFastAdvertisingEnabled);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
void BLEManagerCommon::HandleWriteEvent(blekw_msg_t * msg)
{
blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data;
attErrorCode_t status = gAttErrCodeNoError_c;
#if CHIP_DEVICE_CHIP0BLE_DEBUG
ChipLogProgress(DeviceLayer, "Attribute write request(device: %d,handle: %d).", att_wr_data->device_id, att_wr_data->handle);
#endif
blekw_start_connection_timeout();
if (value_chipoble_rx == att_wr_data->handle)
{
sImplInstance->HandleRXCharWrite(msg);
}
else if (cccd_chipoble_tx == att_wr_data->handle)
{
sImplInstance->HandleTXCharCCCDWrite(msg);
}
/* TODO: do we need to send the status also for CCCD_WRITTEN? */
if (msg->type != BLE_KW_MSG_ATT_CCCD_WRITTEN)
{
bleResult_t res = GattServer_SendAttributeWrittenStatus(att_wr_data->device_id, att_wr_data->handle, status);
if (res != gBleSuccess_c)
{
ChipLogProgress(DeviceLayer, "GattServer_SendAttributeWrittenStatus returned %d", res);
}
}
}
void BLEManagerCommon::HandleTXCharCCCDWrite(blekw_msg_t * msg)
{
CHIP_ERROR err = CHIP_NO_ERROR;
blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data;
ChipDeviceEvent event;
VerifyOrExit(att_wr_data->length != 0, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(att_wr_data->data != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
#if CHIP_DEVICE_CHIP0BLE_DEBUG
ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", *att_wr_data->data ? "subscribe" : "unsubscribe");
#endif
if (*att_wr_data->data)
{
if (!mDeviceSubscribed)
{
mDeviceSubscribed = true;
event.Type = DeviceEventType::kCHIPoBLESubscribe;
event.CHIPoBLESubscribe.ConId = att_wr_data->device_id;
err = PlatformMgr().PostEvent(&event);
}
}
else
{
mDeviceSubscribed = false;
event.Type = DeviceEventType::kCHIPoBLEUnsubscribe;
event.CHIPoBLESubscribe.ConId = att_wr_data->device_id;
err = PlatformMgr().PostEvent(&event);
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err));
}
}
void BLEManagerCommon::HandleRXCharWrite(blekw_msg_t * msg)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle buf;
blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data;
VerifyOrExit(att_wr_data->length != 0, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(att_wr_data->data != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
// Copy the data to a PacketBuffer.
buf = System::PacketBufferHandle::NewWithData(att_wr_data->data, att_wr_data->length);
VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
#if CHIP_DEVICE_CHIP0BLE_DEBUG
ChipLogDetail(DeviceLayer,
"Write request/command received for"
"CHIPoBLE RX characteristic (con %u, len %u)",
att_wr_data->device_id, buf->DataLength());
#endif
// Post an event to the CHIP queue to deliver the data into the CHIP stack.
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
event.CHIPoBLEWriteReceived.ConId = att_wr_data->device_id;
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 BLEManagerCommon::HandleForceDisconnect()
{
ChipLogProgress(DeviceLayer, "BLE connection timeout: Forcing disconnection.");
/* Set the advertising parameters */
if (Gap_Disconnect(mDeviceId) != gBleSuccess_c)
{
ChipLogProgress(DeviceLayer, "Gap_Disconnect() failed.");
}
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_AllowDeviceToSleep();
#endif
}
/*******************************************************************************
* BLE stack callbacks
*******************************************************************************/
void BLEManagerCommon::blekw_generic_cb(gapGenericEvent_t * pGenericEvent)
{
/* Call BLE Conn Manager */
BleConnManager_GenericEvent(pGenericEvent);
if (sImplInstance && sImplInstance->callbackDelegate.gapCallback)
{
sImplInstance->callbackDelegate.gapCallback(pGenericEvent);
}
switch (pGenericEvent->eventType)
{
case gInternalError_c:
/* Notify the CHIP that the BLE hardware report fail */
ChipLogProgress(DeviceLayer, "BLE Internal Error: Code 0x%04X, Source 0x%08X, HCI OpCode %d.\n",
pGenericEvent->eventData.internalError.errorCode, pGenericEvent->eventData.internalError.errorSource,
pGenericEvent->eventData.internalError.hciCommandOpcode);
if ((gHciUnsupportedRemoteFeature_c == pGenericEvent->eventData.internalError.errorCode) &&
(gLeSetPhy_c == pGenericEvent->eventData.internalError.errorSource))
{
(void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_KW_MSG_2M_UPGRADE_ERROR);
}
else
{
(void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_INTERNAL_ERROR);
}
break;
case gAdvertisingSetupFailed_c:
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED);
break;
case gAdvertisingParametersSetupComplete_c:
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE);
break;
case gAdvertisingDataSetupComplete_c:
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE);
break;
case gRandomAddressReady_c:
Gap_SetRandomAddress(pGenericEvent->eventData.addrReady.aAddress);
break;
case gRandomAddressSet_c:
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_RND_ADDR_SET);
break;
#if BLE_HIGH_TX_POWER
case gTxPowerLevelSetComplete_c:
if (gBleSuccess_c == pGenericEvent->eventData.txPowerLevelSetStatus)
{
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET);
}
break;
#endif
case gInitializationComplete_c:
/* Common GAP configuration */
BleConnManager_GapCommonConfig();
/* Set the local synchronization event */
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INIT_COMPLETE);
break;
default:
break;
}
}
void BLEManagerCommon::blekw_gap_advertising_cb(gapAdvertisingEvent_t * pAdvertisingEvent)
{
if (pAdvertisingEvent->eventType == gAdvertisingStateChanged_c)
{
/* Set the local synchronization event */
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED);
}
else
{
/* The advertisement start failed */
ChipLogProgress(DeviceLayer, "Advertising failed: event=%d reason=0x%04X\n", pAdvertisingEvent->eventType,
pAdvertisingEvent->eventData.failReason);
/* Set the local synchronization event */
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_FAILED);
}
}
void BLEManagerCommon::blekw_gap_connection_cb(deviceId_t deviceId, gapConnectionEvent_t * pConnectionEvent)
{
/* Call BLE Conn Manager */
BleConnManager_GapPeripheralEvent(deviceId, pConnectionEvent);
if (pConnectionEvent->eventType == gConnEvtConnected_c)
{
#if CHIP_DEVICE_K32W1
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
/* Disallow must be called here for K32W1, otherwise an assert will be reached.
* Disclaimer: this is a workaround until a better cross platform solution is found. */
PWR_DisallowDeviceToSleep();
#endif
#endif
#if CHIP_DEVICE_CONFIG_BLE_SET_PHY_2M_REQ
ChipLogProgress(DeviceLayer, "BLE K32W: Trying to set the PHY to 2M");
(void) Gap_LeSetPhy(FALSE, deviceId, 0, gConnPhyUpdateReqTxPhySettings_c, gConnPhyUpdateReqRxPhySettings_c,
(uint16_t) gConnPhyUpdateReqPhyOptions_c);
#endif
/* Notify App Task that the BLE is connected now */
(void) blekw_msg_add_u8(BLE_KW_MSG_CONNECTED, (uint8_t) deviceId);
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
PWR_AllowDeviceToSleep();
#endif
}
else if (pConnectionEvent->eventType == gConnEvtDisconnected_c)
{
blekw_stop_connection_timeout();
/* Notify App Task that the BLE is disconnected now */
(void) blekw_msg_add_u8(BLE_KW_MSG_DISCONNECTED, (uint8_t) deviceId);
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
if (bleAppStopInProgress == TRUE)
{
bleAppStopInProgress = FALSE;
PWR_AllowDeviceToSleep();
}
#endif
}
else if (pConnectionEvent->eventType == gConnEvtPairingRequest_c)
{
/* Reject request for pairing */
Gap_RejectPairing(deviceId, gPairingNotSupported_c);
}
else if (pConnectionEvent->eventType == gConnEvtAuthenticationRejected_c)
{
ChipLogProgress(DeviceLayer, "BLE Authentication rejected (reason:%d).\n",
pConnectionEvent->eventData.authenticationRejectedEvent.rejectReason);
}
}
void BLEManagerCommon::blekw_connection_timeout_cb(TimerHandle_t timer)
{
(void) blekw_msg_add_u8(BLE_KW_MSG_FORCE_DISCONNECT, 0);
}
void BLEManagerCommon::blekw_start_connection_timeout(void)
{
xTimerReset(connectionTimeout, 0);
}
void BLEManagerCommon::blekw_stop_connection_timeout(void)
{
ChipLogProgress(DeviceLayer, "Stopped connectionTimeout timer.");
xTimerStop(connectionTimeout, 0);
}
void BLEManagerCommon::blekw_gatt_server_cb(deviceId_t deviceId, gattServerEvent_t * pServerEvent)
{
if (sImplInstance && sImplInstance->callbackDelegate.gattCallback)
{
sImplInstance->callbackDelegate.gattCallback(deviceId, pServerEvent);
}
switch (pServerEvent->eventType)
{
case gEvtMtuChanged_c: {
uint16_t tempMtu = 0;
(void) Gatt_GetMtu(deviceId, &tempMtu);
blekw_msg_add_u16(BLE_KW_MSG_MTU_CHANGED, tempMtu);
break;
}
case gEvtAttributeWritten_c:
blekw_msg_add_att_written(BLE_KW_MSG_ATT_WRITTEN, deviceId, pServerEvent->eventData.attributeWrittenEvent.handle,
pServerEvent->eventData.attributeWrittenEvent.aValue,
pServerEvent->eventData.attributeWrittenEvent.cValueLength);
break;
case gEvtLongCharacteristicWritten_c:
blekw_msg_add_att_written(BLE_KW_MSG_ATT_LONG_WRITTEN, deviceId, pServerEvent->eventData.longCharWrittenEvent.handle,
pServerEvent->eventData.longCharWrittenEvent.aValue,
pServerEvent->eventData.longCharWrittenEvent.cValueLength);
break;
case gEvtAttributeRead_c:
blekw_msg_add_att_read(BLE_KW_MSG_ATT_READ, deviceId, pServerEvent->eventData.attributeReadEvent.handle);
break;
case gEvtCharacteristicCccdWritten_c: {
uint16_t cccd_val = pServerEvent->eventData.charCccdWrittenEvent.newCccd;
blekw_msg_add_att_written(BLE_KW_MSG_ATT_CCCD_WRITTEN, deviceId, pServerEvent->eventData.charCccdWrittenEvent.handle,
(uint8_t *) &cccd_val, 2);
break;
}
case gEvtHandleValueConfirmation_c:
/* Set the local synchronization event */
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED);
break;
case gEvtError_c:
if (pServerEvent->eventData.procedureError.procedureType == gSendIndication_c)
{
/* Set the local synchronization event */
xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_FAILED);
}
else
{
ChipLogProgress(DeviceLayer, "BLE Gatt Server Error: Code 0x%04X, Source %d.\n",
pServerEvent->eventData.procedureError.error, pServerEvent->eventData.procedureError.procedureType);
/* Notify CHIP BLE App Task that the BLE hardware report fail */
(void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_INTERNAL_GATT_ERROR);
}
break;
default:
break;
}
}
/*******************************************************************************
* Add to message queue functions
*******************************************************************************/
CHIP_ERROR BLEManagerCommon::blekw_msg_add_att_written(blekw_msg_type_t type, uint8_t device_id, uint16_t handle, uint8_t * data,
uint16_t length)
{
CHIP_ERROR err = CHIP_NO_ERROR;
blekw_msg_t * msg = NULL;
blekw_att_written_data_t * att_wr_data;
/* Allocate a buffer with enough space to store the packet */
msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t) + sizeof(blekw_att_written_data_t) + length);
VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY);
msg->type = type;
msg->length = sizeof(blekw_att_written_data_t) + length;
att_wr_data = (blekw_att_written_data_t *) msg->data.data;
att_wr_data->device_id = device_id;
att_wr_data->handle = handle;
att_wr_data->length = length;
FLib_MemCpy(att_wr_data->data, data, length);
VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY);
otTaskletsSignalPending(NULL);
exit:
return err;
}
CHIP_ERROR BLEManagerCommon::blekw_msg_add_att_read(blekw_msg_type_t type, uint8_t device_id, uint16_t handle)
{
CHIP_ERROR err = CHIP_NO_ERROR;
blekw_msg_t * msg = NULL;
blekw_att_read_data_t * att_rd_data;
/* Allocate a buffer with enough space to store the packet */
msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t) + sizeof(blekw_att_read_data_t));
VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY);
msg->type = type;
msg->length = sizeof(blekw_att_read_data_t);
att_rd_data = (blekw_att_read_data_t *) msg->data.data;
att_rd_data->device_id = device_id;
att_rd_data->handle = handle;
VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY);
otTaskletsSignalPending(NULL);
exit:
return err;
}
CHIP_ERROR BLEManagerCommon::blekw_msg_add_u8(blekw_msg_type_t type, uint8_t data)
{
CHIP_ERROR err = CHIP_NO_ERROR;
blekw_msg_t * msg = NULL;
/* Allocate a buffer with enough space to store the packet */
msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t));
VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY);
msg->type = type;
msg->length = 0;
msg->data.u8 = data;
VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY);
otTaskletsSignalPending(NULL);
exit:
return err;
}
CHIP_ERROR BLEManagerCommon::blekw_msg_add_u16(blekw_msg_type_t type, uint16_t data)
{
CHIP_ERROR err = CHIP_NO_ERROR;
blekw_msg_t * msg = NULL;
/* Allocate a buffer with enough space to store the packet */
msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t));
VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY);
msg->type = type;
msg->length = 0;
msg->data.u16 = data;
VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY);
otTaskletsSignalPending(NULL);
exit:
return err;
}
void BLEManagerCommon::BleAdvTimeoutHandler(TimerHandle_t xTimer)
{
if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled))
{
ChipLogDetail(DeviceLayer, "Start slow advertisement");
BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
}
}
void BLEManagerCommon::CancelBleAdvTimeoutTimer(void)
{
if (xTimerStop(sbleAdvTimeoutTimer, 0) == pdFAIL)
{
ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer");
}
}
void BLEManagerCommon::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");
}
}
bool BLEManagerCommon::blekw_stop_connection_internal(BLE_CONNECTION_OBJECT conId)
{
ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId);
if (Gap_Disconnect(conId) != gBleSuccess_c)
{
ChipLogProgress(DeviceLayer, "Gap_Disconnect() failed.");
return false;
}
#if defined(chip_with_low_power) && (chip_with_low_power == 1)
else
{
bleAppStopInProgress = TRUE;
PWR_DisallowDeviceToSleep();
}
#endif
return true;
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE