/* * * Copyright (c) 2022 Project CHIP Authors * 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 Beken platforms. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #include #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING #include #endif #include "stdio.h" #include "timers.h" #include // BK7231n BLE related header files #include "matter_pal.h" /******************************************************************************* * Local data types *******************************************************************************/ using namespace ::chip; using namespace ::chip::Ble; namespace chip { namespace DeviceLayer { namespace Internal { namespace { /******************************************************************************* * Macros & Constants definitions *******************************************************************************/ #ifndef MAX_ADV_DATA_LEN #define MAX_ADV_DATA_LEN 31 #endif #define CHIP_ADV_DATA_TYPE_FLAGS 0x01 #define CHIP_ADV_DATA_FLAGS 0x06 /* advertising configuration */ #define CHIP_ADV_SHORT_UUID_LEN (2) /* FreeRTOS sw timer */ TimerHandle_t bleFastAdvTimer; enum { DriveBLEExtPerfEvt_DISCONNECT = 0, }; static const uint8_t _svc_uuid[16] = { 0xF6, 0xFF, 0, 0, 0x0, 0x0, 0, 0, 0, 0, 0x0, 0x0, 0, 0, 0, 0 }; #define UUID_CHIPoBLECharact_RX \ { \ 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 \ } // #define UUID_CHIPoBLECharact_RX { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, // 0x11 // } #define ChipUUID_CHIPoBLECharact_TX \ { \ 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 \ } // #define ChipUUID_CHIPoBLECharact_TX { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, // 0x12 } #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING #define UUID_CHIPoBLEChar_C3 \ { \ 0x04, 0x8F, 0x21, 0x83, 0x8A, 0x74, 0x7D, 0xB8, 0xF2, 0x45, 0x72, 0x87, 0x38, 0x02, 0x63, 0x64 \ } #endif #define BEKEN_ATT_DECL_PRIMARY_SERVICE_128 \ { \ 0x00, 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ } #define BEKEN_ATT_DECL_CHARACTERISTIC_128 \ { \ 0x03, 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ } #define BEKEN_ATT_DESC_CLIENT_CHAR_CFG_128 \ { \ 0x02, 0x29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ } enum { SVR_FFF6_IDX_SVC, SVR_FFF6_RX_DECL, SVR_FFF6_RX_VALUE, SVR_FFF6_TX_DECL, SVR_FFF6_TX_VALUE, #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING SVR_FFF6_C3_VALUE, #endif SVR_FFF6_TX_CFG, SVR_FFF6_MAX, }; ble_attm_desc_t svr_fff6_att_db[SVR_FFF6_MAX] = { // Service Declaration [SVR_FFF6_IDX_SVC] = { BEKEN_ATT_DECL_PRIMARY_SERVICE_128, BK_BLE_PERM_SET(RD, ENABLE), 0, 2 }, // Level Characteristic Declaration [SVR_FFF6_RX_DECL] = { BEKEN_ATT_DECL_CHARACTERISTIC_128, BK_BLE_PERM_SET(RD, ENABLE), 0, 0 }, // Level Characteristic Value BK_PERM_RIGHT_ENABLE WRITE_REQ_POS RI_POS UUID_LEN_POS BK_PERM_RIGHT_UUID_128 [SVR_FFF6_RX_VALUE] = { UUID_CHIPoBLECharact_RX, BK_BLE_PERM_SET(WRITE_REQ, ENABLE), BK_BLE_PERM_SET(RI, ENABLE) | BK_BLE_PERM_SET(UUID_LEN, UUID_128), 512 }, /// RD_POS NTF_POS [SVR_FFF6_TX_DECL] = { BEKEN_ATT_DECL_CHARACTERISTIC_128, BK_BLE_PERM_SET(RD, ENABLE) | BK_BLE_PERM_SET(NTF, ENABLE), 0, 0 }, //// UUID_LEN_POS BK_PERM_RIGHT_UUID_128 RD_POS [SVR_FFF6_TX_VALUE] = { ChipUUID_CHIPoBLECharact_TX, BK_BLE_PERM_SET(RD, ENABLE) | BK_BLE_PERM_SET(NTF, ENABLE), BK_BLE_PERM_SET(RI, ENABLE) | BK_BLE_PERM_SET(UUID_LEN, UUID_128), 512 }, #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING [SVR_FFF6_C3_VALUE] = { UUID_CHIPoBLEChar_C3, BK_BLE_PERM_SET(RD, ENABLE), BK_BLE_PERM_SET(RI, ENABLE) | BK_BLE_PERM_SET(UUID_LEN, UUID_128), 512 }, #endif [SVR_FFF6_TX_CFG] = { BEKEN_ATT_DESC_CLIENT_CHAR_CFG_128, BK_BLE_PERM_SET(RD, ENABLE) | BK_BLE_PERM_SET(WRITE_REQ, ENABLE), 0, 2 }, }; /// const static uint8_t svr_fff6_att_db_item = SVR_FFF6_MAX; } // namespace BLEManagerImpl BLEManagerImpl::sInstance; int BLEManagerImpl::beken_ble_init(void) { int status; struct bk_ble_db_cfg ble_db_cfg; ble_db_cfg.att_db = svr_fff6_att_db; ble_db_cfg.att_db_nb = SVR_FFF6_MAX; ble_db_cfg.prf_task_id = 0; ble_db_cfg.start_hdl = 0; ble_db_cfg.svc_perm = BK_BLE_PERM_SET(SVC_UUID_LEN, UUID_16); memcpy(&(ble_db_cfg.uuid[0]), &_svc_uuid[0], 16); status = bk_ble_create_db(&ble_db_cfg); if (status != BK_ERR_BLE_SUCCESS) { return -1; } return 0; } CHIP_ERROR BLEManagerImpl::_Init() { CHIP_ERROR err; // Initialize the CHIP BleLayer. err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); SuccessOrExit(err); mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; memset(mBleConnections, 0, sizeof(mBleConnections)); // Check if BLE stack is initialized VerifyOrExit(!mFlags.Has(Flags::kAMEBABLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE); bk_ble_set_notice_cb(ble_event_notice); // Set related flags mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); mFlags.Set(Flags::kAMEBABLEStackInitialized); mFlags.Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? true : false); mFlags.Set(Flags::kFastAdvertisingEnabled); mFlags.Set(Flags::kSlowAdvertisingEnabled); if (!mFlags.Has(Flags::kBEKENBLEAdvTimer)) { uint32_t bleAdvTimeoutMs = CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME; bleFastAdvTimer = xTimerCreate("", (bleAdvTimeoutMs / 2), pdFALSE, NULL, ble_adv_timer_timeout_handle); mFlags.Set(Flags::kBEKENBLEAdvTimer); } PlatformMgr().ScheduleWork(DriveBLEState, 0); exit: return err; } void BLEManagerImpl::HandleTXCharRead(void * param) { CHIPoBLEConState * conState; ble_read_req_t * r_req = (ble_read_req_t *) param; if (param == NULL) { ChipLogError(DeviceLayer, "HandleTXCharRead failed: %p", param); } r_req->length = 0; } void BLEManagerImpl::HandleTXCharCCCDRead(void * param) { CHIPoBLEConState * conState; ble_read_req_t * r_req = (ble_read_req_t *) param; conState = GetConnectionState(r_req->conn_idx); if (param == NULL) { ChipLogError(DeviceLayer, "HandleTXCharCCCDRead failed"); return; } if (conState != NULL) { r_req->value[0] = conState->subscribed ? 1 : 0; r_req->value[1] = 0; r_req->length = 2; } else { ChipLogError(DeviceLayer, "conState failed: %p", conState); r_req->length = 0; } } void BLEManagerImpl::HandleTXCharCCCDWrite(int conn_id, int notificationsEnabled, int indicationsEnabled) { CHIP_ERROR err = CHIP_NO_ERROR; // If the client has requested to enabled indications/notifications if (indicationsEnabled || notificationsEnabled) { // If indications are not already enabled for the connection... if (!IsSubscribed(conn_id)) { // Record that indications have been enabled for this connection. err = SetSubscribed(conn_id); VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); SuccessOrExit(err); } } else { // If indications had previously been enabled for this connection, record that they are no longer enabled. UnsetSubscribed(conn_id); } // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on // whether the client is enabling or disabling indications. { ChipDeviceEvent event; event.Type = (indicationsEnabled || notificationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe; event.CHIPoBLESubscribe.ConId = conn_id; PlatformMgr().PostEventOrDie(&event); } ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", (indicationsEnabled || notificationsEnabled) ? "subscribe" : "unsubscribe"); exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); } return; } CHIP_ERROR BLEManagerImpl::HandleTXComplete(int conn_id) { // Post an event to the Chip queue to process the indicate confirmation. ChipDeviceEvent event; event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; event.CHIPoBLEIndicateConfirm.ConId = conn_id; PlatformMgr().PostEventOrDie(&event); return CHIP_NO_ERROR; } uint16_t BLEManagerImpl::_NumConnections(void) { uint16_t numCons = 0; for (uint8_t i = 0; i < kMaxConnections; i++) { if (mBleConnections[i].allocated == 1) { numCons += 1; } } return numCons; } CHIP_ERROR BLEManagerImpl::HandleGAPConnect(uint16_t conn_id) { CHIP_ERROR err = CHIP_NO_ERROR; // Track the number of active GAP connections. mNumGAPCons++; err = SetSubscribed(conn_id); VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); SuccessOrExit(err); exit: return err; } CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(uint16_t conn_id, uint16_t disc_cause) { // Update the number of GAP connections. if (mNumGAPCons > 0) { mNumGAPCons--; } if (RemoveConnection(conn_id)) { CHIP_ERROR disconReason; switch (disc_cause) { case 0x13: case 0x08: disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; break; case 0x16: disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; break; default: disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; break; } HandleConnectionError(conn_id, disconReason); } // Force a reconfiguration of advertising in case we switched to non-connectable mode when // the BLE connection was established. mFlags.Set(Flags::kAdvertisingRefreshNeeded); return CHIP_NO_ERROR; } bool BLEManagerImpl::RemoveConnection(uint8_t connectionHandle) { CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle); bool status = false; if (bleConnState != NULL) { bleConnState->Reset(); memset(bleConnState, 0, sizeof(CHIPoBLEConState)); status = true; } return status; } BLEManagerImpl::CHIPoBLEConState * BLEManagerImpl::GetConnectionState(uint8_t connectionHandle, bool allocate) { uint8_t freeIndex = kMaxConnections; for (uint8_t i = 0; i < kMaxConnections; i++) { if (mBleConnections[i].allocated == 1) { if (mBleConnections[i].conn_idx == connectionHandle) { return &mBleConnections[i]; } } else if (i < freeIndex) { freeIndex = i; } } if (allocate) { if (freeIndex < kMaxConnections) { mBleConnections[freeIndex].Set(connectionHandle); return &mBleConnections[freeIndex]; } ChipLogError(DeviceLayer, "Failed to allocate CHIPoBLEConState"); } return NULL; } CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); if (val != mServiceMode) { mServiceMode = val; PlatformMgr().ScheduleWork(DriveBLEState, 0); } exit: return err; } CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); if (mFlags.Has(Flags::kAdvertisingEnabled) != val) { mFlags.Set(Flags::kAdvertisingEnabled, val); PlatformMgr().ScheduleWork(DriveBLEState, 0); } exit: return err; } CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) { switch (mode) { case BLEAdvertisingMode::kFastAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, true); break; case BLEAdvertisingMode::kSlowAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, false); break; default: return CHIP_ERROR_INVALID_ARGUMENT; } mFlags.Set(Flags::kAdvertisingRefreshNeeded); PlatformMgr().ScheduleWork(DriveBLEState, 0); return CHIP_NO_ERROR; } CHIP_ERROR BLEManagerImpl::_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 BLEManagerImpl::_SetDeviceName(const char * deviceName) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); if (deviceName != NULL && deviceName[0] != 0) { VerifyOrExit(strlen(deviceName) >= kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); strcpy(mDeviceName, deviceName); mFlags.Set(Flags::kDeviceNameSet); ChipLogProgress(DeviceLayer, "Setting device name to : \"%s\"", deviceName); } else { mDeviceName[0] = 0; mFlags.Clear(Flags::kDeviceNameSet); } exit: return err; } void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) { switch (event->Type) { // Platform specific events case DeviceEventType::kCHIPoBLESubscribe: HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); { ChipDeviceEvent connEstEvent; connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; PlatformMgr().PostEventOrDie(&connEstEvent); } break; case DeviceEventType::kCHIPoBLEUnsubscribe: { ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe"); HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); } break; case DeviceEventType::kCHIPoBLEWriteReceived: { ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived"); HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID, PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); } break; case DeviceEventType::kCHIPoBLEConnectionError: { ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError"); HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); } break; case DeviceEventType::kCHIPoBLEIndicateConfirm: { ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm"); HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); } break; case DeviceEventType::kServiceProvisioningChange: case DeviceEventType::kWiFiConnectivityChange: ChipLogProgress(DeviceLayer, "Updating advertising data"); StartAdvertising(); break; default: ChipLogProgress(DeviceLayer, "_OnPlatformEvent default: event->Type = %d", event->Type); break; } } CHIP_ERROR BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) { ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) { ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) { CHIP_ERROR err; ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); uint32_t delay_time = 20; int ret; do { ret = bk_ble_disconnect(conId, beken_ble_cmd_cb); if (BK_ERR_BLE_SUCCESS == ret) { break; } rtos_delay_milliseconds(10); delay_time--; } while (delay_time); // Beken Ble close function err = MapBLEError(ret); if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "bk_ble_disconnect() failed: %s", ErrorStr(err)); } return err; } uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const { CHIPoBLEConState * conState = const_cast(this)->GetConnectionState(conId); return (conState != NULL) ? conState->mtu : 0; } CHIP_ERROR BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, PacketBufferHandle pBuf) { ChipLogError(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); return CHIP_ERROR_NOT_IMPLEMENTED; } void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) { // Nothing to do } CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, PacketBufferHandle data) { CHIP_ERROR err = CHIP_NO_ERROR; int ret; VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); ret = bk_ble_send_noti_value(conId, data->DataLength(), data->Start(), 0, SVR_FFF6_TX_VALUE); err = MapBLEError(ret); exit: return err; } /******************************************************************************* * Private functions *******************************************************************************/ CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) { CHIP_ERROR err = CHIP_NO_ERROR; // If the device name is not specified, generate a CHIP-standard name based on the bottom digits of the Chip device id. uint16_t discriminator; SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator)); if (!mFlags.Has(Flags::kDeviceNameSet)) { snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); mDeviceName[kMaxDeviceNameLength] = 0; } // Configure the BLE device name. sInstance.mFlags.Set(Flags::kDeviceNameDefSet); bk_ble_appm_set_dev_name(kMaxDeviceNameLength, (uint8_t *) mDeviceName); exit: return err; } CHIP_ERROR BLEManagerImpl::StartAdvertising(void) { ble_err_t bk_err; CHIP_ERROR err = CHIP_NO_ERROR; ChipLogProgress(DeviceLayer, "StartAdvertising..."); ChipLogProgress(DeviceLayer, "BLE flag = %x", mFlags.Raw()); if ((!mFlags.Has(Flags::kDeviceNameSet)) && (!mFlags.Has(Flags::kDeviceNameDefSet))) { err = sInstance.ConfigureAdvertisingData(); SuccessOrExit(err); } // Post a CHIPoBLEAdvertisingChange(Stopped) event. if (mFlags.Has(Flags::kBEKENBLEADVStop)) { bk_ble_delete_advertising(adv_actv_idx, beken_ble_cmd_cb); mFlags.Clear(Flags::kBEKENBLEADVStop); ChipDeviceEvent advChange; advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; PlatformMgr().PostEventOrDie(&advChange); goto exit; } else if (!mFlags.Has(Flags::kBEKENBLEADVCreate)) { ChipLogProgress(DeviceLayer, "BLE ADVCreate..."); uint16_t adv_int_min; uint16_t adv_int_max; ble_adv_param_t adv_param; memset(&adv_param, 0, sizeof(adv_param)); if (mFlags.Has(Flags::kFastAdvertisingEnabled)) { adv_int_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; adv_int_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; mFlags.Set(Flags::kAdvertisingIsFastADV); } else { adv_int_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; adv_int_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; mFlags.Clear(Flags::kAdvertisingIsFastADV); } adv_actv_idx = bk_ble_get_idle_actv_idx_handle(); if (UNKNOW_ACT_IDX == adv_actv_idx) { ChipLogError(DeviceLayer, "adv act-idx:%d error", adv_actv_idx); return MapBLEError(-1); } adv_param.chnl_map = 7; adv_param.adv_intv_max = 160; adv_param.adv_intv_min = 160; adv_param.own_addr_type = 0; adv_param.adv_type = 0; adv_param.adv_prop = 3; adv_param.prim_phy = 1; // bk_ble_create_advertising(adv_actv_idx, 7, adv_int_min, adv_int_max, beken_ble_cmd_cb); bk_err = bk_ble_create_advertising(adv_actv_idx, &adv_param, beken_ble_cmd_cb); if (bk_err != BK_OK) { ChipLogProgress(DeviceLayer, "BLE ADVCreate ret= %x.", bk_err); } ChipLogProgress(DeviceLayer, "BLE ADVCreate ret= %x. adv_actv_idx = %x", bk_err, adv_actv_idx); sInstance.mFlags.Clear(Flags::kAdvertisingRefreshNeeded); goto exit; } else if (!mFlags.Has(Flags::kBEKENBLEADVSetData)) { ChipLogProgress(DeviceLayer, "BLE SetData..."); ChipBLEDeviceIdentificationInfo deviceIdInfo; uint8_t advData[MAX_ADV_DATA_LEN] = { 0 }; uint8_t index = 0; /**************** Prepare advertising data *******************************************/ memset(advData, 0, sizeof(advData)); advData[index++] = 0x02; // length advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value advData[index++] = static_cast(sizeof(deviceIdInfo) + CHIP_ADV_SHORT_UUID_LEN + 1); ; // length advData[index++] = 0x16; // AD type: (Service Data - 16-bit UUID) advData[index++] = static_cast(_svc_uuid[0] & 0xFF); // AD value advData[index++] = static_cast(_svc_uuid[1] & 0xFF); // AD value err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err)); ExitNow(); } #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING deviceIdInfo.SetAdditionalDataFlag(true); #endif VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo)); index = static_cast(index + sizeof(deviceIdInfo)); bk_ble_set_adv_data(adv_actv_idx, advData, index, beken_ble_cmd_cb); goto exit; } else if (!mFlags.Has(Flags::kBEKENBLEADVSetRsp)) { /// uint8_t advData[MAX_ADV_DATA_LEN] = { 0 }; /// bk_ble_set_scan_rsp_data(adv_actv_idx, advData, 0xF, beken_ble_cmd_cb); sInstance.mFlags.Set(Flags::kBEKENBLEADVSetRsp); PlatformMgr().ScheduleWork(DriveBLEState, 0); goto exit; } else if (!mFlags.Has(Flags::kBEKENBLEADVStarted)) { ChipLogProgress(DeviceLayer, "BLE Started..."); bk_ble_start_advertising(adv_actv_idx, 0, beken_ble_cmd_cb); goto exit; } if (mFlags.Has(Flags::kBEKENBLEADVStarted)) { ChipDeviceEvent advChange; advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; PlatformMgr().PostEventOrDie(&advChange); } exit: return err; } CHIP_ERROR BLEManagerImpl::StopAdvertising(void) { // Change flag status to the 'not Advertising state' if ((mFlags.Has(Flags::kBEKENBLEADVStarted)) && (!mFlags.Has(Flags::kBEKENBLEADVStop))) { mFlags.Set(Flags::kBEKENBLEADVStop); bk_ble_stop_advertising(adv_actv_idx, beken_ble_cmd_cb); ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopping"); goto exit; } // Post a CHIPoBLEAdvertisingChange(Stopped) event. if (mFlags.Has(Flags::kBEKENBLEADVStop)) { bk_ble_delete_advertising(adv_actv_idx, beken_ble_cmd_cb); mFlags.Clear(Flags::kBEKENBLEADVStop); ChipDeviceEvent advChange; advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; PlatformMgr().PostEventOrDie(&advChange); } exit: return CHIP_NO_ERROR; } CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) { switch (bleErr) { case BK_ERR_BLE_SUCCESS: return CHIP_NO_ERROR; default: return CHIP_ERROR_INCORRECT_STATE; } } void BLEManagerImpl::DriveBLEState(void) { CHIP_ERROR err = CHIP_NO_ERROR; // Check if BLE stack is initialized VerifyOrExit(mFlags.Has(Flags::kAMEBABLEStackInitialized), /* */); if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled) { if (!mFlags.Has(Flags::kBekenBLESGATTSReady)) { beken_ble_init(); goto exit; } } if ((!mFlags.Has(Flags::kFastAdvertisingEnabled)) && (!mFlags.Has(Flags::kSlowAdvertisingEnabled))) { mFlags.Clear(Flags::kAdvertisingEnabled); mFlags.Clear(Flags::kAdvertisingRefreshNeeded); } if (mFlags.Has(Flags::kAdvertisingRefreshNeeded)) { if (mFlags.Has(Flags::kBEKENBLEADVStarted)) { err = StopAdvertising(); SuccessOrExit(err); goto exit; } else if (mFlags.Has(Flags::kBEKENBLEADVStarted)) { bk_ble_delete_advertising(adv_actv_idx, beken_ble_cmd_cb); goto exit; } } // Start advertising if needed... if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && ((mFlags.Has(Flags::kAdvertisingEnabled)) || (mFlags.Has(Flags::kAdvertisingRefreshNeeded)))) { // Start/re-start advertising if not already started, or if there is a pending change // to the advertising configuration. if (!mFlags.Has(Flags::kBEKENBLEADVStarted)) { err = StartAdvertising(); SuccessOrExit(err); } else { mFlags.Clear(Flags::kAdvertisingRefreshNeeded); } } // Otherwise, stop advertising if it is enabled. else if ((mFlags.Has(Flags::kBEKENBLEADVStarted)) || (mFlags.Has(Flags::kBEKENBLEADVStop))) { err = StopAdvertising(); SuccessOrExit(err); ChipLogProgress(DeviceLayer, "Stopped Advertising"); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; } } void BLEManagerImpl::DriveBLEState(intptr_t arg) { sInstance.DriveBLEState(); } void BLEManagerImpl::DriveBLEExtPerf(intptr_t arg) { int arg_int = static_cast(arg); int event = arg_int & 0xFFU; switch (event) { case DriveBLEExtPerfEvt_DISCONNECT: { uint8_t conn_indx = (arg_int >> 8) & 0xFFU; sInstance.CloseConnection(conn_indx); } break; default: break; } } /******************************************************************************* * FreeRTOS Task Management Functions *******************************************************************************/ void BLEManagerImpl::ble_adv_timer_timeout_handle(TimerHandle_t xTimer) { if (sInstance.mFlags.Has(Flags::kFastAdvertisingEnabled)) { ChipLogDetail(DeviceLayer, "bleAdv Timeout : Stop Fast advertisement"); sInstance.mFlags.Clear(Flags::kFastAdvertisingEnabled); // Stop advertising, change interval and restart it; sInstance.StopAdvertising(); } else if (sInstance._IsAdvertisingEnabled()) { // Advertisement time expired. Stop advertising ChipLogDetail(DeviceLayer, "bleAdv Timeout : Stop slow advertisement"); sInstance.mFlags.Clear(Flags::kSlowAdvertisingEnabled); sInstance.StopAdvertising(); } } void BLEManagerImpl::CancelBleAdvTimeoutTimer(void) { if (xTimerIsTimerActive(bleFastAdvTimer)) { if (xTimerStop(bleFastAdvTimer, 0) == pdFAIL) { ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer"); sInstance.mFlags.Clear(Flags::kBEKENBLEAdvTimerRun); } } } void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs) { 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(bleFastAdvTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) { ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer"); } else { xTimerStart(bleFastAdvTimer, BEKEN_WAIT_FOREVER); sInstance.mFlags.Set(Flags::kBEKENBLEAdvTimerRun); } } CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) { CHIPoBLEConState * bleConnState = GetConnectionState(conId, false); if (bleConnState != NULL) { bleConnState->subscribed = 1; return CHIP_NO_ERROR; } return CHIP_ERROR_NO_MEMORY; } bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) { CHIPoBLEConState * bleConnState = GetConnectionState(conId, false); if (bleConnState != NULL) { bleConnState->subscribed = 0; return true; } return false; } bool BLEManagerImpl::IsSubscribed(uint16_t conId) { CHIPoBLEConState * bleConnState = GetConnectionState(conId, false); if (bleConnState != NULL) { if (bleConnState->subscribed) { return true; } } return false; } void BLEManagerImpl::HandleRXCharWrite(uint8_t * p_value, uint16_t len, uint8_t conn_id) { CHIP_ERROR err = CHIP_NO_ERROR; PacketBufferHandle buf = System::PacketBufferHandle::New(len, 0); memcpy(buf->Start(), p_value, len); buf->SetDataLength(len); // Post an event to the Chip queue to deliver the data into the Chip stack. { ChipDeviceEvent event; event.Type = DeviceEventType::kCHIPoBLEWriteReceived; event.CHIPoBLEWriteReceived.ConId = (uint16_t) conn_id; event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); PlatformMgr().PostEventOrDie(&event); } if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); } } void BLEManagerImpl::HandleTXCharConfirm(CHIPoBLEConState * conState, int status) { // If the confirmation was successful... if (status == 0) { // Post an event to the Chip queue to process the indicate confirmation. ChipDeviceEvent event; event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; event.CHIPoBLEIndicateConfirm.ConId = conState->conn_idx; PlatformMgr().PostEventOrDie(&event); } else { ChipDeviceEvent event; event.Type = DeviceEventType::kCHIPoBLEConnectionError; event.CHIPoBLEConnectionError.ConId = conState->conn_idx; event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; PlatformMgr().PostEventOrDie(&event); } } void BLEManagerImpl::beken_ble_cmd_cb(ble_cmd_t cmd, ble_cmd_param_t * param) { ChipLogProgress(DeviceLayer, "cmd:%d idx:%d status:%d\r\n", cmd, param->cmd_idx, param->status); switch (cmd) { case BLE_CREATE_ADV: sInstance.mFlags.Set(Flags::kBEKENBLEADVCreate); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; case BLE_SET_ADV_DATA: sInstance.mFlags.Set(Flags::kBEKENBLEADVSetData); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; case BLE_SET_RSP_DATA: sInstance.mFlags.Set(Flags::kBEKENBLEADVSetRsp); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; case BLE_START_ADV: { uint32_t bleAdvTimeoutMs; sInstance.mFlags.Set(Flags::kBEKENBLEADVStarted); // if (sInstance.mFlags.Has(Flags::kAdvertisingIsFastADV)){ bleAdvTimeoutMs = CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME; //}else{ // bleAdvTimeoutMs = CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT; //} StartBleAdvTimeoutTimer(bleAdvTimeoutMs); PlatformMgr().ScheduleWork(DriveBLEState, 0); } break; case BLE_STOP_ADV: sInstance.mFlags.Clear(Flags::kBEKENBLEADVStarted); ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); CancelBleAdvTimeoutTimer(); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; case BLE_DELETE_ADV: sInstance.mFlags.Clear(Flags::kBEKENBLEADVCreate); sInstance.mFlags.Clear(Flags::kBEKENBLEADVSetData); sInstance.mFlags.Clear(Flags::kBEKENBLEADVSetRsp); sInstance.mFlags.Clear(Flags::kBEKENBLEADVStarted); sInstance.adv_actv_idx = kUnusedIndex; PlatformMgr().ScheduleWork(DriveBLEState, 0); break; case BLE_CONN_DIS_CONN: break; default: break; } } #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING void BLEManagerImpl::HandleC3CharRead(void * param) { CHIP_ERROR err = CHIP_NO_ERROR; chip::System::PacketBufferHandle bufferHandle; ble_read_req_t * r_req = (ble_read_req_t *) param; AdditionalDataPayloadGeneratorParams additionalDataPayloadParams; BitFlags additionalDataFields; #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(additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter); SuccessOrExit(err); additionalDataPayloadParams.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan; additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId); #endif /* CHIP_ENABLE_ROTATING_DEVICE_ID */ err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, bufferHandle, additionalDataFields); SuccessOrExit(err); if (r_req->value == NULL) { ChipLogError(DeviceLayer, "param->value == NULL"); return; } memcpy(r_req->value, bufferHandle->Start(), bufferHandle->DataLength()); r_req->length = bufferHandle->DataLength(); exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data"); } return; } #endif void BLEManagerImpl::ble_event_notice(ble_notice_t notice, void * param) { /// BLEManagerImpl * blemgr = static_cast(param); static int conn_idx = 0; // TODO. will improve this when driver notify the status and channel to app. switch (notice) { case BLE_5_STACK_OK: { ChipLogProgress(DeviceLayer, "ble stack ok"); sInstance.mFlags.Set(Flags::kAMEBABLEStackInitialized); } break; case BLE_5_WRITE_EVENT: { ble_write_req_t * w_req = (ble_write_req_t *) param; ChipLogProgress(DeviceLayer, "write_cb:conn_idx:%d, prf_id:%d, add_id:%d, len:%d, data[0]:%02x\r\n", w_req->conn_idx, w_req->prf_id, w_req->att_idx, w_req->len, w_req->value[0]); if (w_req->att_idx == SVR_FFF6_TX_VALUE) { sInstance.HandleRXCharWrite((uint8_t *) &w_req->value[0], w_req->len, w_req->conn_idx); } else if (w_req->att_idx == SVR_FFF6_TX_CFG) { int notificationsEnabled = w_req->value[0] | (w_req->value[0] << 8); sInstance.HandleTXCharCCCDWrite(w_req->conn_idx, notificationsEnabled); } else if (w_req->att_idx == SVR_FFF6_RX_VALUE) { sInstance.HandleRXCharWrite((uint8_t *) &w_req->value[0], w_req->len, w_req->conn_idx); } break; } case BLE_5_READ_EVENT: { ble_read_req_t * r_req = (ble_read_req_t *) param; ChipLogProgress(DeviceLayer, "read_cb:conn_idx:%d, prf_id:%d, add_id:%d\r\n", r_req->conn_idx, r_req->prf_id, r_req->att_idx); if (r_req->att_idx == SVR_FFF6_RX_VALUE) { sInstance.HandleTXCharRead(param); } if (r_req->att_idx == SVR_FFF6_TX_CFG) { sInstance.HandleTXCharCCCDRead(param); } #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING if (r_req->att_idx == SVR_FFF6_C3_VALUE) { ChipLogProgress(DeviceLayer, "SVR_FFF6_OPT_VALUE!!!!\r\n"); sInstance.HandleTXCharRead((void *) param); } #endif break; } case BLE_5_TX_DONE: { ChipLogProgress(DeviceLayer, "BLE_5_TX_DONE"); #if 0 tx_done_rsp_t* txd_rsp = (tx_done_rsp_t*)param; if(txd_rsp) { CHIPoBLEConState * conState = sInstance.GetConnectionState(txd_rsp->conn_idx,false); if (conState != NULL) { sInstance.HandleTXCharConfirm(conState, txd_rsp->status); } } #endif CHIPoBLEConState * conState = sInstance.GetConnectionState(conn_idx, false); if (conState != NULL) { sInstance.HandleTXCharConfirm(conState, 0); } } break; case BLE_5_MTU_CHANGE: { ble_mtu_change_t * m_ind = (ble_mtu_change_t *) param; ChipLogProgress(DeviceLayer, "m_ind:conn_idx:%d, mtu_size:%d\r\n", m_ind->conn_idx, m_ind->mtu_size); CHIPoBLEConState * conState = sInstance.GetConnectionState(m_ind->conn_idx); if (conState != NULL) { conState->mtu = (m_ind->mtu_size >= (1 << 10)) ? ((1 << 10) - 1) : m_ind->mtu_size; } break; } case BLE_5_CONNECT_EVENT: { ble_conn_ind_t * c_ind = (ble_conn_ind_t *) param; ChipLogProgress(DeviceLayer, "BLE GATT connection established (con %u)", c_ind->conn_idx); ChipLogProgress(DeviceLayer, "c_ind:conn_idx:%d, addr_type:%d, peer_addr:%02x:%02x:%02x:%02x:%02x:%02x\r\n", c_ind->conn_idx, c_ind->peer_addr_type, c_ind->peer_addr[0], c_ind->peer_addr[1], c_ind->peer_addr[2], c_ind->peer_addr[3], c_ind->peer_addr[4], c_ind->peer_addr[5]); sInstance.mFlags.Clear(Flags::kBEKENBLEADVStarted); CHIPoBLEConState * bleConnState = sInstance.GetConnectionState(c_ind->conn_idx, true); if (bleConnState == NULL) { ChipLogError(DeviceLayer, "BLE_5_CONNECT_EVENT failed"); int ext_evt = DriveBLEExtPerfEvt_DISCONNECT | (c_ind->conn_idx << 8); PlatformMgr().ScheduleWork(DriveBLEExtPerf, ext_evt); } conn_idx = c_ind->conn_idx; break; } case BLE_5_DISCONNECT_EVENT: { ble_discon_ind_t * d_ind = (ble_discon_ind_t *) param; ChipLogProgress(DeviceLayer, "d_ind:conn_idx:%d,reason:%d\r\n", d_ind->conn_idx, d_ind->reason); sInstance.HandleGAPDisconnect(d_ind->conn_idx, d_ind->reason); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; } case BLE_5_ATT_INFO_REQ: { ble_att_info_req_t * a_ind = (ble_att_info_req_t *) param; ChipLogProgress(DeviceLayer, "a_ind:conn_idx:%d\r\n", a_ind->conn_idx); if (SVR_FFF6_RX_VALUE == a_ind->att_idx) { a_ind->length = 512; a_ind->status = BK_ERR_BLE_SUCCESS; } else if (SVR_FFF6_TX_CFG == a_ind->att_idx) { a_ind->length = 2; a_ind->status = BK_ERR_BLE_SUCCESS; } break; } case BLE_5_CREATE_DB: { ble_create_db_t * cd_ind = (ble_create_db_t *) param; ChipLogProgress(DeviceLayer, "cd_ind:prf_id:%d, status:%d\r\n", cd_ind->prf_id, cd_ind->status); sInstance.mFlags.Set(Flags::kBekenBLESGATTSReady); PlatformMgr().ScheduleWork(DriveBLEState, 0); break; } default: { ChipLogProgress(DeviceLayer, "Unhandled event:%x", notice); } break; } } } // namespace Internal } // namespace DeviceLayer } // namespace chip #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE