From a04ee1581524a1dfaab24fbe3854722125f953eb Mon Sep 17 00:00:00 2001 From: thekurtovic <40248206+thekurtovic@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:55:10 -0500 Subject: [PATCH] refactor: Consolidate attribute get code into NimBLEUtils --- src/NimBLEClient.cpp | 190 +++++++++++------------------ src/NimBLERemoteCharacteristic.cpp | 137 ++++++++------------- src/NimBLERemoteService.cpp | 106 +++++----------- src/NimBLEUtils.h | 31 +++++ 4 files changed, 182 insertions(+), 282 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index e5b1383..c2e53dd 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -101,8 +101,8 @@ NimBLEClient::~NimBLEClient() { */ void NimBLEClient::deleteServices() { // Delete all the services. - for (auto& it : m_svcVec) { - delete it; + for (auto& svc : m_svcVec) { + delete svc; } std::vector().swap(m_svcVec); @@ -243,8 +243,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, break; default: - NIMBLE_LOGE(LOG_TAG, - "Failed to connect to %s, rc=%d; %s", + NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s", std::string(m_peerAddress).c_str(), rc, NimBLEUtils::returnCodeToString(rc)); @@ -631,48 +630,14 @@ NimBLERemoteService* NimBLEClient::getService(const char* uuid) { */ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID& uuid) { NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); + NimBLERemoteService *pSvc = nullptr; - for (auto& it : m_svcVec) { - if (it->getUUID() == uuid) { - NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); - return it; - } - } + NimBLEUtils::getAttr(uuid, pSvc, m_svcVec, [this](const NimBLEUUID* u, void* arg) { + return retrieveServices(u, (NimBLERemoteService*)arg); + }); - size_t prevSize = m_svcVec.size(); - if (retrieveServices(&uuid)) { - if (m_svcVec.size() > prevSize) { - return m_svcVec.back(); - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if (retrieveServices(&uuid128)) { - if (m_svcVec.size() > prevSize) { - return m_svcVec.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if (retrieveServices(&uuid16)) { - if (m_svcVec.size() > prevSize) { - return m_svcVec.back(); - } - } - } - } - } - - NIMBLE_LOGD(LOG_TAG, "<< getService: not found"); - return nullptr; + NIMBLE_LOGD(LOG_TAG, "<< getService: %sfound", !pSvc ? "not " : ""); + return pSvc; } // getService /** @@ -725,7 +690,7 @@ bool NimBLEClient::discoverAttributes() { * * Here we ask the server for its set of services and wait until we have received them all. * @return true on success otherwise false if an error occurred */ -bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { +bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter, NimBLERemoteService *out) { if (!isConnected()) { NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting"); return false; @@ -735,9 +700,9 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { NimBLETaskData taskData(this); if (uuidFilter == nullptr) { - rc = ble_gattc_disc_all_svcs(m_connHandle, NimBLEClient::serviceDiscoveredCB, &taskData); + rc = ble_gattc_disc_all_svcs(m_connHandle, NimBLEClient::serviceDiscCB, &taskData); } else { - rc = ble_gattc_disc_svc_by_uuid(m_connHandle, uuidFilter->getBase(), NimBLEClient::serviceDiscoveredCB, &taskData); + rc = ble_gattc_disc_svc_by_uuid(m_connHandle, uuidFilter->getBase(), NimBLEClient::serviceDiscCB, &taskData); } if (rc != 0) { @@ -748,13 +713,15 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); rc = taskData.m_flags; - if (rc == 0 || rc == BLE_HS_EDONE) { - return true; + if (rc != BLE_HS_EDONE) { + m_lastErr = rc; + NIMBLE_LOGE(LOG_TAG, "Could not retrieve services, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } - m_lastErr = rc; - NIMBLE_LOGE(LOG_TAG, "Could not retrieve services, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; + out = m_svcVec.back(); + NIMBLE_LOGD(LOG_TAG, "<< retrieveServices(): found %d services.", m_svcVec.size()); + return true; } // getServices /** @@ -762,39 +729,29 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) { * @details When a service is found or there is none left or there was an error * the API will call this and report findings. */ -int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle, - const struct ble_gatt_error* error, - const struct ble_gatt_svc* service, - void* arg) { - NIMBLE_LOGD(LOG_TAG, - "Service Discovered >> status: %d handle: %d", - error->status, - (error->status == 0) ? service->start_handle : -1); - - NimBLETaskData* pTaskData = (NimBLETaskData*)arg; - NimBLEClient* pClient = (NimBLEClient*)pTaskData->m_pInstance; - - if (error->status == BLE_HS_ENOTCONN) { - NIMBLE_LOGE(LOG_TAG, "<< Service Discovered; Disconnected"); - NimBLEUtils::taskRelease(*pTaskData, error->status); - return error->status; - } +int NimBLEClient::serviceDiscCB(uint16_t connHandle, + const struct ble_gatt_error* error, + const struct ble_gatt_svc* service, + void* arg) { + const int rc = error->status; + auto pTaskData = (NimBLETaskData*)arg; + auto pClient = (NimBLEClient*)pTaskData->m_pInstance; + NIMBLE_LOGD(LOG_TAG, "Service Discovered >> status: %d handle: %d", rc, (rc == 0) ? service->start_handle : -1); // Make sure the service discovery is for this device if (pClient->getConnHandle() != connHandle) { return 0; } - if (error->status == 0) { - // Found a service - add it to the vector + if (rc == 0) { // Found a service - add it to the vector pClient->m_svcVec.push_back(new NimBLERemoteService(pClient, service)); return 0; } NimBLEUtils::taskRelease(*pTaskData, error->status); - NIMBLE_LOGD(LOG_TAG, "<< Service Discovered"); + NIMBLE_LOGD(LOG_TAG, "<< Service Discovered%s", (rc == BLE_HS_ENOTCONN) ? "; Disconnected" : ""); return error->status; -} // serviceDiscoveredCB +} // serviceDiscCB /** * @brief Get the value of a specific characteristic associated with a specific service. @@ -803,8 +760,7 @@ int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle, * @returns characteristic value or an empty value if not found. */ NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID) { - NIMBLE_LOGD(LOG_TAG, - ">> getValue: serviceUUID: %s, characteristicUUID: %s", + NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); @@ -833,15 +789,14 @@ bool NimBLEClient::setValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID, const NimBLEAttValue& value, bool response) { - NIMBLE_LOGD(LOG_TAG, - ">> setValue: serviceUUID: %s, characteristicUUID: %s", + NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); bool ret = false; auto pService = getService(serviceUUID); if (pService != nullptr) { - NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID); + auto pChar = pService->getCharacteristic(characteristicUUID); if (pChar != nullptr) { ret = pChar->writeValue(value, response); } @@ -858,11 +813,13 @@ bool NimBLEClient::setValue(const NimBLEUUID& serviceUUID, */ NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(uint16_t handle) { for (const auto& svc : m_svcVec) { - if (svc->getStartHandle() <= handle && handle <= svc->getEndHandle()) { - for (const auto& chr : svc->m_vChars) { - if (chr->getHandle() == handle) { - return chr; - } + if (svc->getStartHandle() > handle && handle > svc->getEndHandle()) { + continue; + } + + for (const auto& chr : svc->m_vChars) { + if (chr->getHandle() == handle) { + return chr; } } } @@ -882,28 +839,28 @@ uint16_t NimBLEClient::getMTU() const { * @brief Callback for the MTU exchange API function. * @details When the MTU exchange is complete the API will call this and report the new MTU. */ -int NimBLEClient::exchangeMTUCb(uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void* arg) { - NIMBLE_LOGD(LOG_TAG, "exchangeMTUCb: status=%d, mtu=%d", error->status, mtu); +int NimBLEClient::exchangeMTUCB(uint16_t connHandle, const ble_gatt_error* error, uint16_t mtu, void* arg) { + NIMBLE_LOGD(LOG_TAG, "exchangeMTUCB: status=%d, mtu=%d", error->status, mtu); NimBLEClient* pClient = (NimBLEClient*)arg; - if (pClient->getConnHandle() != conn_handle) { + if (pClient->getConnHandle() != connHandle) { return 0; } if (error->status != 0) { - NIMBLE_LOGE(LOG_TAG, "exchangeMTUCb() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status)); + NIMBLE_LOGE(LOG_TAG, "exchangeMTUCB() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status)); pClient->m_lastErr = error->status; } return 0; -} // exchangeMTUCb +} // exchangeMTUCB /** * @brief Begin the MTU exchange process with the server. * @returns true if the request was sent successfully. */ bool NimBLEClient::exchangeMTU() { - int rc = ble_gattc_exchange_mtu(m_connHandle, NimBLEClient::exchangeMTUCb, this); + int rc = ble_gattc_exchange_mtu(m_connHandle, NimBLEClient::exchangeMTUCB, this); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); m_lastErr = rc; @@ -989,25 +946,25 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { pClient->m_pClientCallbacks->onConnect(pClient); } - if (pClient->m_config.exchangeMTU) { - if (!pClient->exchangeMTU()) { - rc = pClient->m_lastErr; // sets the error in the task data - break; - } - - return 0; // return as we may have a task waiting for the MTU before releasing it. + if (!pClient->m_config.exchangeMTU) { + break; } - } else { - pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE; - if (pClient->m_config.asyncConnect) { - pClient->m_pClientCallbacks->onConnectFail(pClient, rc); - if (pClient->m_config.deleteOnConnectFail) { - NimBLEDevice::deleteClient(pClient); - } + if (!pClient->exchangeMTU()) { + rc = pClient->m_lastErr; // sets the error in the task data + break; } + + return 0; // return as we may have a task waiting for the MTU before releasing it. } + pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE; + if (pClient->m_config.asyncConnect) { + pClient->m_pClientCallbacks->onConnectFail(pClient, rc); + if (pClient->m_config.deleteOnConnectFail) { + NimBLEDevice::deleteClient(pClient); + } + } break; } // BLE_GAP_EVENT_CONNECT @@ -1035,23 +992,23 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { continue; } - NIMBLE_LOGD(LOG_TAG, - "checking service %s for handle: %d", + NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", svc->getUUID().toString().c_str(), event->notify_rx.attr_handle); for (const auto& chr : svc->m_vChars) { - if (chr->getHandle() == event->notify_rx.attr_handle) { - NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str()); - - uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om); - chr->m_value.setValue(event->notify_rx.om->om_data, data_len); - - if (chr->m_notifyCallback != nullptr) { - chr->m_notifyCallback(chr, event->notify_rx.om->om_data, data_len, !event->notify_rx.indication); - } - break; + if (chr->getHandle() != event->notify_rx.attr_handle) { + continue; } + + NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str()); + uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om); + chr->m_value.setValue(event->notify_rx.om->om_data, data_len); + + if (chr->m_notifyCallback != nullptr) { + chr->m_notifyCallback(chr, event->notify_rx.om->om_data, data_len, !event->notify_rx.indication); + } + break; } } @@ -1064,8 +1021,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) { return 0; } NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters"); - NIMBLE_LOGD(LOG_TAG, - "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", + NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", event->conn_update_req.peer_params->itvl_min, event->conn_update_req.peer_params->itvl_max, event->conn_update_req.peer_params->latency, diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index bac8574..b089395 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -27,17 +27,17 @@ # include -typedef struct { - const NimBLEUUID* uuid; - void* task_data; -} desc_filter_t; +struct desc_filter_t { + const NimBLEUUID* uuid; + void* taskData; +}; static const char* LOG_TAG = "NimBLERemoteCharacteristic"; /** * @brief Constructor. * @param [in] svc A pointer to the service this characteristic belongs to. - * @param [in] ble_gatt_chr struct defined as: + * @param [in] chr struct defined as: * struct ble_gatt_chr { * uint16_t def_handle; * uint16_t val_handle; @@ -62,57 +62,56 @@ NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() { /** * @brief Callback used by the API when a descriptor is discovered or search complete. */ -int NimBLERemoteCharacteristic::descriptorDiscCB( - uint16_t conn_handle, const ble_gatt_error* error, uint16_t chr_val_handle, const ble_gatt_dsc* dsc, void* arg) { - int rc = error->status; +int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t connHandle, + const ble_gatt_error* error, + uint16_t chrHandle, + const ble_gatt_dsc* dsc, + void* arg) { + int rc = error->status; + auto filter = (desc_filter_t*)arg; + auto pTaskData = (NimBLETaskData*)filter->taskData; + const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->m_pInstance; + const auto uuid = filter->uuid; // UUID to filter for NIMBLE_LOGD(LOG_TAG, "Descriptor Discovery >> status: %d handle: %d", rc, (rc == 0) ? dsc->handle : -1); - auto filter = (desc_filter_t*)arg; - auto pTaskData = (NimBLETaskData*)filter->task_data; - const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->m_pInstance; - const NimBLEUUID* uuidFilter = filter->uuid; - - if (pChr->getHandle() != chr_val_handle) { - return 0; // Descriptor not for this characteristic - } - - if (rc == 0) { - if (uuidFilter != nullptr) { - if (ble_uuid_cmp(uuidFilter->getBase(), &dsc->uuid.u) == 0) { - rc = BLE_HS_EDONE; // Found the descriptor, stop the search - } else { - return 0; // Not the descriptor we are looking for - } - } - + // Results for chrHandle added until rc != 0 + // Must find specified UUID if filter is used + if (rc == 0 && pChr->getHandle() == chrHandle + && (!uuid || 0 == ble_uuid_cmp(uuid->getBase(), &dsc->uuid.u))) { + // Return BLE_HS_EDONE if the descriptor was found, stop the search pChr->m_vDescriptors.push_back(new NimBLERemoteDescriptor(pChr, dsc)); - return 0; + rc = !!uuid * BLE_HS_EDONE; } - NimBLEUtils::taskRelease(*pTaskData, rc); - NIMBLE_LOGD(LOG_TAG, "<< Descriptor Discovery"); + if (rc != 0) { + NimBLEUtils::taskRelease(*pTaskData, rc); + NIMBLE_LOGD(LOG_TAG, "<< Descriptor Discovery"); + } return rc; } /** * @brief Populate the descriptors (if any) for this characteristic. - * @param [in] the end handle of the characteristic, or the service, whichever comes first. + * @param [in] filter Structure containing pointers to descriptor, UUID, and task data. + * @return True if successfully retrieved, success = BLE_HS_EDONE. */ -bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilter) const { +bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilter, NimBLERemoteDescriptor* out) const { NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); + NimBLETaskData taskData(const_cast(this)); + desc_filter_t filter = {uuidFilter, &taskData}; + const uint16_t handle = getHandle(); + const uint16_t svcHandle = getRemoteService()->getEndHandle(); + // If this is the last handle then there are no descriptors - if (getHandle() == getRemoteService()->getEndHandle()) { - NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): found 0 descriptors."); - return true; + if (handle == svcHandle) { + NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): found 0 descriptors."); + return true; } - NimBLETaskData taskData(const_cast(this)); - desc_filter_t filter = {uuidFilter, &taskData}; - int rc = ble_gattc_disc_all_dscs(getClient()->getConnHandle(), - getHandle(), - getRemoteService()->getEndHandle(), + handle, + svcHandle, NimBLERemoteCharacteristic::descriptorDiscCB, &filter); if (rc != 0) { @@ -122,13 +121,14 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilte 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; + if (rc != BLE_HS_EDONE) { + NIMBLE_LOGE(LOG_TAG, "<< retrieveDescriptors(): failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } - NIMBLE_LOGE(LOG_TAG, "<< retrieveDescriptors(): failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; + out = m_vDescriptors.back(); + NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): found %d descriptors.", m_vDescriptors.size()); + return true; } // retrieveDescriptors /** @@ -138,50 +138,13 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID* uuidFilte */ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID& uuid) const { NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); - NimBLERemoteDescriptor* pDsc = nullptr; - size_t prev_size = m_vDescriptors.size(); + NimBLERemoteDescriptor* pDsc = nullptr; - for (const auto& it : m_vDescriptors) { - if (it->getUUID() == uuid) { - pDsc = it; - goto Done; - } - } + NimBLEUtils::getAttr(uuid, pDsc, m_vDescriptors, [this](const NimBLEUUID* u, void* arg) { + return retrieveDescriptors(u, (NimBLERemoteDescriptor*)arg); + }); - if (retrieveDescriptors(&uuid)) { - if (m_vDescriptors.size() > prev_size) { - pDsc = m_vDescriptors.back(); - goto Done; - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if (retrieveDescriptors(&uuid128)) { - if (m_vDescriptors.size() > prev_size) { - pDsc = m_vDescriptors.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if (retrieveDescriptors(&uuid16)) { - if (m_vDescriptors.size() > prev_size) { - pDsc = m_vDescriptors.back(); - } - } - } - } - } - -Done: - NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: %sfound", pDsc ? "" : "not "); + NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: %sfound", !pDsc ? "not " : ""); return pDsc; } // getDescriptor @@ -311,7 +274,7 @@ size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID& uuid) cons * @return True if supported. */ bool NimBLERemoteCharacteristic::canBroadcast() const { - return (m_properties & BLE_GATT_CHR_PROP_BROADCAST) != 0; + return (m_properties & BLE_GATT_CHR_PROP_BROADCAST); }; /** diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index c131af7..6dba0f5 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -76,50 +76,13 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u */ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID& uuid) const { NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str()); - NimBLERemoteCharacteristic* pChar = nullptr; - size_t prev_size = m_vChars.size(); + NimBLERemoteCharacteristic* pChar = nullptr; - for (const auto& it : m_vChars) { - if (it->getUUID() == uuid) { - pChar = it; - goto Done; - } - } + NimBLEUtils::getAttr(uuid, pChar, m_vChars, [this](const NimBLEUUID* u, void* arg) { + return retrieveCharacteristics(u, (NimBLERemoteCharacteristic*)arg); + }); - if (retrieveCharacteristics(&uuid)) { - if (m_vChars.size() > prev_size) { - pChar = m_vChars.back(); - goto Done; - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if (retrieveCharacteristics(&uuid128)) { - if (m_vChars.size() > prev_size) { - pChar = m_vChars.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if (retrieveCharacteristics(&uuid16)) { - if (m_vChars.size() > prev_size) { - pChar = m_vChars.back(); - } - } - } - } - } - -Done: - NIMBLE_LOGD(LOG_TAG, "<< Characteristic %sfound", pChar ? "" : "not "); + NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: %sfound", !pChar ? "not " : ""); return pChar; } // getCharacteristic @@ -143,47 +106,39 @@ const std::vector& NimBLERemoteService::getCharacte * @brief Callback for Characteristic discovery. * @return success == 0 or error code. */ -int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, +int NimBLERemoteService::characteristicDiscCB(uint16_t connHandle, const ble_gatt_error* error, const ble_gatt_chr* chr, void* arg) { - NIMBLE_LOGD(LOG_TAG, - "Characteristic Discovery >> status: %d handle: %d", - error->status, - (error->status == 0) ? chr->def_handle : -1); + const int rc = error->status; auto pTaskData = (NimBLETaskData*)arg; const auto pSvc = (NimBLERemoteService*)pTaskData->m_pInstance; - - if (error->status == BLE_HS_ENOTCONN) { - NIMBLE_LOGE(LOG_TAG, "<< Characteristic Discovery; Not connected"); - NimBLEUtils::taskRelease(*pTaskData, error->status); - return error->status; - } + NIMBLE_LOGD(LOG_TAG, "Characteristic Discovery >> status: %d handle: %d", rc, (rc == 0) ? chr->def_handle : -1); // Make sure the discovery is for this device - if (pSvc->getClient()->getConnHandle() != conn_handle) { + if (pSvc->getClient()->getConnHandle() != connHandle) { return 0; } - if (error->status == 0) { + if (rc == 0) { pSvc->m_vChars.push_back(new NimBLERemoteCharacteristic(pSvc, chr)); return 0; } - NimBLEUtils::taskRelease(*pTaskData, error->status); - NIMBLE_LOGD(LOG_TAG, "<< Characteristic Discovery"); - return error->status; + NimBLEUtils::taskRelease(*pTaskData, rc); + NIMBLE_LOGD(LOG_TAG, "<< Characteristic Discovery%s", (rc == BLE_HS_ENOTCONN) ? "; Not connected" : ""); + return rc; } /** * @brief Retrieve all the characteristics for this service. * This function will not return until we have all the characteristics. - * @return True if successful. + * @return True if successfully retrieved, success = BLE_HS_EDONE. */ -bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) const { +bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter, NimBLERemoteCharacteristic* out) const { NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics()"); - int rc = 0; NimBLETaskData taskData(const_cast(this)); + int rc = 0; if (uuidFilter == nullptr) { rc = ble_gattc_disc_all_chrs(m_pClient->getConnHandle(), @@ -207,13 +162,14 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) 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; + if (rc != BLE_HS_EDONE) { + NIMBLE_LOGE(LOG_TAG, "<< retrieveCharacteristics(): failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); + return false; } - NIMBLE_LOGE(LOG_TAG, "<< retrieveCharacteristics() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; + out = m_vChars.back(); + NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics(): found %d characteristics.", m_vChars.size()); + return true; } // retrieveCharacteristics /** @@ -231,11 +187,8 @@ NimBLEClient* NimBLERemoteService::getClient() const { */ NimBLEAttValue NimBLERemoteService::getValue(const NimBLEUUID& uuid) const { const auto pChar = getCharacteristic(uuid); - if (pChar) { - return pChar->readValue(); - } - - return NimBLEAttValue{}; + return pChar ? pChar->readValue() + : NimBLEAttValue{}; } // readValue /** @@ -246,11 +199,8 @@ NimBLEAttValue NimBLERemoteService::getValue(const NimBLEUUID& uuid) const { */ bool NimBLERemoteService::setValue(const NimBLEUUID& uuid, const NimBLEAttValue& value) const { const auto pChar = getCharacteristic(uuid); - if (pChar) { - return pChar->writeValue(value); - } - - return false; + return pChar ? pChar->writeValue(value) + : false; } // setValue /** @@ -260,8 +210,8 @@ bool NimBLERemoteService::setValue(const NimBLEUUID& uuid, const NimBLEAttValue& * them. This method does just that. */ void NimBLERemoteService::deleteCharacteristics() const { - for (const auto& it : m_vChars) { - delete it; + for (const auto& chr : m_vChars) { + delete chr; } std::vector{}.swap(m_vChars); } // deleteCharacteristics diff --git a/src/NimBLEUtils.h b/src/NimBLEUtils.h index e56f568..a8c2084 100644 --- a/src/NimBLEUtils.h +++ b/src/NimBLEUtils.h @@ -20,6 +20,8 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) +# include "NimBLEUUID.h" +# include "functional" # include class NimBLEAddress; @@ -53,6 +55,35 @@ class NimBLEUtils { static NimBLEAddress generateAddr(bool nrpa); static bool taskWait(const NimBLETaskData& taskData, uint32_t timeout); static void taskRelease(const NimBLETaskData& taskData, int rc = 0); + + template + static void getAttr(const NimBLEUUID& uuid, T* attr, const std::vector vec, const std::function& getter) { + // Check if already exists. + for (const auto& v : vec) { + if (v->getUUID() == uuid) { + attr = v; + return; + } + } + + // Exit if request failed or uuid was found. + if (!getter(&uuid, attr) || attr) { + return; + } + + // Try again with 128 bit uuid if request succeeded with no uuid found. + if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) { + NimBLEUUID uuid128 = NimBLEUUID(uuid).to128(); + getter(&uuid128, attr); + return; + } + // Try again with 16 bit uuid if request succeeded with no uuid found. + // If the uuid was 128 bit but not of the BLE base type this check will fail. + NimBLEUUID uuid16 = NimBLEUUID(uuid).to16(); + if (uuid16.bitSize() == BLE_UUID_TYPE_16) { + getter(&uuid16, attr); + } + } }; #endif // CONFIG_BT_ENABLED