From beac19cc92984bd2fb34a1d68889d85f11b66d9a Mon Sep 17 00:00:00 2001 From: h2zero Date: Sun, 10 Nov 2024 13:31:37 -0700 Subject: [PATCH] [BREAKING] - Refactor NimBLEUtils * Add functions `NimBLEUtils::taskWait` and `NimBLEUtils::taskRelease` to simplify task blocking/messaging. * `NimBLEUtils::buildHexData` replaced with `NimBLEUtils::dataToHexString` * Add missing GAP event strings. * Add missing return code strings. * `NimBLEUtils::dumpGapEvent` function removed. * Event/error code strings optimized. --- src/NimBLEAdvertisedDevice.cpp | 22 +- src/NimBLEClient.cpp | 87 ++-- src/NimBLEClient.h | 4 +- src/NimBLERemoteCharacteristic.cpp | 36 +- src/NimBLERemoteService.cpp | 35 +- src/NimBLERemoteValueAttribute.cpp | 45 +- src/NimBLEScan.cpp | 14 +- src/NimBLEScan.h | 2 +- src/NimBLEServer.cpp | 46 +- src/NimBLEServer.h | 2 +- src/NimBLEUtils.cpp | 657 +++++++++++++++-------------- src/NimBLEUtils.h | 55 ++- 12 files changed, 481 insertions(+), 524 deletions(-) diff --git a/src/NimBLEAdvertisedDevice.cpp b/src/NimBLEAdvertisedDevice.cpp index e815564..fed8bf6 100644 --- a/src/NimBLEAdvertisedDevice.cpp +++ b/src/NimBLEAdvertisedDevice.cpp @@ -253,7 +253,7 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() const { * @return The number of addresses. */ uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() const { - uint8_t count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR); return count; @@ -269,7 +269,7 @@ NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) const { uint8_t count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc); if (count < index + 1) { index -= count; - count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc); + count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc); } if (count > 0 && data_loc != ULONG_MAX) { @@ -368,14 +368,14 @@ size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t* bytes) co } index -= found; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc); + found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc); if (found > index) { *bytes = 4; return data_loc; } index -= found; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc); + found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc); if (found > index) { *bytes = 16; return data_loc; @@ -389,7 +389,7 @@ size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t* bytes) co * @return The number of service data UUIDS in the vector. */ uint8_t NimBLEAdvertisedDevice::getServiceDataCount() const { - uint8_t count = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32); count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128); @@ -448,7 +448,7 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) const { * @return The count of services in the advertising packet. */ uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() const { - uint8_t count = findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16); count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32); count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32); @@ -695,11 +695,9 @@ std::string NimBLEAdvertisedDevice::toString() const { } if (haveManufacturerData()) { - char* pHex = - NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); - res += ", manufacturer data: "; - res += pHex; - free(pHex); + auto mfgData = getManufacturerData(); + res += ", manufacturer data: "; + res += NimBLEUtils::dataToHexString(reinterpret_cast(mfgData.data()), mfgData.length()); } if (haveServiceUUID()) { @@ -714,7 +712,7 @@ std::string NimBLEAdvertisedDevice::toString() const { } if (haveServiceData()) { - uint8_t count = getServiceDataCount(); + uint8_t count = getServiceDataCount(); res += "\nService Data:"; for (uint8_t i = 0; i < count; i++) { res += "\nUUID: " + std::string(getServiceDataUUID(i)); diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 8c141c0..da4b58f 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -201,11 +201,10 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, deleteServices(); } - int rc = 0; - m_asyncConnect = asyncConnect; - m_exchangeMTU = exchangeMTU; - TaskHandle_t curTask = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {this, curTask, 0, nullptr}; + int rc = 0; + m_asyncConnect = asyncConnect; + m_exchangeMTU = exchangeMTU; + NimBLETaskData taskData(this); if (!asyncConnect) { m_pTaskData = &taskData; } @@ -276,12 +275,8 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, return true; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(curTask, ULONG_MAX); -# endif // Wait for the connect timeout time +1 second for the connection to complete - if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { + if (!NimBLEUtils::taskWait(*m_pTaskData, m_connectTimeout + 1000)) { m_pTaskData = nullptr; // If a connection was made but no response from MTU exchange; disconnect if (isConnected()) { @@ -296,9 +291,9 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, return false; - } else if (taskData.rc != 0) { - m_lastErr = taskData.rc; - NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", taskData.rc, NimBLEUtils::returnCodeToString(taskData.rc)); + } else if (taskData.m_flags != 0) { + m_lastErr = taskData.m_flags; + NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", m_lastErr, NimBLEUtils::returnCodeToString(m_lastErr)); // If the failure was not a result of a disconnection, make sure we disconnect now to avoid dangling connections if (isConnected()) { disconnect(); @@ -324,9 +319,8 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, */ bool NimBLEClient::secureConnection() const { NIMBLE_LOGD(LOG_TAG, ">> secureConnection()"); - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; - int retryCount = 1; + NimBLETaskData taskData(const_cast(this)); + int retryCount = 1; do { m_pTaskData = &taskData; @@ -337,16 +331,12 @@ bool NimBLEClient::secureConnection() const { return false; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); + NimBLEUtils::taskWait(*m_pTaskData, BLE_NPL_TIME_FOREVER); + } while (taskData.m_flags == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); - if (taskData.rc != 0) { - m_lastErr = taskData.rc; - NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc); + if (taskData.m_flags != 0) { + m_lastErr = taskData.m_flags; + NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.m_flags); return false; } @@ -736,9 +726,8 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { return false; } - int rc = 0; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {this, cur_task, 0, nullptr}; + int rc = 0; + NimBLETaskData taskData(this); if (uuidFilter == nullptr) { rc = ble_gattc_disc_all_svcs(m_connHandle, NimBLEClient::serviceDiscoveredCB, &taskData); @@ -752,24 +741,15 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { return false; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - - // wait until we have all the services - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - m_lastErr = taskData.rc; - - if (taskData.rc == 0) { + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); + rc = taskData.m_flags; + if (rc == 0 || rc == BLE_HS_EDONE) { return true; - } else { - NIMBLE_LOGE(LOG_TAG, - "Could not retrieve services, rc=%d %s", - taskData.rc, - NimBLEUtils::returnCodeToString(taskData.rc)); - return false; } + + m_lastErr = rc; + NIMBLE_LOGE(LOG_TAG, "Could not retrieve services, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } // getServices /** @@ -786,8 +766,8 @@ int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle, error->status, (error->status == 0) ? service->start_handle : -1); - BleTaskData* pTaskData = (BleTaskData*)arg; - NimBLEClient* pClient = (NimBLEClient*)pTaskData->pATT; + NimBLETaskData* pTaskData = (NimBLETaskData*)arg; + NimBLEClient* pClient = (NimBLEClient*)pTaskData->m_pInstance; // Make sure the service discovery is for this device if (pClient->getConnHandle() != connHandle) { @@ -800,15 +780,7 @@ int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle, return 0; } - if (error->status == BLE_HS_EDONE) { - pTaskData->rc = 0; - } else { - NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status)); - pTaskData->rc = error->status; - } - - xTaskNotifyGive(pTaskData->task); - + NimBLEUtils::taskRelease(*pTaskData, error->status); NIMBLE_LOGD(LOG_TAG, "<< Service Discovered"); return error->status; } @@ -1204,10 +1176,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { } // Switch if (pClient->m_pTaskData != nullptr) { - pClient->m_pTaskData->rc = rc; - if (pClient->m_pTaskData->task) { - xTaskNotifyGive(pClient->m_pTaskData->task); - } + NimBLEUtils::taskRelease(*pClient->m_pTaskData, rc); pClient->m_pTaskData = nullptr; } diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index 7b0b8e9..99b4dde 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -37,7 +37,7 @@ class NimBLEAdvertisedDevice; class NimBLEAttValue; class NimBLEClientCallbacks; class NimBLEConnInfo; -struct BleTaskData; +struct NimBLETaskData; /** * @brief A model of a BLE client. @@ -112,7 +112,7 @@ class NimBLEClient { NimBLEAddress m_peerAddress; mutable int m_lastErr; int32_t m_connectTimeout; - mutable BleTaskData* m_pTaskData; + mutable NimBLETaskData* m_pTaskData; std::vector m_svcVec; NimBLEClientCallbacks* m_pClientCallbacks; uint16_t m_connHandle; diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index fa1e8c5..3d812ac 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -65,8 +65,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB( NIMBLE_LOGD(LOG_TAG, "Descriptor Discovery >> status: %d handle: %d", rc, (rc == 0) ? dsc->handle : -1); auto filter = (desc_filter_t*)arg; - auto pTaskData = (BleTaskData*)filter->task_data; - const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->pATT; + auto pTaskData = (NimBLETaskData*)filter->task_data; + const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->m_pInstance; const NimBLEUUID* uuidFilter = filter->uuid; if (pChr->getHandle() != chr_val_handle) { @@ -85,12 +85,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB( pChr->m_vDescriptors.push_back(new NimBLERemoteDescriptor(pChr, dsc)); } - if (rc != 0) { - pTaskData->rc = rc == BLE_HS_EDONE ? 0 : rc; - NIMBLE_LOGD(LOG_TAG, "<< Descriptor Discovery"); - xTaskNotifyGive(pTaskData->task); - } - + NimBLEUtils::taskRelease(*pTaskData, rc); + NIMBLE_LOGD(LOG_TAG, "<< Descriptor Discovery"); return rc; } @@ -101,9 +97,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB( bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilter) const { NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; - desc_filter_t filter = {uuidFilter, &taskData}; + NimBLETaskData taskData(const_cast(this)); + desc_filter_t filter = {uuidFilter, &taskData}; int rc = ble_gattc_disc_all_dscs(getClient()->getConnHandle(), getHandle(), @@ -115,22 +110,15 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilte return false; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - if (taskData.rc != 0) { - NIMBLE_LOGE(LOG_TAG, - "<< retrieveDescriptors(): failed: rc=%d %s", - taskData.rc, - NimBLEUtils::returnCodeToString(taskData.rc)); - } else { + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); + rc = taskData.m_flags; + if (rc == 0 || rc == BLE_HS_EDONE) { NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): found %d descriptors.", m_vDescriptors.size()); + return true; } - return taskData.rc == 0; + NIMBLE_LOGE(LOG_TAG, "<< retrieveDescriptors(): failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } // retrieveDescriptors /** diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index a31d998..4517da8 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -145,8 +145,8 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, const ble_gatt_chr* chr, void* arg) { NIMBLE_LOGD(LOG_TAG, "Characteristic Discovery >>"); - auto pTaskData = (BleTaskData*)arg; - const auto pSvc = (NimBLERemoteService*)pTaskData->pATT; + auto pTaskData = (NimBLETaskData*)arg; + const auto pSvc = (NimBLERemoteService*)pTaskData->m_pInstance; // Make sure the discovery is for this device if (pSvc->getClient()->getConnHandle() != conn_handle) { @@ -155,12 +155,11 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, if (error->status == 0) { pSvc->m_vChars.push_back(new NimBLERemoteCharacteristic(pSvc, chr)); - } else { - pTaskData->rc = error->status == BLE_HS_EDONE ? 0 : error->status; - NIMBLE_LOGD(LOG_TAG, "<< Characteristic Discovery"); - xTaskNotifyGive(pTaskData->task); + return 0; } + NimBLEUtils::taskRelease(*pTaskData, error->status); + NIMBLE_LOGD(LOG_TAG, "<< Characteristic Discovery"); return error->status; } @@ -171,9 +170,8 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, */ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) const { NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics()"); - int rc = 0; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; + int rc = 0; + NimBLETaskData taskData(const_cast(this)); if (uuidFilter == nullptr) { rc = ble_gattc_disc_all_chrs(m_pClient->getConnHandle(), @@ -190,21 +188,20 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) &taskData); } - if (rc == 0) { -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_chrs rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } - if (taskData.rc != 0) { - NIMBLE_LOGE(LOG_TAG, "<< retrieveCharacteristics() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - } else { + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); + rc = taskData.m_flags; + if (rc == 0 || rc == BLE_HS_EDONE) { NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); + return true; } - return taskData.rc == 0; + NIMBLE_LOGE(LOG_TAG, "<< retrieveCharacteristics() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } // retrieveCharacteristics /** diff --git a/src/NimBLERemoteValueAttribute.cpp b/src/NimBLERemoteValueAttribute.cpp index aca3fed..7d4089f 100644 --- a/src/NimBLERemoteValueAttribute.cpp +++ b/src/NimBLERemoteValueAttribute.cpp @@ -20,11 +20,10 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, NIMBLE_LOGD(LOG_TAG, ">> writeValue()"); const NimBLEClient* pClient = getClient(); - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {const_cast(this), cur_task, 0, nullptr}; int retryCount = 1; int rc = 0; uint16_t mtu = pClient->getMTU() - 3; + NimBLETaskData taskData(const_cast(this)); // Check if the data length is longer than we can write in one connection event. // If so we must do a long write which requires a response. @@ -51,13 +50,8 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, goto Done; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); + rc = taskData.m_flags; switch (rc) { case 0: case BLE_HS_EDONE: @@ -83,7 +77,7 @@ Done: if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "<< writeValue failed, rc: %d %s", rc, NimBLEUtils::returnCodeToString(rc)); } else { - NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc); + NIMBLE_LOGD(LOG_TAG, "<< writeValue"); } return (rc == 0); @@ -94,16 +88,15 @@ Done: * @return success == 0 or error code. */ int NimBLERemoteValueAttribute::onWriteCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) { - auto pTaskData = static_cast(arg); - const auto pAtt = static_cast(pTaskData->pATT); + auto pTaskData = static_cast(arg); + const auto pAtt = static_cast(pTaskData->m_pInstance); if (pAtt->getClient()->getConnHandle() != conn_handle) { return 0; } NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d", error->status); - pTaskData->rc = error->status; - xTaskNotifyGive(pTaskData->task); + NimBLEUtils::taskRelease(*pTaskData, error->status); return 0; } @@ -119,8 +112,7 @@ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const { const NimBLEClient* pClient = getClient(); int rc = 0; int retryCount = 1; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {const_cast(this), cur_task, 0, &value}; + NimBLETaskData taskData(const_cast(this), 0, &value); do { rc = ble_gattc_read_long(pClient->getConnHandle(), getHandle(), 0, NimBLERemoteValueAttribute::onReadCB, &taskData); @@ -128,13 +120,8 @@ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const { goto Done; } -# ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -# endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); + rc = taskData.m_flags; switch (rc) { case 0: case BLE_HS_EDONE: @@ -169,7 +156,7 @@ Done: if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "<< readValue failed rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } else { - NIMBLE_LOGD(LOG_TAG, "<< readValue rc=%d", rc); + NIMBLE_LOGD(LOG_TAG, "<< readValue"); } return value; @@ -180,8 +167,8 @@ Done: * @return success == 0 or error code. */ int NimBLERemoteValueAttribute::onReadCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) { - auto pTaskData = static_cast(arg); - const auto pAtt = static_cast(pTaskData->pATT); + auto pTaskData = static_cast(arg); + const auto pAtt = static_cast(pTaskData->m_pInstance); if (pAtt->getClient()->getConnHandle() != conn_handle) { return 0; @@ -192,7 +179,7 @@ int NimBLERemoteValueAttribute::onReadCB(uint16_t conn_handle, const ble_gatt_er if (rc == 0) { if (attr) { - auto valBuf = static_cast(pTaskData->buf); + auto valBuf = static_cast(pTaskData->m_pBuf); uint16_t data_len = OS_MBUF_PKTLEN(attr->om); if ((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) { rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; @@ -204,9 +191,7 @@ int NimBLERemoteValueAttribute::onReadCB(uint16_t conn_handle, const ble_gatt_er } } - pTaskData->rc = rc; - xTaskNotifyGive(pTaskData->task); - + NimBLEUtils::taskRelease(*pTaskData, rc); return rc; } // onReadCB diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index 56d49a0..d3fc1c6 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -167,8 +167,7 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { } if(pScan->m_pTaskData != nullptr) { - pScan->m_pTaskData->rc = event->disc_complete.reason; - xTaskNotifyGive(pScan->m_pTaskData->task); + NimBLEUtils::taskRelease(*pScan->m_pTaskData, event->disc_complete.reason); } return 0; @@ -393,7 +392,7 @@ bool NimBLEScan::stop() { } if(m_pTaskData != nullptr) { - xTaskNotifyGive(m_pTaskData->task); + NimBLEUtils::taskRelease(*m_pTaskData); } NIMBLE_LOGD(LOG_TAG, "<< stop()"); @@ -461,16 +460,11 @@ NimBLEScanResults NimBLEScan::getResults(uint32_t duration, bool is_continue) { NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); } - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - BleTaskData taskData = {nullptr, cur_task, 0, nullptr}; + NimBLETaskData taskData; m_pTaskData = &taskData; if(start(duration, is_continue)) { -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); } m_pTaskData = nullptr; diff --git a/src/NimBLEScan.h b/src/NimBLEScan.h index b7550ea..47dd5c4 100644 --- a/src/NimBLEScan.h +++ b/src/NimBLEScan.h @@ -94,7 +94,7 @@ private: bool m_ignoreResults; NimBLEScanResults m_scanResults; uint32_t m_duration; - BleTaskData *m_pTaskData; + NimBLETaskData *m_pTaskData; uint8_t m_maxResults; }; diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 1c2ba39..9e9aab7 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -368,8 +368,8 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - BleTaskData *pTaskData = (BleTaskData*)arg; - std::string *name = (std::string*)pTaskData->buf; + NimBLETaskData *pTaskData = (NimBLETaskData*)arg; + std::string *name = (std::string*)pTaskData->m_pBuf; int rc = error->status; if (rc == 0) { @@ -380,16 +380,15 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, } if (rc == BLE_HS_EDONE) { - // No ask means this was read for a callback. - if (pTaskData->task == nullptr) { - NimBLEServer* pServer = (NimBLEServer*)pTaskData->pATT; + if (pTaskData->m_flags != -1) { + NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance; NimBLEConnInfo peerInfo{}; ble_gap_conn_find(conn_handle, &peerInfo.m_desc); - // Use the rc value as a flag to indicate which callback should be called. - if (pTaskData->rc == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) { + // check the flag to indicate which callback should be called. + if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) { pServer->m_pServerCallbacks->onConnect(pServer, peerInfo, *name); - } else if (pTaskData->rc == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) { + } else if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) { pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo, *name); } } @@ -397,9 +396,8 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, NIMBLE_LOGE(LOG_TAG, "NimBLEServerPeerNameCB rc=%d; %s", rc, NimBLEUtils::returnCodeToString(rc)); } - if (pTaskData->task != nullptr) { - pTaskData->rc = rc; - xTaskNotifyGive(pTaskData->task); + if (pTaskData->m_flags == -1) { + NimBLEUtils::taskRelease(*pTaskData, rc); } else { // If the read was triggered for callback use then these were allocated. delete name; @@ -412,16 +410,16 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle, /** * @brief Internal method that sends the read command. */ -std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, TaskHandle_t task, int cb_type) { +std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, int cb_type) { std::string *buf = new std::string{}; - BleTaskData *taskData = new BleTaskData{this, task, cb_type, buf}; + NimBLETaskData *pTaskData = new NimBLETaskData(this, cb_type, buf); ble_uuid16_t uuid {{BLE_UUID_TYPE_16}, BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME}; int rc = ble_gattc_read_by_uuid(conn_handle, 1, 0xffff, &uuid.u, NimBLEServer::peerNameCB, - taskData); + pTaskData); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_read_by_uuid rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); NimBLEConnInfo peerInfo{}; @@ -432,17 +430,13 @@ std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, TaskHandle_t m_pServerCallbacks->onAuthenticationComplete(peerInfo, *buf); } delete buf; - delete taskData; - } else if (task != nullptr) { -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData->rc; - std::string name{*(std::string*)taskData->buf}; + delete pTaskData; + } else if (cb_type == -1) { + NimBLEUtils::taskWait(*pTaskData, BLE_NPL_TIME_FOREVER); + rc = pTaskData->m_flags; + std::string name{*(std::string*)pTaskData->m_pBuf}; delete buf; - delete taskData; + delete pTaskData; if (rc != 0 && rc != BLE_HS_EDONE) { NIMBLE_LOGE(LOG_TAG, "getPeerName rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); @@ -461,7 +455,7 @@ std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, TaskHandle_t * @note This is a blocking call and should NOT be called from any callbacks! */ std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) { - std::string name = getPeerNameInternal(connInfo.getConnHandle(), xTaskGetCurrentTaskHandle()); + std::string name = getPeerNameInternal(connInfo.getConnHandle()); return name; } @@ -500,7 +494,6 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { if (pServer->m_getPeerNameOnConnect) { pServer->getPeerNameInternal(event->connect.conn_handle, - nullptr, NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB); } else { pServer->m_pServerCallbacks->onConnect(pServer, peerInfo); @@ -661,7 +654,6 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { if (pServer->m_getPeerNameOnConnect) { pServer->getPeerNameInternal(event->enc_change.conn_handle, - nullptr, NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB); } else { pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo); diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index 936daa8..86700e1 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -115,7 +115,7 @@ private: static int handleGapEvent(struct ble_gap_event *event, void *arg); static int peerNameCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); - std::string getPeerNameInternal(uint16_t conn_handle, TaskHandle_t task, int cb_type = -1); + std::string getPeerNameInternal(uint16_t conn_handle, int cb_type = -1); void serviceChanged(); void resetGATT(); bool setIndicateWait(uint16_t conn_handle); diff --git a/src/NimBLEUtils.cpp b/src/NimBLEUtils.cpp index 936a9d8..4537360 100644 --- a/src/NimBLEUtils.cpp +++ b/src/NimBLEUtils.cpp @@ -9,9 +9,9 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) -#include "NimBLEUtils.h" -#include "NimBLEAddress.h" -#include "NimBLELog.h" +# include "NimBLEUtils.h" +# include "NimBLEAddress.h" +# include "NimBLELog.h" # if defined(CONFIG_NIMBLE_CPP_IDF) # include "host/ble_hs.h" @@ -20,474 +20,497 @@ # endif /**** FIX COMPILATION ****/ -#undef min -#undef max +# undef min +# undef max /**************************/ -#include +# include +# include static const char* LOG_TAG = "NimBLEUtils"; +/** + * @brief Blocks the calling task until released or timeout. + * @param [in] taskData A pointer to the task data structure. + * @param [in] timeout The time to wait in milliseconds. + * @return True if the task completed, false if the timeout was reached. + */ +bool NimBLEUtils::taskWait(const NimBLETaskData& taskData, uint32_t timeout) { + ble_npl_time_t ticks; + if (timeout == BLE_NPL_TIME_FOREVER) { + ticks = BLE_NPL_TIME_FOREVER; + } else { + ble_npl_time_ms_to_ticks(timeout, &ticks); + } + +# if defined INC_FREERTOS_H + taskData.m_pHandle = xTaskGetCurrentTaskHandle(); +# ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(static_cast(taskData.m_pHandle), ULONG_MAX); +# endif + return ulTaskNotifyTake(pdTRUE, ticks) == pdTRUE; + +# else + ble_npl_sem sem; + ble_npl_error_t err = ble_npl_sem_init(&sem, 0); + if (err != BLE_NPL_OK) { + NIMBLE_LOGE(LOG_TAG, "Failed to create semaphore"); + return false; + } + + taskData.m_pHandle = &sem; + err = ble_npl_sem_pend(&sem, ticks); + ble_npl_sem_deinit(&sem); + taskData.m_pHandle = nullptr; + return err == BLE_NPL_OK; +# endif +} // taskWait + +/** + * @brief Release a task. + * @param [in] taskData A pointer to the task data structure. + * @param [in] flags A return value to set in the task data structure. + */ +void NimBLEUtils::taskRelease(const NimBLETaskData& taskData, int flags) { + if (taskData.m_pHandle != nullptr) { + taskData.m_flags = flags; +# if defined INC_FREERTOS_H + xTaskNotifyGive(static_cast(taskData.m_pHandle)); +# else + ble_npl_sem_release(static_cast(taskData.m_pHandle)); +# endif + } +} // taskRelease + /** * @brief Converts a return code from the NimBLE stack to a text string. * @param [in] rc The return code to convert. * @return A string representation of the return code. */ const char* NimBLEUtils::returnCodeToString(int rc) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) - switch(rc) { +# if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) + switch (rc) { case 0: return "SUCCESS"; case BLE_HS_EAGAIN: - return "Temporary failure; try again."; + return "Temporary failure; try again"; case BLE_HS_EALREADY: - return "Operation already in progress or completed."; + return "Operation already in progress or complete"; case BLE_HS_EINVAL: - return "One or more arguments are invalid."; + return "One or more arguments are invalid"; case BLE_HS_EMSGSIZE: - return "The provided buffer is too small."; + return "Buffer too small"; case BLE_HS_ENOENT: - return "No entry matching the specified criteria."; + return "No matching entry found"; case BLE_HS_ENOMEM: - return "Operation failed due to resource exhaustion."; + return "Not enough memory"; case BLE_HS_ENOTCONN: - return "No open connection with the specified handle."; + return "No open connection with handle"; case BLE_HS_ENOTSUP: - return "Operation disabled at compile time."; + return "Operation disabled at compile time"; case BLE_HS_EAPP: - return "Application callback behaved unexpectedly."; + return "Application error"; case BLE_HS_EBADDATA: - return "Command from peer is invalid."; + return "Invalid command from peer"; case BLE_HS_EOS: - return "Mynewt OS error."; + return "OS error"; case BLE_HS_ECONTROLLER: - return "Event from controller is invalid."; + return "Controller error"; case BLE_HS_ETIMEOUT: - return "Operation timed out."; + return "Operation timed out"; case BLE_HS_EDONE: - return "Operation completed successfully."; + return "Operation completed successfully"; case BLE_HS_EBUSY: - return "Operation cannot be performed until procedure completes."; + return "Busy"; case BLE_HS_EREJECT: - return "Peer rejected a connection parameter update request."; + return "Peer rejected request"; case BLE_HS_EUNKNOWN: - return "Unexpected failure; catch all."; + return "Unknown failure"; case BLE_HS_EROLE: - return "Operation requires different role (e.g., central vs. peripheral)."; + return "Operation requires different role"; case BLE_HS_ETIMEOUT_HCI: - return "HCI request timed out; controller unresponsive."; + return "HCI request timed out"; case BLE_HS_ENOMEM_EVT: - return "Controller failed to send event due to memory exhaustion (combined host-controller only)."; + return "Controller error; not enough memory"; case BLE_HS_ENOADDR: - return "Operation requires an identity address but none configured."; + return "No identity address"; case BLE_HS_ENOTSYNCED: - return "Attempt to use the host before it is synced with controller."; + return "Host not synced with controller"; case BLE_HS_EAUTHEN: - return "Insufficient authentication."; + return "Insufficient authentication"; case BLE_HS_EAUTHOR: - return "Insufficient authorization."; + return "Insufficient authorization"; case BLE_HS_EENCRYPT: - return "Insufficient encryption level."; + return "Insufficient encryption level"; case BLE_HS_EENCRYPT_KEY_SZ: - return "Insufficient key size."; + return "Insufficient key size"; case BLE_HS_ESTORE_CAP: - return "Storage at capacity."; + return "Storage at capacity"; case BLE_HS_ESTORE_FAIL: - return "Storage IO error."; - case (0x0100+BLE_ATT_ERR_INVALID_HANDLE ): - return "The attribute handle given was not valid on this server."; - case (0x0100+BLE_ATT_ERR_READ_NOT_PERMITTED ): - return "The attribute cannot be read."; - case (0x0100+BLE_ATT_ERR_WRITE_NOT_PERMITTED ): - return "The attribute cannot be written."; - case (0x0100+BLE_ATT_ERR_INVALID_PDU ): - return "The attribute PDU was invalid."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHEN ): - return "The attribute requires authentication before it can be read or written."; - case (0x0100+BLE_ATT_ERR_REQ_NOT_SUPPORTED ): - return "Attribute server does not support the request received from the client."; - case (0x0100+BLE_ATT_ERR_INVALID_OFFSET ): - return "Offset specified was past the end of the attribute."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHOR ): - return "The attribute requires authorization before it can be read or written."; - case (0x0100+BLE_ATT_ERR_PREPARE_QUEUE_FULL ): - return "Too many prepare writes have been queued."; - case (0x0100+BLE_ATT_ERR_ATTR_NOT_FOUND ): - return "No attribute found within the given attribute handle range."; - case (0x0100+BLE_ATT_ERR_ATTR_NOT_LONG ): - return "The attribute cannot be read or written using the Read Blob Request."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_KEY_SZ ): - return "The Encryption Key Size used for encrypting this link is insufficient."; - case (0x0100+BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ): - return "The attribute value length is invalid for the operation."; - case (0x0100+BLE_ATT_ERR_UNLIKELY ): - return "The attribute request has encountered an error that was unlikely, could not be completed as requested."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_ENC ): - return "The attribute requires encryption before it can be read or written."; - case (0x0100+BLE_ATT_ERR_UNSUPPORTED_GROUP ): - return "The attribute type is not a supported grouping attribute as defined by a higher layer specification."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_RES ): - return "Insufficient Resources to complete the request."; - case (0x0200+BLE_ERR_UNKNOWN_HCI_CMD ): + return "Storage IO error"; + case BLE_HS_EPREEMPTED: + return "Host preempted"; + case BLE_HS_EDISABLED: + return "Host disabled"; + case BLE_HS_ESTALLED: + return "CoC module is stalled"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INVALID_HANDLE): + return "Invalid attribute handle"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_READ_NOT_PERMITTED): + return "The attribute cannot be read"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_WRITE_NOT_PERMITTED): + return "The attribute cannot be written"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INVALID_PDU): + return "Invalid attribute PDU"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INSUFFICIENT_AUTHEN): + return "Insufficient authentication"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_REQ_NOT_SUPPORTED): + return "Unsupported request"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INVALID_OFFSET): + return "Invalid offset"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INSUFFICIENT_AUTHOR): + return "Insufficient authorization"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_PREPARE_QUEUE_FULL): + return "Prepare write queue full"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_ATTR_NOT_FOUND): + return "Attribute not found"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_ATTR_NOT_LONG): + return "Long read not supported"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INSUFFICIENT_KEY_SZ): + return "Insufficient encryption key size"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN): + return "Invalid attribute value length"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_UNLIKELY): + return "Unlikely attribute error"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INSUFFICIENT_ENC): + return "Insufficient encryption"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_UNSUPPORTED_GROUP): + return "Not a supported grouping attribute type"; + case (BLE_HS_ERR_ATT_BASE + BLE_ATT_ERR_INSUFFICIENT_RES): + return "Insufficient Resources"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNKNOWN_HCI_CMD): return "Unknown HCI Command"; - case (0x0200+BLE_ERR_UNK_CONN_ID ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNK_CONN_ID): return "Unknown Connection Identifier"; - case (0x0200+BLE_ERR_HW_FAIL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_HW_FAIL): return "Hardware Failure"; - case (0x0200+BLE_ERR_PAGE_TMO ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_PAGE_TMO): return "Page Timeout"; - case (0x0200+BLE_ERR_AUTH_FAIL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_AUTH_FAIL): return "Authentication Failure"; - case (0x0200+BLE_ERR_PINKEY_MISSING ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING): return "PIN or Key Missing"; - case (0x0200+BLE_ERR_MEM_CAPACITY ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_MEM_CAPACITY): return "Memory Capacity Exceeded"; - case (0x0200+BLE_ERR_CONN_SPVN_TMO ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_SPVN_TMO): return "Connection Timeout"; - case (0x0200+BLE_ERR_CONN_LIMIT ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_LIMIT): return "Connection Limit Exceeded"; - case (0x0200+BLE_ERR_SYNCH_CONN_LIMIT ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_SYNCH_CONN_LIMIT): return "Synchronous Connection Limit To A Device Exceeded"; - case (0x0200+BLE_ERR_ACL_CONN_EXISTS ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_ACL_CONN_EXISTS): return "ACL Connection Already Exists"; - case (0x0200+BLE_ERR_CMD_DISALLOWED ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CMD_DISALLOWED): return "Command Disallowed"; - case (0x0200+BLE_ERR_CONN_REJ_RESOURCES ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_REJ_RESOURCES): return "Connection Rejected due to Limited Resources"; - case (0x0200+BLE_ERR_CONN_REJ_SECURITY ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_REJ_SECURITY): return "Connection Rejected Due To Security Reasons"; - case (0x0200+BLE_ERR_CONN_REJ_BD_ADDR ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_REJ_BD_ADDR): return "Connection Rejected due to Unacceptable BD_ADDR"; - case (0x0200+BLE_ERR_CONN_ACCEPT_TMO ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ACCEPT_TMO): return "Connection Accept Timeout Exceeded"; - case (0x0200+BLE_ERR_UNSUPPORTED ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNSUPPORTED): return "Unsupported Feature or Parameter Value"; - case (0x0200+BLE_ERR_INV_HCI_CMD_PARMS ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_INV_HCI_CMD_PARMS): return "Invalid HCI Command Parameters"; - case (0x0200+BLE_ERR_REM_USER_CONN_TERM ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_REM_USER_CONN_TERM): return "Remote User Terminated Connection"; - case (0x0200+BLE_ERR_RD_CONN_TERM_RESRCS ): - return "Remote Device Terminated Connection due to Low Resources"; - case (0x0200+BLE_ERR_RD_CONN_TERM_PWROFF ): - return "Remote Device Terminated Connection due to Power Off"; - case (0x0200+BLE_ERR_CONN_TERM_LOCAL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_RD_CONN_TERM_RESRCS): + return "Remote Device Terminated Connection; Low Resources"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_RD_CONN_TERM_PWROFF): + return "Remote Device Terminated Connection; Power Off"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_TERM_LOCAL): return "Connection Terminated By Local Host"; - case (0x0200+BLE_ERR_REPEATED_ATTEMPTS ): - return "Repeated Attempts"; - case (0x0200+BLE_ERR_NO_PAIRING ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_REPEATED_ATTEMPTS): + return "Repeated Pairing Attempts"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_NO_PAIRING): return "Pairing Not Allowed"; - case (0x0200+BLE_ERR_UNK_LMP ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNK_LMP): return "Unknown LMP PDU"; - case (0x0200+BLE_ERR_UNSUPP_REM_FEATURE ): - return "Unsupported Remote Feature / Unsupported LMP Feature"; - case (0x0200+BLE_ERR_SCO_OFFSET ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNSUPP_REM_FEATURE): + return "Unsupported Remote Feature"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_SCO_OFFSET): return "SCO Offset Rejected"; - case (0x0200+BLE_ERR_SCO_ITVL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_SCO_ITVL): return "SCO Interval Rejected"; - case (0x0200+BLE_ERR_SCO_AIR_MODE ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_SCO_AIR_MODE): return "SCO Air Mode Rejected"; - case (0x0200+BLE_ERR_INV_LMP_LL_PARM ): - return "Invalid LMP Parameters / Invalid LL Parameters"; - case (0x0200+BLE_ERR_UNSPECIFIED ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_INV_LMP_LL_PARM): + return "Invalid LL Parameters"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNSPECIFIED): return "Unspecified Error"; - case (0x0200+BLE_ERR_UNSUPP_LMP_LL_PARM ): - return "Unsupported LMP Parameter Value / Unsupported LL Parameter Value"; - case (0x0200+BLE_ERR_NO_ROLE_CHANGE ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNSUPP_LMP_LL_PARM): + return "Unsupported LL Parameter Value"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_NO_ROLE_CHANGE): return "Role Change Not Allowed"; - case (0x0200+BLE_ERR_LMP_LL_RSP_TMO ): - return "LMP Response Timeout / LL Response Timeout"; - case (0x0200+BLE_ERR_LMP_COLLISION ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_LMP_LL_RSP_TMO): + return "LL Response Timeout"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_LMP_COLLISION): return "LMP Error Transaction Collision"; - case (0x0200+BLE_ERR_LMP_PDU ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_LMP_PDU): return "LMP PDU Not Allowed"; - case (0x0200+BLE_ERR_ENCRYPTION_MODE ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_ENCRYPTION_MODE): return "Encryption Mode Not Acceptable"; - case (0x0200+BLE_ERR_LINK_KEY_CHANGE ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_LINK_KEY_CHANGE): return "Link Key cannot be Changed"; - case (0x0200+BLE_ERR_UNSUPP_QOS ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNSUPP_QOS): return "Requested QoS Not Supported"; - case (0x0200+BLE_ERR_INSTANT_PASSED ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_INSTANT_PASSED): return "Instant Passed"; - case (0x0200+BLE_ERR_UNIT_KEY_PAIRING ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNIT_KEY_PAIRING): return "Pairing With Unit Key Not Supported"; - case (0x0200+BLE_ERR_DIFF_TRANS_COLL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_DIFF_TRANS_COLL): return "Different Transaction Collision"; - case (0x0200+BLE_ERR_QOS_PARM ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_QOS_PARM): return "QoS Unacceptable Parameter"; - case (0x0200+BLE_ERR_QOS_REJECTED ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_QOS_REJECTED): return "QoS Rejected"; - case (0x0200+BLE_ERR_CHAN_CLASS ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CHAN_CLASS): return "Channel Classification Not Supported"; - case (0x0200+BLE_ERR_INSUFFICIENT_SEC ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_INSUFFICIENT_SEC): return "Insufficient Security"; - case (0x0200+BLE_ERR_PARM_OUT_OF_RANGE ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_PARM_OUT_OF_RANGE): return "Parameter Out Of Mandatory Range"; - case (0x0200+BLE_ERR_PENDING_ROLE_SW ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_PENDING_ROLE_SW): return "Role Switch Pending"; - case (0x0200+BLE_ERR_RESERVED_SLOT ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_RESERVED_SLOT): return "Reserved Slot Violation"; - case (0x0200+BLE_ERR_ROLE_SW_FAIL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_ROLE_SW_FAIL): return "Role Switch Failed"; - case (0x0200+BLE_ERR_INQ_RSP_TOO_BIG ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_INQ_RSP_TOO_BIG): return "Extended Inquiry Response Too Large"; - case (0x0200+BLE_ERR_SEC_SIMPLE_PAIR ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_SEC_SIMPLE_PAIR): return "Secure Simple Pairing Not Supported By Host"; - case (0x0200+BLE_ERR_HOST_BUSY_PAIR ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_HOST_BUSY_PAIR): return "Host Busy - Pairing"; - case (0x0200+BLE_ERR_CONN_REJ_CHANNEL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_REJ_CHANNEL): return "Connection Rejected, No Suitable Channel Found"; - case (0x0200+BLE_ERR_CTLR_BUSY ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CTLR_BUSY): return "Controller Busy"; - case (0x0200+BLE_ERR_CONN_PARMS ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_PARMS): return "Unacceptable Connection Parameters"; - case (0x0200+BLE_ERR_DIR_ADV_TMO ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_DIR_ADV_TMO): return "Directed Advertising Timeout"; - case (0x0200+BLE_ERR_CONN_TERM_MIC ): - return "Connection Terminated due to MIC Failure"; - case (0x0200+BLE_ERR_CONN_ESTABLISHMENT ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_TERM_MIC): + return "Connection Terminated; MIC Failure"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT): return "Connection Failed to be Established"; - case (0x0200+BLE_ERR_MAC_CONN_FAIL ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_MAC_CONN_FAIL): return "MAC Connection Failed"; - case (0x0200+BLE_ERR_COARSE_CLK_ADJ ): + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_COARSE_CLK_ADJ): return "Coarse Clock Adjustment Rejected"; - case (0x0300+BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD ): - return "Invalid or unsupported incoming L2CAP sig command."; - case (0x0300+BLE_L2CAP_SIG_ERR_MTU_EXCEEDED ): - return "Incoming packet too large."; - case (0x0300+BLE_L2CAP_SIG_ERR_INVALID_CID ): - return "No channel with specified ID."; - case (0x0400+BLE_SM_ERR_PASSKEY ): - return "The user input of passkey failed, for example, the user cancelled the operation."; - case (0x0400+BLE_SM_ERR_OOB ): - return "The OOB data is not available."; - case (0x0400+BLE_SM_ERR_AUTHREQ ): - return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices."; - case (0x0400+BLE_SM_ERR_CONFIRM_MISMATCH ): - return "The confirm value does not match the calculated compare value."; - case (0x0400+BLE_SM_ERR_PAIR_NOT_SUPP ): - return "Pairing is not supported by the device."; - case (0x0400+BLE_SM_ERR_ENC_KEY_SZ ): - return "The resultant encryption key size is insufficient for the security requirements of this device."; - case (0x0400+BLE_SM_ERR_CMD_NOT_SUPP ): - return "The SMP command received is not supported on this device."; - case (0x0400+BLE_SM_ERR_UNSPECIFIED ): - return "Pairing failed due to an unspecified reason."; - case (0x0400+BLE_SM_ERR_REPEATED ): - return "Pairing or authentication procedure disallowed, too little time has elapsed since last pairing request or security request."; - case (0x0400+BLE_SM_ERR_INVAL ): - return "Command length is invalid or that a parameter is outside of the specified range."; - case (0x0400+BLE_SM_ERR_DHKEY ): - return "DHKey Check value received doesn't match the one calculated by the local device."; - case (0x0400+BLE_SM_ERR_NUMCMP ): - return "Confirm values in the numeric comparison protocol do not match."; - case (0x0400+BLE_SM_ERR_ALREADY ): - return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process."; - case (0x0400+BLE_SM_ERR_CROSS_TRANS ): - return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport."; - case (0x0500+BLE_SM_ERR_PASSKEY ): - return "The user input of passkey failed or the user cancelled the operation."; - case (0x0500+BLE_SM_ERR_OOB ): - return "The OOB data is not available."; - case (0x0500+BLE_SM_ERR_AUTHREQ ): - return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices."; - case (0x0500+BLE_SM_ERR_CONFIRM_MISMATCH ): - return "The confirm value does not match the calculated compare value."; - case (0x0500+BLE_SM_ERR_PAIR_NOT_SUPP ): - return "Pairing is not supported by the device."; - case (0x0500+BLE_SM_ERR_ENC_KEY_SZ ): - return "The resultant encryption key size is insufficient for the security requirements of this device."; - case (0x0500+BLE_SM_ERR_CMD_NOT_SUPP ): - return "The SMP command received is not supported on this device."; - case (0x0500+BLE_SM_ERR_UNSPECIFIED ): - return "Pairing failed due to an unspecified reason."; - case (0x0500+BLE_SM_ERR_REPEATED ): - return "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request."; - case (0x0500+BLE_SM_ERR_INVAL ): - return "Command length is invalid or a parameter is outside of the specified range."; - case (0x0500+BLE_SM_ERR_DHKEY ): - return "Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device."; - case (0x0500+BLE_SM_ERR_NUMCMP ): - return "Confirm values in the numeric comparison protocol do not match."; - case (0x0500+BLE_SM_ERR_ALREADY ): - return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process."; - case (0x0500+BLE_SM_ERR_CROSS_TRANS ): - return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport."; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_TYPE0_SUBMAP_NDEF): + return "Type0 Submap Not Defined"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNK_ADV_INDENT): + return "Unknown Advertising Identifier"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_LIMIT_REACHED): + return "Limit Reached"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_OPERATION_CANCELLED): + return "Operation Cancelled by Host"; + case (BLE_HS_ERR_HCI_BASE + BLE_ERR_PACKET_TOO_LONG): + return "Packet Too Long"; + case (BLE_HS_ERR_L2C_BASE + BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD): + return "Invalid or unsupported incoming L2CAP sig command"; + case (BLE_HS_ERR_L2C_BASE + BLE_L2CAP_SIG_ERR_MTU_EXCEEDED): + return "Incoming packet too large"; + case (BLE_HS_ERR_L2C_BASE + BLE_L2CAP_SIG_ERR_INVALID_CID): + return "No channel with specified ID"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_PASSKEY): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_PASSKEY): + return "Incorrect passkey or the user cancelled"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_OOB): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_OOB): + return "The OOB data is not available"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_AUTHREQ): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_AUTHREQ): + return "Authentication requirements cannot be met due to IO capabilities"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_CONFIRM_MISMATCH): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_CONFIRM_MISMATCH): + return "The confirm value does not match the calculated compare value"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_PAIR_NOT_SUPP): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_PAIR_NOT_SUPP): + return "Pairing is not supported by the device"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_ENC_KEY_SZ): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_ENC_KEY_SZ): + return "Insufficient encryption key size for this device"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_CMD_NOT_SUPP): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_CMD_NOT_SUPP): + return "The SMP command received is not supported on this device"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_UNSPECIFIED): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_UNSPECIFIED): + return "Pairing failed; unspecified reason"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_REPEATED): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_REPEATED): + return "Repeated pairing attempt"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_INVAL): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_INVAL): + return "Invalid command length or parameter"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_DHKEY): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_DHKEY): + return "DHKey check value received doesn't match"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_NUMCMP): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_NUMCMP): + return "Confirm values do not match"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_ALREADY): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_ALREADY): + return "Pairing already in process"; + case (BLE_HS_ERR_SM_US_BASE + BLE_SM_ERR_CROSS_TRANS): + case (BLE_HS_ERR_SM_PEER_BASE + BLE_SM_ERR_CROSS_TRANS): + return "Invalid link key for the LE transport"; default: return "Unknown"; } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) +# else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) (void)rc; return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) +# endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) } - /** * @brief Convert the advertising type flag to a string. * @param advType The type to convert. * @return A string representation of the advertising flags. */ const char* NimBLEUtils::advTypeToString(uint8_t advType) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) - switch(advType) { - case BLE_HCI_ADV_TYPE_ADV_IND : //0 +# if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) + switch (advType) { + case BLE_HCI_ADV_TYPE_ADV_IND: // 0 return "Undirected - Connectable / Scannable"; - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: //1 + case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: // 1 return "Directed High Duty - Connectable"; - case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: //2 + case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: // 2 return "Non-Connectable - Scan Response Available"; - case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: //3 + case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: // 3 return "Non-Connectable - No Scan Response"; - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: //4 + case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: // 4 return "Directed Low Duty - Connectable"; default: return "Unknown flag"; } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) +# else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) (void)advType; return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) +# endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) } // adFlagsToString - -/** - * @brief Create a hex representation of data. - * - * @param [in] target Where to write the hex string. If this is null, we malloc storage. - * @param [in] source The start of the binary data. - * @param [in] length The length of the data to convert. - * @return A pointer to the formatted buffer. - */ -char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t length) { - // Guard against too much data. - if (length > 100) length = 100; - - if (target == nullptr) { - target = (uint8_t*) malloc(length * 2 + 1); - if (target == nullptr) { - NIMBLE_LOGE(LOG_TAG, "buildHexData: malloc failed"); - return nullptr; - } - } - char* startOfData = (char*) target; - - for (int i = 0; i < length; i++) { - sprintf((char*) target, "%.2x", (char) *source); - source++; - target += 2; - } - - // Handle the special case where there was no data. - if (length == 0) { - *startOfData = 0; - } - - return startOfData; -} // buildHexData - - -/** - * @brief Utility function to log the gap event info. - * @param [in] event A pointer to the gap event structure. - * @param [in] arg Unused. - */ -void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){ - (void)arg; -#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) - NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type)); -#else - (void)event; -#endif -} - - /** * @brief Convert a GAP event type to a string representation. * @param [in] eventType The type of event. * @return A string representation of the event type. */ const char* NimBLEUtils::gapEventToString(uint8_t eventType) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) +# if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) switch (eventType) { - case BLE_GAP_EVENT_CONNECT : //0 + case BLE_GAP_EVENT_CONNECT: // 0 return "BLE_GAP_EVENT_CONNECT "; - - case BLE_GAP_EVENT_DISCONNECT: //1 + case BLE_GAP_EVENT_DISCONNECT: // 1 return "BLE_GAP_EVENT_DISCONNECT"; - - case BLE_GAP_EVENT_CONN_UPDATE: //3 + case BLE_GAP_EVENT_CONN_UPDATE: // 3 return "BLE_GAP_EVENT_CONN_UPDATE"; - - case BLE_GAP_EVENT_CONN_UPDATE_REQ: //4 + case BLE_GAP_EVENT_CONN_UPDATE_REQ: // 4 return "BLE_GAP_EVENT_CONN_UPDATE_REQ"; - - case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: //5 + case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: // 5 return "BLE_GAP_EVENT_L2CAP_UPDATE_REQ"; - - case BLE_GAP_EVENT_TERM_FAILURE: //6 + case BLE_GAP_EVENT_TERM_FAILURE: // 6 return "BLE_GAP_EVENT_TERM_FAILURE"; - - case BLE_GAP_EVENT_DISC: //7 + case BLE_GAP_EVENT_DISC: // 7 return "BLE_GAP_EVENT_DISC"; - - case BLE_GAP_EVENT_DISC_COMPLETE: //8 + case BLE_GAP_EVENT_DISC_COMPLETE: // 8 return "BLE_GAP_EVENT_DISC_COMPLETE"; - - case BLE_GAP_EVENT_ADV_COMPLETE: //9 + case BLE_GAP_EVENT_ADV_COMPLETE: // 9 return "BLE_GAP_EVENT_ADV_COMPLETE"; - - case BLE_GAP_EVENT_ENC_CHANGE: //10 + case BLE_GAP_EVENT_ENC_CHANGE: // 10 return "BLE_GAP_EVENT_ENC_CHANGE"; - - case BLE_GAP_EVENT_PASSKEY_ACTION : //11 + case BLE_GAP_EVENT_PASSKEY_ACTION: // 11 return "BLE_GAP_EVENT_PASSKEY_ACTION"; - - case BLE_GAP_EVENT_NOTIFY_RX: //12 + case BLE_GAP_EVENT_NOTIFY_RX: // 12 return "BLE_GAP_EVENT_NOTIFY_RX"; - - case BLE_GAP_EVENT_NOTIFY_TX : //13 + case BLE_GAP_EVENT_NOTIFY_TX: // 13 return "BLE_GAP_EVENT_NOTIFY_TX"; - - case BLE_GAP_EVENT_SUBSCRIBE : //14 + case BLE_GAP_EVENT_SUBSCRIBE: // 14 return "BLE_GAP_EVENT_SUBSCRIBE"; - - case BLE_GAP_EVENT_MTU: //15 + case BLE_GAP_EVENT_MTU: // 15 return "BLE_GAP_EVENT_MTU"; - - case BLE_GAP_EVENT_IDENTITY_RESOLVED: //16 + case BLE_GAP_EVENT_IDENTITY_RESOLVED: // 16 return "BLE_GAP_EVENT_IDENTITY_RESOLVED"; - - case BLE_GAP_EVENT_REPEAT_PAIRING: //17 + case BLE_GAP_EVENT_REPEAT_PAIRING: // 17 return "BLE_GAP_EVENT_REPEAT_PAIRING"; - - case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: //18 + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: // 18 return "BLE_GAP_EVENT_PHY_UPDATE_COMPLETE"; - - case BLE_GAP_EVENT_EXT_DISC: //19 + case BLE_GAP_EVENT_EXT_DISC: // 19 return "BLE_GAP_EVENT_EXT_DISC"; -#ifdef BLE_GAP_EVENT_PERIODIC_SYNC // IDF 4.0 does not support these - case BLE_GAP_EVENT_PERIODIC_SYNC: //20 +# ifdef BLE_GAP_EVENT_PERIODIC_SYNC // IDF 4.0 does not support these + case BLE_GAP_EVENT_PERIODIC_SYNC: // 20 return "BLE_GAP_EVENT_PERIODIC_SYNC"; - - case BLE_GAP_EVENT_PERIODIC_REPORT: //21 + case BLE_GAP_EVENT_PERIODIC_REPORT: // 21 return "BLE_GAP_EVENT_PERIODIC_REPORT"; - - case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: //22 + case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: // 22 return "BLE_GAP_EVENT_PERIODIC_SYNC_LOST"; - - case BLE_GAP_EVENT_SCAN_REQ_RCVD: //23 + case BLE_GAP_EVENT_SCAN_REQ_RCVD: // 23 return "BLE_GAP_EVENT_SCAN_REQ_RCVD"; -#endif + case BLE_GAP_EVENT_PERIODIC_TRANSFER: // 24 + return "BLE_GAP_EVENT_PERIODIC_TRANSFER"; + case BLE_GAP_EVENT_PATHLOSS_THRESHOLD: // 25 + return "BLE_GAP_EVENT_PATHLOSS_THRESHOLD"; + case BLE_GAP_EVENT_TRANSMIT_POWER: // 26 + return "BLE_GAP_EVENT_TRANSMIT_POWER"; + case BLE_GAP_EVENT_SUBRATE_CHANGE: // 27 + return "BLE_GAP_EVENT_SUBRATE_CHANGE"; + case BLE_GAP_EVENT_VS_HCI: // 28 + return "BLE_GAP_EVENT_VS_HCI"; + case BLE_GAP_EVENT_REATTEMPT_COUNT: // 29 + return "BLE_GAP_EVENT_REATTEMPT_COUNT"; + case BLE_GAP_EVENT_AUTHORIZE: // 30 + return "BLE_GAP_EVENT_AUTHORIZE"; + case BLE_GAP_EVENT_TEST_UPDATE: // 31 + return "BLE_GAP_EVENT_TEST_UPDATE"; + case BLE_GAP_EVENT_DATA_LEN_CHG: // 32 + return "BLE_GAP_EVENT_DATA_LEN_CHG"; + case BLE_GAP_EVENT_LINK_ESTAB: // 33 + return "BLE_GAP_EVENT_LINK_ESTAB"; +# endif default: - NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); + NIMBLE_LOGD(LOG_TAG, "Unknown event type %d 0x%.2x", eventType, eventType); return "Unknown event type"; } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) +# else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) (void)eventType; return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) +# endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) } // gapEventToString +/** + * @brief Create a hexadecimal string representation of the input data. + * @param [in] source The start of the binary data. + * @param [in] length The length of the data to convert. + * @return A string representation of the data. + */ +std::string NimBLEUtils::dataToHexString(const uint8_t* source, uint8_t length) { + std::string str{}; + str.reserve(length * 2 + 1); + + for (uint8_t i = 0; i < length; i++) { + char c = (source[i] >> 4) & 0x0f; + str.push_back(c > 9 ? c + 'A' - 10 : c + '0'); + c = source[i] & 0x0f; + str.push_back(c > 9 ? c + 'A' - 10 : c + '0'); + } + + return str; +} // hexDataToString + /** * @brief Generate a random BLE address. * @param [in] nrpa True to generate a non-resolvable private address, @@ -496,7 +519,7 @@ const char* NimBLEUtils::gapEventToString(uint8_t eventType) { */ NimBLEAddress NimBLEUtils::generateAddr(bool nrpa) { ble_addr_t addr{}; - int rc = ble_hs_id_gen_rnd(nrpa, &addr); + int rc = ble_hs_id_gen_rnd(nrpa, &addr); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Generate address failed, rc=%d", rc); } @@ -504,4 +527,4 @@ NimBLEAddress NimBLEUtils::generateAddr(bool nrpa) { return NimBLEAddress{addr}; } // generateAddr -#endif //CONFIG_BT_ENABLED +#endif // CONFIG_BT_ENABLED diff --git a/src/NimBLEUtils.h b/src/NimBLEUtils.h index 71928d0..1c80ba5 100644 --- a/src/NimBLEUtils.h +++ b/src/NimBLEUtils.h @@ -6,40 +6,51 @@ * */ -#ifndef COMPONENTS_NIMBLEUTILS_H_ -#define COMPONENTS_NIMBLEUTILS_H_ +#ifndef NIMBLE_CPP_UTILS_H_ +#define NIMBLE_CPP_UTILS_H_ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) - -# include -# include - -#include +# include class NimBLEAddress; -struct BleTaskData { - void* pATT; - TaskHandle_t task; - int rc; - void* buf; -}; +/** + * @brief A structure to hold data for a task that is waiting for a response. + * @details This structure is used in conjunction with NimBLEUtils::taskWait() and NimBLEUtils::taskRelease(). + * All items are optional, the m_pHandle will be set in taskWait(). + */ +struct NimBLETaskData { + /** + * @brief Constructor. + * @param [in] pInstance An instance of the class that is waiting. + * @param [in] flags General purpose flags for the caller. + * @param [in] buf A buffer for data. + */ + NimBLETaskData(void* pInstance = nullptr, int flags = 0, void* buf = nullptr) + : m_pInstance(pInstance), m_flags(flags), m_pBuf(buf) {} + void* m_pInstance{nullptr}; + mutable int m_flags{0}; + void* m_pBuf{nullptr}; -struct ble_gap_event; + private: + mutable void* m_pHandle{nullptr}; // semaphore or task handle + friend class NimBLEUtils; +}; /** * @brief A BLE Utility class with methods for debugging and general purpose use. */ class NimBLEUtils { -public: - static void dumpGapEvent(ble_gap_event *event, void *arg); - static const char* gapEventToString(uint8_t eventType); - static char* buildHexData(uint8_t* target, const uint8_t* source, uint8_t length); - static const char* advTypeToString(uint8_t advType); - static const char* returnCodeToString(int rc); - static NimBLEAddress generateAddr(bool nrpa); + public: + static const char* gapEventToString(uint8_t eventType); + static std::string dataToHexString(const uint8_t* source, uint8_t length); + static const char* advTypeToString(uint8_t advType); + static const char* returnCodeToString(int rc); + static NimBLEAddress generateAddr(bool nrpa); + static bool taskWait(const NimBLETaskData& taskData, uint32_t timeout); + static void taskRelease(const NimBLETaskData& taskData, int rc = 0); }; #endif // CONFIG_BT_ENABLED -#endif // COMPONENTS_NIMBLEUTILS_H_ +#endif // NIMBLE_CPP_UTILS_H_