/* * * Copyright (c) 2020-2021 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 Ameba platforms. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #include #include "stdio.h" #include "timers.h" #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING #include #endif #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER #include "matter_blemgr_common.h" #else // Ameba BLE related header files #include "bt_matter_adapter_app_main.h" #include "bt_matter_adapter_app_task.h" #include "bt_matter_adapter_peripheral_app.h" #include "bt_matter_adapter_service.h" #include "bte.h" #include "gap.h" #include "gap_adv.h" #include "gap_conn_le.h" #include "os_sched.h" #include "profile_server.h" #include "rtk_coex.h" #include "trace_app.h" #include "wifi_conf.h" // #include "complete_ble_service.h" #include "app_msg.h" #endif /******************************************************************************* * Local data types *******************************************************************************/ using namespace ::chip; using namespace ::chip::Ble; namespace chip { namespace DeviceLayer { namespace Internal { namespace { /******************************************************************************* * Macros & Constants definitions *******************************************************************************/ #define APP_MAX_LINKS 4 #define MAX_ADV_DATA_LEN 31 #define CHIP_ADV_DATA_TYPE_FLAGS 0x01 #define CHIP_ADV_DATA_FLAGS 0x06 #define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16 #define LOOP_EV_BLE (0x08) /* ble app task configuration */ #define CHIP_DEVICE_CONFIG_BLE_APP_TASK_PRIORITY (HOST_TASK_PRIORITY - 1) #define CHIP_DEVICE_CONFIG_BLE_APP_TASK_STACK_SIZE (1024) /* advertising configuration */ #define CHIP_ADV_SHORT_UUID_LEN (2) #define DISC_CAUSE_REMOTE_USER_TERMINATE 0x113 #define DISC_CAUSE_LOCAL_HOST_TERMINATE 0x116 /* FreeRTOS sw timer */ TimerHandle_t sbleAdvTimeoutTimer; /* Used by BLE App Task to handle asynchronous GATT events */ EventGroupHandle_t bleAppTaskLoopEvent; /* keep the device ID of the connected peer */ uint8_t device_id; /** Type of UUID */ enum { /** 16-bit UUID (BT SIG assigned) */ BLE_UUID_TYPE_16 = 16, /** 32-bit UUID (BT SIG assigned) */ BLE_UUID_TYPE_32 = 32, /** 128-bit UUID */ BLE_UUID_TYPE_128 = 128, }; typedef struct { /** Type of the UUID */ uint8_t type; } ble_uuid_t; /** 16-bit UUID */ typedef struct { ble_uuid_t u; uint16_t value; } ble_uuid16_t; const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFFF6 }; static constexpr System::Clock::Timeout kFastAdvertiseTimeout = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); System::Clock::Timestamp mAdvertiseStartTime; } // namespace BLEManagerImpl BLEManagerImpl::sInstance; CHIP_ERROR BLEManagerImpl::_Init() { CHIP_ERROR err; // Initialize the CHIP BleLayer. err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); SuccessOrExit(err); mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; // Check if BLE stack is initialized VerifyOrExit(!mFlags.Has(Flags::kAMEBABLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE); #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_set_callback_func((matter_blemgr_callback) (matter_blemgr_callback_dispatcher), this); err = MapBLEError(matter_blemgr_init()); #else err = MapBLEError(bt_matter_adapter_init()); chip_blemgr_set_callback_func((chip_blemgr_callback) (ble_callback_dispatcher), this); #endif SuccessOrExit(err); // 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); InitSubscribed(); PlatformMgr().ScheduleWork(DriveBLEState, 0); exit: return err; } void BLEManagerImpl::HandleTXCharRead(void * param) { /* Not supported */ ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharRead() not supported"); } void BLEManagerImpl::HandleTXCharCCCDRead(void * param) { /* Not Supported */ ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharCCCDRead() not supported"); } void BLEManagerImpl::HandleTXCharCCCDWrite(int conn_id, int indicationsEnabled, int notificationsEnabled) { 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() { uint16_t numCons = 0; for (uint16_t i = 0; i < kMaxConnections; i++) { if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED) { numCons++; } } return numCons; } CHIP_ERROR BLEManagerImpl::HandleGAPConnect(uint16_t conn_id) { CHIP_ERROR err = CHIP_NO_ERROR; // Track the number of active GAP connections. mNumGAPCons++; VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); SuccessOrExit(err); mFlags.Set(Flags::kRestartAdvertising); mFlags.Clear(Flags::kRestartAdvertising); 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--; } CHIP_ERROR disconReason; switch (disc_cause) { case DISC_CAUSE_REMOTE_USER_TERMINATE: // BLE_ERR_REM_USER_CONN_TERM: disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; break; case DISC_CAUSE_LOCAL_HOST_TERMINATE: // BLE_ERR_CONN_TERM_LOCAL: disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; break; default: disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; break; } ChipDeviceEvent event; event.Type = DeviceEventType::kCHIPoBLEConnectionError; event.CHIPoBLEConnectionError.ConId = conn_id; event.CHIPoBLEConnectionError.Reason = disconReason; PlatformMgr().PostEventOrDie(&event); // Force a reconfiguration of advertising in case we switched to non-connectable mode when // the BLE connection was established. mFlags.Set(Flags::kRestartAdvertising); mFlags.Clear(Flags::kAdvertisingConfigured); return CHIP_NO_ERROR; } bool BLEManagerImpl::RemoveConnection(uint8_t connectionHandle) { CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true); bool status = false; if (bleConnState != NULL) { memset(bleConnState, 0, sizeof(CHIPoBLEConState)); status = true; } return status; } void BLEManagerImpl::AddConnection(uint8_t connectionHandle) { CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true); if (bleConnState != NULL) { memset(bleConnState, 0, sizeof(CHIPoBLEConState)); bleConnState->allocated = 1; bleConnState->connectionHandle = connectionHandle; } } 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].connectionHandle == connectionHandle) { return &mBleConnections[i]; } } else if (i < freeIndex) { freeIndex = i; } } if (allocate) { if (freeIndex < kMaxConnections) { return &mBleConnections[freeIndex]; } ChipLogError(DeviceLayer, "Failed to allocate CHIPoBLEConState"); } return NULL; } CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); if (val) { mAdvertiseStartTime = System::SystemClock().GetMonotonicTimestamp(); ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleFastAdvertisementTimer, this)); } if (mFlags.Has(Flags::kAdvertisingEnabled) != val) { mFlags.Set(Flags::kAdvertisingEnabled, val); mFlags.Set(Flags::kFastAdvertisingEnabled, val); mFlags.Set(Flags::kRestartAdvertising, 1); PlatformMgr().ScheduleWork(DriveBLEState, 0); } exit: return err; } void BLEManagerImpl::HandleFastAdvertisementTimer(System::Layer * systemLayer, void * context) { static_cast(context)->HandleFastAdvertisementTimer(); } void BLEManagerImpl::HandleFastAdvertisementTimer() { System::Clock::Timestamp currentTimestamp = System::SystemClock().GetMonotonicTimestamp(); if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout) { mFlags.Set(Flags::kFastAdvertisingEnabled, 0); mFlags.Set(Flags::kRestartAdvertising, 1); PlatformMgr().ScheduleWork(DriveBLEState, 0); } } CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) { switch (mode) { case BLEAdvertisingMode::kFastAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, true); break; case BLEAdvertisingMode::kSlowAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, false); break; default: return CHIP_ERROR_INVALID_ARGUMENT; } mFlags.Set(Flags::kRestartAdvertising); PlatformMgr().ScheduleWork(DriveBLEState, 0); return CHIP_NO_ERROR; } CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) { if (strlen(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); // Configure the BLE device name. #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_set_device_name(mDeviceName, strlen(mDeviceName)); #else le_set_gap_param(GAP_PARAM_DEVICE_NAME, kMaxDeviceNameLength, mDeviceName); #endif 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"); mFlags.Clear(Flags::kAdvertisingConfigured); mFlags.Set(Flags::kRestartAdvertising); DriveBLEState(); break; default: 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); // Ameba Ble close function #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER err = MapBLEError(matter_blemgr_disconnect(conId)); #else err = MapBLEError(le_disconnect(conId)); #endif if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Close connection failed: %s", ErrorStr(err)); } mFlags.Set(Flags::kRestartAdvertising); mFlags.Clear(Flags::kAdvertisingConfigured); PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const { int mtu; #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER mtu = matter_blemgr_get_mtu(conId); #else mtu = ble_att_mtu_z2(conId); #endif return mtu; } 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; VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_send_indication(conId, data->Start(), data->DataLength()); #else server_send_data(conId, bt_matter_adapter_service_id, BT_MATTER_ADAPTER_SERVICE_CHAR_INDICATE_CCCD_INDEX - 1, data->Start(), data->DataLength(), GATT_PDU_TYPE_INDICATION); #endif exit: return err; } /******************************************************************************* * Private functions *******************************************************************************/ CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData() { CHIP_ERROR err; uint8_t advData[MAX_ADV_DATA_LEN] = { 0 }; uint8_t advPayload[MAX_ADV_DATA_LEN] = { 0 }; uint8_t deviceIdInfoLength = 0; ChipBLEDeviceIdentificationInfo deviceIdInfo; uint8_t index = 0; uint16_t adv_int_min; uint16_t adv_int_max; // 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; } /**************** 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++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) advData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value advData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 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)); 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; } else { adv_int_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; adv_int_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; } #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_config_adv(adv_int_min, adv_int_max, advData, index); #else le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MIN, sizeof(adv_int_min), &adv_int_min); le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MAX, sizeof(adv_int_max), &adv_int_max); le_adv_set_param(GAP_PARAM_ADV_DATA, sizeof(advData), (void *) advData); // set advData #endif exit: return err; } CHIP_ERROR BLEManagerImpl::StartAdvertising() { CHIP_ERROR err = CHIP_NO_ERROR; err = ConfigureAdvertisingData(); SuccessOrExit(err); // Start advertising #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_start_adv(); #else le_adv_stop(); vTaskDelay(100); le_adv_start(); #endif mFlags.Set(Flags::kAdvertising); mFlags.Clear(Flags::kRestartAdvertising); if (err == CHIP_NO_ERROR) { ChipDeviceEvent advChange; advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; PlatformMgr().PostEventOrDie(&advChange); } exit: return err; } CHIP_ERROR BLEManagerImpl::StopAdvertising() { CHIP_ERROR err; // Stop advertising #if defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER matter_blemgr_stop_adv(); #else le_adv_stop(); #endif // Change flag status to the 'not Advertising state' if (mFlags.Has(Flags::kAdvertising)) { mFlags.Clear(Flags::kAdvertising); mFlags.Set(Flags::kFastAdvertisingEnabled); ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); // Post a CHIPoBLEAdvertisingChange(Stopped) event. { ChipDeviceEvent advChange; advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; PlatformMgr().PostEventOrDie(&advChange); } } return CHIP_NO_ERROR; } CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) { switch (bleErr) { case 0: return CHIP_NO_ERROR; default: return CHIP_ERROR_INCORRECT_STATE; } } void BLEManagerImpl::DriveBLEState() { CHIP_ERROR err = CHIP_NO_ERROR; // Check if BLE stack is initialized VerifyOrExit(mFlags.Has(Flags::kAMEBABLEStackInitialized), /* */); // 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); ChipLogProgress(DeviceLayer, "Started BLE Advertising"); } } // Otherwise, stop advertising if it is enabled. else if (mFlags.Has(Flags::kAdvertising)) { err = StopAdvertising(); SuccessOrExit(err); ChipLogProgress(DeviceLayer, "Stopped BLE 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::InitSubscribed() { for (uint16_t i = 0; i < kMaxConnections; i++) { mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; } } CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) { uint16_t freeIndex = kMaxConnections; for (uint16_t i = 0; i < kMaxConnections; i++) { if (mSubscribedConIds[i] == conId) { return CHIP_NO_ERROR; } else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex) { freeIndex = i; } } if (freeIndex < kMaxConnections) { mSubscribedConIds[freeIndex] = conId; return CHIP_NO_ERROR; } else { return CHIP_ERROR_NO_MEMORY; } } bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) { for (uint16_t i = 0; i < kMaxConnections; i++) { if (mSubscribedConIds[i] == conId) { mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; return true; } } return false; } bool BLEManagerImpl::IsSubscribed(uint16_t conId) { if (conId != BLE_CONNECTION_UNINITIALIZED) { for (uint16_t i = 0; i < kMaxConnections; i++) { if (mSubscribedConIds[i] == conId) { 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 defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING void BLEManagerImpl::HandleC3CharRead(uint8_t ** pp_value, uint16_t * p_len) { CHIP_ERROR err = CHIP_NO_ERROR; PacketBufferHandle bufferHandle; BitFlags additionalDataFields; AdditionalDataPayloadGeneratorParams additionalDataPayloadParams; #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 && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */ err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, bufferHandle, additionalDataFields); SuccessOrExit(err); *pp_value = bufferHandle->Start(); *p_len = bufferHandle->DataLength(); exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data (%s)", __func__); } return; } #endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */ CHIP_ERROR BLEManagerImpl::matter_blemgr_gap_connect_cb(uint8_t conn_id) { CHIP_ERROR err = CHIP_NO_ERROR; err = sInstance.HandleGAPConnect((uint16_t) conn_id); if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; } // Schedule DriveBLEState() to run. PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } CHIP_ERROR BLEManagerImpl::matter_blemgr_gap_disconnect_cb(uint8_t conn_id, uint16_t disc_cause) { CHIP_ERROR err = CHIP_NO_ERROR; err = sInstance.HandleGAPDisconnect((uint16_t) conn_id, disc_cause); if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; } // Schedule DriveBLEState() to run. PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } void BLEManagerImpl::matter_blemgr_rx_char_write_cb(uint8_t conn_id, uint8_t * p_value, uint16_t len) { sInstance.HandleRXCharWrite(p_value, len, conn_id); PlatformMgr().ScheduleWork(DriveBLEState, 0); } void BLEManagerImpl::matter_blemgr_tx_char_cccd_write_cb(uint8_t conn_id, uint8_t indicationsEnabled, uint8_t notificationsEnabled) { sInstance.HandleTXCharCCCDWrite(static_cast(conn_id), static_cast(indicationsEnabled), static_cast(notificationsEnabled)); PlatformMgr().ScheduleWork(DriveBLEState, 0); } CHIP_ERROR BLEManagerImpl::matter_blemgr_tx_complete_cb(uint8_t conn_id) { CHIP_ERROR err = CHIP_NO_ERROR; err = sInstance.HandleTXComplete(static_cast(conn_id)); PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } void BLEManagerImpl::matter_blemgr_c3_char_read_cb(uint8_t ** pp_value, uint16_t * p_len) { #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING sInstance.HandleC3CharRead(pp_value, p_len); #else *pp_value = NULL; *p_len = 0; #endif PlatformMgr().ScheduleWork(DriveBLEState, 0); } int BLEManagerImpl::matter_blemgr_callback_dispatcher(void * param, T_MATTER_BLEMGR_CALLBACK_TYPE cb_type, void * p_cb_data) { BLEManagerImpl * blemgr = static_cast(param); switch (cb_type) { case MATTER_BLEMGR_GAP_CONNECT_CB: { T_MATTER_BLEMGR_GAP_CONNECT_CB_ARG * gap_connect_cb_arg = (T_MATTER_BLEMGR_GAP_CONNECT_CB_ARG *) p_cb_data; blemgr->matter_blemgr_gap_connect_cb(gap_connect_cb_arg->conn_id); } break; case MATTER_BLEMGR_GAP_DISCONNECT_CB: { T_MATTER_BLEMGR_GAP_DISCONNECT_CB_ARG * gap_disconnect_cb_arg = (T_MATTER_BLEMGR_GAP_DISCONNECT_CB_ARG *) p_cb_data; blemgr->matter_blemgr_gap_disconnect_cb(gap_disconnect_cb_arg->conn_id, gap_disconnect_cb_arg->disc_cause); } break; case MATTER_BLEMGR_RX_CHAR_WRITE_CB: { T_MATTER_BLEMGR_RX_CHAR_WRITE_CB_ARG * rx_char_write_cb_arg = (T_MATTER_BLEMGR_RX_CHAR_WRITE_CB_ARG *) p_cb_data; blemgr->matter_blemgr_rx_char_write_cb(rx_char_write_cb_arg->conn_id, rx_char_write_cb_arg->p_value, rx_char_write_cb_arg->len); } break; case MATTER_BLEMGR_TX_CHAR_CCCD_WRITE_CB: { T_MATTER_BLEMGR_TX_CHAR_CCCD_WRITE_CB_ARG * tx_char_cccd_write_cb_arg = (T_MATTER_BLEMGR_TX_CHAR_CCCD_WRITE_CB_ARG *) p_cb_data; blemgr->matter_blemgr_tx_char_cccd_write_cb(tx_char_cccd_write_cb_arg->conn_id, tx_char_cccd_write_cb_arg->indicationsEnabled, tx_char_cccd_write_cb_arg->notificationsEnabled); } break; case MATTER_BLEMGR_TX_COMPLETE_CB: { T_MATTER_BLEMGR_TX_COMPLETE_CB_ARG * tx_complete_cb_arg = (T_MATTER_BLEMGR_TX_COMPLETE_CB_ARG *) p_cb_data; blemgr->matter_blemgr_tx_complete_cb(tx_complete_cb_arg->conn_id); } break; case MATTER_BLEMGR_C3_CHAR_READ_CB: { T_MATTER_BLEMGR_C3_CHAR_READ_CB_ARG * c3_char_read_cb_arg = (T_MATTER_BLEMGR_C3_CHAR_READ_CB_ARG *) p_cb_data; blemgr->matter_blemgr_c3_char_read_cb(c3_char_read_cb_arg->pp_value, c3_char_read_cb_arg->p_len); } default: break; } return 0; } #else // not defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING void BLEManagerImpl::HandleC3CharRead(TBTCONFIG_CALLBACK_DATA * p_data) { CHIP_ERROR err = CHIP_NO_ERROR; PacketBufferHandle bufferHandle; BitFlags additionalDataFields; AdditionalDataPayloadGeneratorParams additionalDataPayloadParams; #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 && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */ err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, bufferHandle, additionalDataFields); SuccessOrExit(err); p_data->msg_data.write.p_value = bufferHandle->Start(); p_data->msg_data.write.len = bufferHandle->DataLength(); exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data (%s)", __func__); } return; } #endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */ CHIP_ERROR BLEManagerImpl::ble_svr_gap_msg_event(void * param, T_IO_MSG * p_gap_msg) { T_LE_GAP_MSG gap_msg; memcpy(&gap_msg, &p_gap_msg->u.param, sizeof(p_gap_msg->u.param)); CHIP_ERROR err = CHIP_NO_ERROR; uint16_t conn_id = gap_msg.msg_data.gap_conn_state_change.conn_id; uint16_t new_state = gap_msg.msg_data.gap_conn_state_change.new_state; uint16_t disc_cause = gap_msg.msg_data.gap_conn_state_change.disc_cause; switch (p_gap_msg->subtype) { case GAP_MSG_LE_CONN_STATE_CHANGE: /* A new connection was established or a connection attempt failed */ if (new_state == GAP_CONN_STATE_CONNECTED) { err = sInstance.HandleGAPConnect(conn_id); SuccessOrExit(err); } else if (new_state == GAP_CONN_STATE_DISCONNECTED) { err = sInstance.HandleGAPDisconnect(conn_id, disc_cause); SuccessOrExit(err); } break; case GAP_MSG_LE_CONN_MTU_INFO: // BLE_GAP_EVENT_MTU: break; default: break; } exit: if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; } // Schedule DriveBLEState() to run. PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } CHIP_ERROR BLEManagerImpl::ble_svr_gap_event(void * param, int cb_type, void * p_cb_data) { CHIP_ERROR err = CHIP_NO_ERROR; T_LE_CB_DATA * p_data = (T_LE_CB_DATA *) p_cb_data; switch (cb_type) { #if defined(CONFIG_PLATFORM_8721D) case GAP_MSG_LE_DATA_LEN_CHANGE_INFO: APP_PRINT_INFO3("GAP_MSG_LE_DATA_LEN_CHANGE_INFO: conn_id %d, tx octets 0x%x, max_tx_time 0x%x", p_data->p_le_data_len_change_info->conn_id, p_data->p_le_data_len_change_info->max_tx_octets, p_data->p_le_data_len_change_info->max_tx_time); break; #endif case GAP_MSG_LE_MODIFY_WHITE_LIST: break; default: break; } return err; } CHIP_ERROR BLEManagerImpl::gatt_svr_chr_access(void * param, T_SERVER_ID service_id, TBTCONFIG_CALLBACK_DATA * p_data) { CHIP_ERROR err = CHIP_NO_ERROR; if (service_id == SERVICE_PROFILE_GENERAL_ID) { T_SERVER_APP_CB_DATA * p_param = (T_SERVER_APP_CB_DATA *) p_data; switch (p_param->eventId) { case PROFILE_EVT_SRV_REG_COMPLETE: // srv register result event. break; case PROFILE_EVT_SEND_DATA_COMPLETE: err = sInstance.HandleTXComplete(p_param->event_data.send_data_result.conn_id); break; default: break; } } else { uint8_t conn_id = p_data->conn_id; T_SERVICE_CALLBACK_TYPE msg_type = p_data->msg_type; uint8_t * p_value = p_data->msg_data.write.p_value; uint16_t len = p_data->msg_data.write.len; BLEManagerImpl * blemgr = static_cast(param); switch (msg_type) { case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE: #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING sInstance.HandleC3CharRead(p_data); #endif break; case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE: sInstance.HandleRXCharWrite(p_value, len, conn_id); break; case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: { TSIMP_CALLBACK_DATA * pp_data; pp_data = (TSIMP_CALLBACK_DATA *) p_data; switch (pp_data->msg_data.notification_indification_index) { case SIMP_NOTIFY_INDICATE_V3_ENABLE: { sInstance.HandleTXCharCCCDWrite(conn_id, 1, 0); } break; case SIMP_NOTIFY_INDICATE_V3_DISABLE: { sInstance.HandleTXCharCCCDWrite(conn_id, 0, 0); } break; } } break; default: break; } } PlatformMgr().ScheduleWork(DriveBLEState, 0); return err; } int BLEManagerImpl::ble_callback_dispatcher(void * param, void * p_cb_data, int type, T_CHIP_BLEMGR_CALLBACK_TYPE callback_type) { BLEManagerImpl * blemgr = static_cast(param); switch (callback_type) { case CB_PROFILE_CALLBACK: blemgr->gatt_svr_chr_access(param, type, (TBTCONFIG_CALLBACK_DATA *) p_cb_data); break; case CB_GAP_CALLBACK: blemgr->ble_svr_gap_event(param, type, p_cb_data); break; case CB_GAP_MSG_CALLBACK: blemgr->ble_svr_gap_msg_event(param, (T_IO_MSG *) p_cb_data); break; default: break; } return 0; } #endif // defined(CONFIG_MATTER_BLEMGR_ADAPTER) && CONFIG_MATTER_BLEMGR_ADAPTER } // namespace Internal } // namespace DeviceLayer } // namespace chip #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE