| /* |
| * |
| * 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."); |
| } |
| } |
| |
| /******************************************************************************* |
| * 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 |