diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index a72b4e37..845a5bb5 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -49,7 +49,7 @@ static NimBLEClientCallbacks defaultCallbacks; * */ -NimBLEClient::NimBLEClient() +NimBLEClient::NimBLEClient(bool preDiscover) { m_pClientCallbacks = &defaultCallbacks; m_conn_id = BLE_HS_CONN_HANDLE_NONE; @@ -65,6 +65,8 @@ NimBLEClient::NimBLEClient() m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units + + m_preDiscover = preDiscover; } // NimBLEClient @@ -375,7 +377,7 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); return it; } - } + } NIMBLE_LOGD(LOG_TAG, "<< getService: not found"); return nullptr; @@ -427,13 +429,15 @@ bool NimBLEClient::retrieveServices() { // If sucessful, remember that we now have services. m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0); if(m_haveServices){ - for (auto &it: m_servicesVector) { - if(!m_isConnected || !it->retrieveCharacteristics()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting"); - return false; + if(m_preDiscover) { + for (auto &it: m_servicesVector) { + if(!m_isConnected || !it->retrieveCharacteristics()) { + NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting"); + return false; + } } } - + NIMBLE_LOGD(LOG_TAG, "<< retrieveServices"); return true; } @@ -669,26 +673,24 @@ uint16_t NimBLEClient::getMTU() { if(it->getEndHandle() < event->notify_rx.attr_handle) { continue; } - auto cVector = it->getCharacteristics(); NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", it->getUUID().toString().c_str(),event->notify_rx.attr_handle); auto characteristic = cVector->cbegin(); for(; characteristic != cVector->cend(); ++characteristic) { if((*characteristic)->m_handle == event->notify_rx.attr_handle) break; } - if(characteristic != cVector->cend()) { NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str()); - + if ((*characteristic)->m_notifyCallback != nullptr) { NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", (*characteristic)->toString().c_str()); (*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); } - + break; } } - + return 0; } // BLE_GAP_EVENT_NOTIFY_RX diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index e2cea9e1..899f9ec1 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -62,7 +62,7 @@ class NimBLEClient { private: - NimBLEClient(); + NimBLEClient(bool preDiscover); ~NimBLEClient(); friend class NimBLEDevice; friend class NimBLERemoteService; @@ -77,10 +77,11 @@ class NimBLEClient { uint16_t m_conn_id; bool m_haveServices = false; // Have we previously obtain the set of services from the remote server. bool m_isConnected = false; // Are we currently connected. - bool m_waitingToConnect =false; + bool m_waitingToConnect = false; bool m_deleteCallbacks = true; int32_t m_connectTimeout; //uint16_t m_mtu = 23; + bool m_preDiscover; NimBLEClientCallbacks* m_pClientCallbacks = nullptr; diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index 1540f632..f061ea0b 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -129,13 +129,13 @@ void NimBLEDevice::stopAdvertising() { * @return A reference to the new client object. */ #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -/* STATIC */ NimBLEClient* NimBLEDevice::createClient() { +/* STATIC */ NimBLEClient* NimBLEDevice::createClient(bool preDiscover) { if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) { NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)", NIMBLE_MAX_CONNECTIONS); } - - NimBLEClient* pClient = new NimBLEClient(); + + NimBLEClient* pClient = new NimBLEClient(preDiscover); m_cList.push_back(pClient); return pClient; diff --git a/src/NimBLEDevice.h b/src/NimBLEDevice.h index c4a6d041..25ea0295 100644 --- a/src/NimBLEDevice.h +++ b/src/NimBLEDevice.h @@ -129,7 +129,7 @@ class NimBLEDevice { #endif #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) - static NimBLEClient* createClient(); + static NimBLEClient* createClient(bool preDiscover = true); static bool deleteClient(NimBLEClient* pClient); static NimBLEClient* getClientByID(uint16_t conn_id); static NimBLEClient* getClientByPeerAddress(const NimBLEAddress &peer_addr); diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index 52b98f25..c276739b 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -113,7 +113,8 @@ bool NimBLERemoteCharacteristic::canNotify() { * @brief Does the characteristic support reading? * @return True if the characteristic supports reading. */ -bool NimBLERemoteCharacteristic::canRead() { +//bool NimBLERemoteCharacteristic::canRead() { +bool NimBLERemoteCharacteristic::canRead() const { return (m_charProp & BLE_GATT_CHR_PROP_READ) != 0; } // canRead @@ -210,8 +211,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(uint16_t endHdl) { return false; } - return true; NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size()); + return true; } // getDescriptors @@ -247,7 +248,6 @@ uint16_t NimBLERemoteCharacteristic::getDefHandle() { */ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) { NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); - for(auto &it: m_descriptorVector) { if(it->getUUID() == uuid) { NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found"); diff --git a/src/NimBLERemoteCharacteristic.h b/src/NimBLERemoteCharacteristic.h index b4748fe0..ce1a0207 100644 --- a/src/NimBLERemoteCharacteristic.h +++ b/src/NimBLERemoteCharacteristic.h @@ -45,7 +45,8 @@ class NimBLERemoteCharacteristic { bool canBroadcast(); bool canIndicate(); bool canNotify(); - bool canRead(); +// bool canRead(); + bool canRead() const; bool canWrite(); bool canWriteNoResponse(); NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid); diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 624de63e..9dc12258 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -80,12 +80,26 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u * @return Reference to the characteristic object, or nullptr if not found. */ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) { + if(!m_haveCharacteristics) { // No characteristics yet, so retrieve the one for uuid + if(retrieveCharacteristic(uuid)) { // Found, so the wanted characteristic is the first in the vector + return m_characteristicVector[0]; + } else { + return nullptr; + } + } if (m_haveCharacteristics) { for(auto &it: m_characteristicVector) { if(it->getUUID() == uuid) { return it; } } + // At this point the characteristic is not found in the vector, so try to retrieve it + if(retrieveCharacteristic(uuid)) { // Found, so the wanted characteristic is the last in the vector + return m_characteristicVector[m_characteristicVector.size()- 1]; + } else { + return nullptr; + } + } return nullptr; @@ -175,19 +189,19 @@ bool NimBLERemoteService::retrieveCharacteristics() { NIMBLE_LOGD(LOG_TAG, "Found UUID: %s Handle: %d Def Handle: %d", (*it)->getUUID().toString().c_str(), (*it)->getHandle(), (*it)->getDefHandle()); // The descriptor handle is between this characteristic val_handle and the next ones def_handle // so make the end of the scan at the handle before the next characteristic def_handle - + // Make sure we don't go past the service end handle if(++it != m_characteristicVector.cend()){ NIMBLE_LOGD(LOG_TAG, "Next UUID: %s Handle: %d Def Handle: %d", (*it)->getUUID().toString().c_str(), (*it)->getHandle(),(*it)->getDefHandle()); - + endHdl = (*it)->getDefHandle()-1; } - else{ + else{ NIMBLE_LOGD(LOG_TAG, "END CHARS"); endHdl = m_endHandle; } --it; - + //If there is no handles between this characteristic and the next there is no descriptor so skip to the next if((*it)->getHandle() != endHdl){ if(!m_pClient->m_isConnected || !(*it)->retrieveDescriptors(endHdl)) { @@ -207,6 +221,48 @@ bool NimBLERemoteService::retrieveCharacteristics() { } // retrieveCharacteristics +/** + * @brief Retrieve only one characteristic for this service. + * This function will not return until we have this characteristic. + * @param [in] uuid Remote characteristic uuid. + * @return N/A + */ +bool NimBLERemoteService::retrieveCharacteristic(const NimBLEUUID &uuid) { + NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristic(%s) for service: %s", std::string(uuid).c_str(), std::string(getUUID()).c_str()); + + int rc = 0; + //removeCharacteristics(); // Forget any previous characteristics. + + m_semaphoreGetCharEvt.take("retrieveCharacteristics"); + + rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), + m_startHandle, + m_endHandle, + &uuid.getNative()->u, + NimBLERemoteService::characteristicDiscCB, + this); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_chrs_by_uuid: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); +// m_haveCharacteristics = false; + m_semaphoreGetCharEvt.give(); + return false; + } + + bool success = (m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0); + m_haveCharacteristics |= success; + if(success){ + NIMBLE_LOGD(LOG_TAG, "Found UUID: %s", std::string(uuid).c_str()); + + NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristic(%s)", std::string(uuid).c_str()); + return true; + } + + NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristic(%s)", std::string(uuid).c_str()); + return false; + +} // retrieveCharacteristics + + /** * @brief Retrieve a vector of all the characteristics of this service. * @return A vector of all the characteristics of this service. diff --git a/src/NimBLERemoteService.h b/src/NimBLERemoteService.h index c13dfb2c..c3386fdb 100644 --- a/src/NimBLERemoteService.h +++ b/src/NimBLERemoteService.h @@ -41,9 +41,7 @@ class NimBLERemoteService { // Public methods NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference. NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid); // Get the specified characteristic reference. -// BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. std::vector* getCharacteristics(); -// void getCharacteristics(std::map* pCharacteristicMap); NimBLEClient* getClient(void); // Get a reference to the client associated with this service. uint16_t getHandle(); // Get the handle of this service. @@ -62,7 +60,8 @@ class NimBLERemoteService { // Private methods bool retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server. - static int characteristicDiscCB(uint16_t conn_handle, + bool retrieveCharacteristic(const NimBLEUUID &uuid); // Retrieve only one characteristic from the BLE Server. + static int characteristicDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg);