From 8bdb1bb15e8ae8ff41fc2d9fb36e4a3eefce6745 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Sat, 9 May 2020 13:29:37 +0200 Subject: [PATCH 1/4] Exchange map for vector, saving 1,076 bytes of program memory and 5,024 bytes of heap for a small device (LYWSD03MMC) --- src/NimBLEClient.cpp | 63 ++++++++++++++++++++++++++++-- src/NimBLEClient.h | 9 ++++- src/NimBLERemoteCharacteristic.cpp | 38 +++++++++++++++--- src/NimBLERemoteCharacteristic.h | 8 ++-- src/NimBLERemoteService.cpp | 34 ++++++++++++++-- src/NimBLERemoteService.h | 9 ++++- 6 files changed, 141 insertions(+), 20 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 022fecb7..855dadfe 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -87,10 +87,17 @@ NimBLEClient::~NimBLEClient() { void NimBLEClient::clearServices() { NIMBLE_LOGD(LOG_TAG, ">> clearServices"); // Delete all the services. +/* for (auto &myPair : m_servicesMap) { delete myPair.second; } m_servicesMap.clear(); +*/ + for(auto &it: m_servicesVector) { + delete it; + } + m_servicesVector.clear(); + m_haveServices = false; NIMBLE_LOGD(LOG_TAG, "<< clearServices"); } // clearServices @@ -365,6 +372,7 @@ NimBLERemoteService* NimBLEClient::getService(NimBLEUUID uuid) { if (!m_haveServices) { return nullptr; } +/* std::string uuidStr = uuid.toString(); for (auto &myPair : m_servicesMap) { if (myPair.first == uuidStr) { @@ -372,17 +380,29 @@ NimBLERemoteService* NimBLEClient::getService(NimBLEUUID uuid) { return myPair.second; } } +*/ + for(auto &it: m_servicesVector) { + if(it->getUUID() == 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; } // getService /** - * @Get a pointer to the map of found services. + * @Get a pointer to the vector of found services. */ +/* std::map* NimBLEClient::getServices() { return &m_servicesMap; } +*/ +std::vector* NimBLEClient::getServices() { + return &m_servicesVector; +} /** @@ -422,12 +442,20 @@ bool NimBLEClient::retrieveServices() { // If sucessful, remember that we now have services. m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0); if(m_haveServices){ +/* for (auto &myPair : m_servicesMap) { if(!m_isConnected || !myPair.second->retrieveCharacteristics()) { NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting"); return false; } } +*/ + 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; @@ -460,9 +488,12 @@ int NimBLEClient::serviceDiscoveredCB( switch (error->status) { case 0: { - // Found a service - add it to the map + // Found a service - add it to the vector NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service); +/* peer->m_servicesMap.insert(std::pair(pRemoteService->getUUID().toString(), pRemoteService)); +*/ + peer->m_servicesVector.push_back(pRemoteService); break; } case BLE_HS_EDONE:{ @@ -658,7 +689,8 @@ uint16_t NimBLEClient::getMTU() { NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle); if(!client->m_haveServices) return 0; - + +/* for(auto &sPair : client->m_servicesMap){ // Dont waste cycles searching services without this handle in their range if(sPair.second->getEndHandle() < event->notify_rx.attr_handle) { @@ -678,6 +710,26 @@ uint16_t NimBLEClient::getMTU() { break; } } +*/ + for(auto &it: client->m_servicesVector) { + // Dont waste cycles searching services without this handle in their range + if(it->getEndHandle() < event->notify_rx.attr_handle) { + continue; + } + auto cMap = it->getCharacteristicsByHandle(); + NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", it->getUUID().toString().c_str(),event->notify_rx.attr_handle); + auto characteristic = cMap->find(event->notify_rx.attr_handle); + if(characteristic != cMap->end()) { + NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", characteristic->second->toString().c_str()); + + if (characteristic->second->m_notifyCallback != nullptr) { + NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", characteristic->second->toString().c_str()); + characteristic->second->m_notifyCallback(characteristic->second, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); + } + + break; + } + } return 0; } // BLE_GAP_EVENT_NOTIFY_RX @@ -848,9 +900,14 @@ void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, b std::string NimBLEClient::toString() { std::string res = "peer address: " + m_peerAddress.toString(); res += "\nServices:\n"; +/* for (auto &myPair : m_servicesMap) { res += myPair.second->toString() + "\n"; } +*/ + for(auto &it: m_servicesVector) { + res += it->toString() + "\n"; + } return res; } // toString diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index 14d14bfc..72069c88 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -21,7 +21,8 @@ #include "NimBLEAdvertisedDevice.h" #include "NimBLERemoteService.h" -#include +//#include +#include #include class NimBLERemoteService; @@ -38,7 +39,10 @@ class NimBLEClient { int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); // Disconnect from the remote BLE Server NimBLEAddress getPeerAddress(); // Get the address of the remote BLE Server int getRssi(); // Get the RSSI of the remote BLE Server +/* std::map* getServices(); // Get a map of the services offered by the remote BLE Server +*/ + std::vector* getServices(); // Get a vector of the services offered by the remote BLE Server NimBLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server. NimBLERemoteService* getService(NimBLEUUID uuid); // Get a reference to a specified service offered by the remote BLE server. std::string getValue(NimBLEUUID serviceUUID, NimBLEUUID characteristicUUID); // Get the value of a given characteristic at a given service. @@ -84,7 +88,10 @@ class NimBLEClient { FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security"); +/* std::map m_servicesMap; +*/ + std::vector m_servicesVector; private: friend class NimBLEClientCallbacks; diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index a48354c5..b8f1cffe 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -152,7 +152,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle, case 0: { // Found a descriptor - add it to the map NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc); - characteristic->m_descriptorMap.insert(std::pair(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); +// characteristic->m_descriptorMap.insert(std::pair(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); + characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor); break; } @@ -205,15 +206,16 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(uint16_t endHdl) { } return true; - NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size()); +// NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size()); + NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size()); } // getDescriptors /** * @brief Retrieve the map of descriptors keyed by UUID. */ -std::map* NimBLERemoteCharacteristic::getDescriptors() { - return &m_descriptorMap; +std::vector* NimBLERemoteCharacteristic::getDescriptors() { + return &m_descriptorVector; } // getDescriptors @@ -241,6 +243,7 @@ uint16_t NimBLERemoteCharacteristic::getDefHandle() { */ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(NimBLEUUID uuid) { NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); +/* std::string v = uuid.toString(); for (auto &myPair : m_descriptorMap) { if (myPair.first == v) { @@ -248,6 +251,13 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(NimBLEUUID uui return myPair.second; } } +*/ + for(auto &it: m_descriptorVector) { + if(it->getUUID() == uuid) { + NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found"); + return it; + } + } NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found"); return nullptr; } // getDescriptor @@ -450,12 +460,19 @@ bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallbac * @return N/A. */ void NimBLERemoteCharacteristic::removeDescriptors() { +/* // Iterate through all the descriptors releasing their storage and erasing them from the map. for (auto &myPair : m_descriptorMap) { m_descriptorMap.erase(myPair.first); delete myPair.second; } m_descriptorMap.clear(); // Technically not neeeded, but just to be sure. +*/ + // Iterate through all the descriptors releasing their storage and erasing them from the vector. + for(auto &it: m_descriptorVector) { + delete it; + } + m_descriptorVector.clear(); } // removeCharacteristics @@ -476,11 +493,15 @@ std::string NimBLERemoteCharacteristic::toString() { res += " 0x"; snprintf(val, sizeof(val), "%02x", m_charProp); res += val; - +/* for (auto &myPair : m_descriptorMap) { res += "\n" + myPair.second->toString(); } - +*/ + for(auto &it: m_descriptorVector) { + res += "\n" + it->toString(); + } + return res; } // toString @@ -621,9 +642,14 @@ uint8_t* NimBLERemoteCharacteristic::readRawData() { void NimBLERemoteCharacteristic::releaseSemaphores() { +/* for (auto &dPair : m_descriptorMap) { dPair.second->releaseSemaphores(); } +*/ + for (auto &it: m_descriptorVector) { + it->releaseSemaphores(); + } m_semaphoreWriteCharEvt.give(1); m_semaphoreGetDescEvt.give(1); m_semaphoreReadCharEvt.give(1); diff --git a/src/NimBLERemoteCharacteristic.h b/src/NimBLERemoteCharacteristic.h index c107be79..949b5845 100644 --- a/src/NimBLERemoteCharacteristic.h +++ b/src/NimBLERemoteCharacteristic.h @@ -23,7 +23,7 @@ #include "NimBLERemoteDescriptor.h" //#include -#include +#include class NimBLERemoteService; class NimBLERemoteDescriptor; @@ -46,7 +46,7 @@ class NimBLERemoteCharacteristic { bool canWrite(); bool canWriteNoResponse(); NimBLERemoteDescriptor* getDescriptor(NimBLEUUID uuid); - std::map* getDescriptors(); + std::vector* getDescriptors(); uint16_t getHandle(); uint16_t getDefHandle(); NimBLEUUID getUUID(); @@ -93,8 +93,8 @@ class NimBLERemoteCharacteristic { uint8_t* m_rawData = nullptr; notify_callback m_notifyCallback; - // We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID. - std::map m_descriptorMap; + // We maintain a vector of descriptors owned by this characteristic. + std::vector m_descriptorVector; }; // BLERemoteCharacteristic #endif /* CONFIG_BT_ENABLED */ #endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */ diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 28c2cc33..86712f85 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -78,12 +78,19 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u */ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(NimBLEUUID uuid) { if (m_haveCharacteristics) { +/* std::string v = uuid.toString(); for (auto &myPair : m_characteristicMap) { if (myPair.first == v) { return myPair.second; } } +*/ + for(auto &it: m_characteristicVector) { + if(it->getUUID() == uuid) { + return it; + } + } } return nullptr; @@ -111,7 +118,10 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, case 0: { // Found a service - add it to the map NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); +/* service->m_characteristicMap.insert(std::pair(pRemoteCharacteristic->getUUID().toString(), pRemoteCharacteristic)); +*/ + service->m_characteristicVector.push_back(pRemoteCharacteristic); service->m_characteristicMapByHandle.insert(std::pair(chr->val_handle, pRemoteCharacteristic)); break; } @@ -206,12 +216,17 @@ bool NimBLERemoteService::retrieveCharacteristics() { /** - * @brief Retrieve a map of all the characteristics of this service. - * @return A map of all the characteristics of this service. + * @brief Retrieve a vector of all the characteristics of this service. + * @return A vector of all the characteristics of this service. */ +/* std::map* NimBLERemoteService::getCharacteristics() { return &m_characteristicMap; } // getCharacteristics +*/ +std::vector* NimBLERemoteService::getCharacteristics() { + return &m_characteristicVector; +} // getCharacteristics /** @@ -305,8 +320,14 @@ bool NimBLERemoteService::setValue(NimBLEUUID characteristicUuid, std::string va * @return N/A. */ void NimBLERemoteService::removeCharacteristics() { +/* m_characteristicMap.clear(); // Clear the map - +*/ + for(auto &it: m_characteristicVector) { + delete it; + } + m_characteristicVector.clear(); // Clear the vector + for (auto &myPair : m_characteristicMapByHandle) { delete myPair.second; } @@ -334,10 +355,15 @@ std::string NimBLERemoteService::toString() { snprintf(val, sizeof(val), "%04x", m_endHandle); res += " 0x"; res += val; - + +/* for (auto &myPair : m_characteristicMap) { res += "\n" + myPair.second->toString(); } +*/ + for (auto &it: m_characteristicVector) { + res += "\n" + it->toString(); + } return res; } // toString diff --git a/src/NimBLERemoteService.h b/src/NimBLERemoteService.h index bef8f0b5..94fcb844 100644 --- a/src/NimBLERemoteService.h +++ b/src/NimBLERemoteService.h @@ -22,7 +22,7 @@ #include "FreeRTOS.h" #include "NimBLERemoteCharacteristic.h" -#include +#include class NimBLEClient; class NimBLERemoteCharacteristic; @@ -39,7 +39,8 @@ class NimBLERemoteService { NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference. NimBLERemoteCharacteristic* getCharacteristic(NimBLEUUID uuid); // Get the specified characteristic reference. // BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. - std::map* getCharacteristics(); +// std::map* getCharacteristics(); + std::vector* getCharacteristics(); std::map* getCharacteristicsByHandle(); // Get the characteristics map. // void getCharacteristics(std::map* pCharacteristicMap); @@ -71,8 +72,12 @@ class NimBLERemoteService { // Properties +/* // We maintain a map of characteristics owned by this service keyed by a string representation of the UUID. std::map m_characteristicMap; +*/ + // We maintain a vector of characteristics owned by this service. + std::vector m_characteristicVector; // We maintain a map of characteristics owned by this service keyed by a handle. std::map m_characteristicMapByHandle; From c8f179ca3c2f938e1f8d33e2f06835ca2c49433e Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Sat, 9 May 2020 14:30:46 +0200 Subject: [PATCH 2/4] Removing m_characteristicMapByHandle (using the handles form m_characteristicVector instead) saving in total (compared to the current master) 1,508 bytes of program memory and 6,500 bytes of heap for a small device (LYWSD03MMC) --- src/NimBLEClient.cpp | 25 ++++++++++++++++------- src/NimBLERemoteService.cpp | 40 ++++++++++++++++++++++++++++++++++++- src/NimBLERemoteService.h | 4 +++- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 855dadfe..6befbd88 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -716,15 +716,26 @@ uint16_t NimBLEClient::getMTU() { if(it->getEndHandle() < event->notify_rx.attr_handle) { continue; } - auto cMap = it->getCharacteristicsByHandle(); +// auto cMap = it->getCharacteristicsByHandle(); + 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 = cMap->find(event->notify_rx.attr_handle); - if(characteristic != cMap->end()) { - NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", characteristic->second->toString().c_str()); +// auto characteristic = cMap->find(event->notify_rx.attr_handle); + auto characteristic = cVector->cbegin(); +// for(auto &characteristic: *cVector) { + for(; characteristic != cVector->cend(); ++characteristic) { + if((*characteristic)->m_handle == event->notify_rx.attr_handle) break; + } +// if(characteristic != cMap->end()) { + if(characteristic != cVector->cend()) { +// NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", characteristic->second->toString().c_str()); + NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str()); - if (characteristic->second->m_notifyCallback != nullptr) { - NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", characteristic->second->toString().c_str()); - characteristic->second->m_notifyCallback(characteristic->second, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); +// if (characteristic->second->m_notifyCallback != nullptr) { + if ((*characteristic)->m_notifyCallback != nullptr) { +// NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", characteristic->second->toString().c_str()); + NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", (*characteristic)->toString().c_str()); +// characteristic->second->m_notifyCallback(characteristic->second, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); + (*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); } break; diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 86712f85..96b49b90 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -122,7 +122,9 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, service->m_characteristicMap.insert(std::pair(pRemoteCharacteristic->getUUID().toString(), pRemoteCharacteristic)); */ service->m_characteristicVector.push_back(pRemoteCharacteristic); +/* service->m_characteristicMapByHandle.insert(std::pair(chr->val_handle, pRemoteCharacteristic)); +*/ break; } case BLE_HS_EDONE:{ @@ -178,6 +180,7 @@ bool NimBLERemoteService::retrieveCharacteristics() { m_haveCharacteristics = (m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0); if(m_haveCharacteristics){ uint16_t endHdl = 0xFFFF; +/* NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics", m_characteristicMapByHandle.size()); for (auto it = m_characteristicMapByHandle.cbegin(); it != m_characteristicMapByHandle.cend(); ++it) { NIMBLE_LOGD(LOG_TAG, "Found UUID: %s Handle: %d Def Handle: %d", (*it).second->getUUID().toString().c_str(), (*it).second->getHandle(), (*it).second->getDefHandle()); @@ -204,6 +207,33 @@ bool NimBLERemoteService::retrieveCharacteristics() { } //NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics in service UUID: %s", chars->size(), myPair.first.c_str()); } +*/ + NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics", m_characteristicVector.size()); + for(auto it = m_characteristicVector.cbegin(); it != m_characteristicVector.cend(); ++it) { + 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{ + 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)) { + return false; + } + } + //NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics in service UUID: %s", chars->size(), myPair.first.c_str()); + } NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); return true; @@ -233,9 +263,11 @@ std::vector* NimBLERemoteService::getCharacteristic * @brief Retrieve a map of all the characteristics of this service. * @return A map of all the characteristics of this service. */ +/* std::map* NimBLERemoteService::getCharacteristicsByHandle() { return &m_characteristicMapByHandle; } // getCharacteristicsByHandle +*/ /** @@ -328,11 +360,12 @@ void NimBLERemoteService::removeCharacteristics() { } m_characteristicVector.clear(); // Clear the vector +/* for (auto &myPair : m_characteristicMapByHandle) { delete myPair.second; } m_characteristicMapByHandle.clear(); // Clear the map - +*/ } // removeCharacteristics @@ -374,9 +407,14 @@ std::string NimBLERemoteService::toString() { * Will release all characteristic and subsequently all descriptor semaphores for this service. */ void NimBLERemoteService::releaseSemaphores() { +/* for (auto &cPair : m_characteristicMapByHandle) { cPair.second->releaseSemaphores(); } +*/ + for(auto &it: m_characteristicVector) { + it->releaseSemaphores(); + } m_semaphoreGetCharEvt.give(1); } diff --git a/src/NimBLERemoteService.h b/src/NimBLERemoteService.h index 94fcb844..e661a912 100644 --- a/src/NimBLERemoteService.h +++ b/src/NimBLERemoteService.h @@ -41,7 +41,7 @@ class NimBLERemoteService { // BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. // std::map* getCharacteristics(); std::vector* getCharacteristics(); - std::map* getCharacteristicsByHandle(); // Get the characteristics map. +// std::map* getCharacteristicsByHandle(); // Get the characteristics map. // void getCharacteristics(std::map* pCharacteristicMap); NimBLEClient* getClient(void); // Get a reference to the client associated with this service. @@ -79,8 +79,10 @@ class NimBLERemoteService { // We maintain a vector of characteristics owned by this service. std::vector m_characteristicVector; +/* // We maintain a map of characteristics owned by this service keyed by a handle. std::map m_characteristicMapByHandle; +*/ bool m_haveCharacteristics; // Have we previously obtained the characteristics. NimBLEClient* m_pClient; From 5a34d790ad1481ad91f9f00a93711398e35588b0 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Sun, 10 May 2020 11:32:48 +0200 Subject: [PATCH 3/4] WIP --- src/NimBLEClient.cpp | 28 +++++++++++-------- src/NimBLEClient.h | 7 +++-- src/NimBLEDevice.cpp | 4 +-- src/NimBLEDevice.h | 10 +++---- src/NimBLERemoteService.cpp | 55 ++++++++++++++++++++++++++++++++++++- src/NimBLERemoteService.h | 1 + 6 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 6befbd88..cb4d02f3 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -46,22 +46,24 @@ static NimBLEClientCallbacks defaultCallbacks; * */ -NimBLEClient::NimBLEClient() +NimBLEClient::NimBLEClient(bool preDiscover) { m_pClientCallbacks = &defaultCallbacks; m_conn_id = BLE_HS_CONN_HANDLE_NONE; m_haveServices = false; m_isConnected = false; - m_connectTimeout = 30000; + m_connectTimeout = 30000; - m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default) + m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default) m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default) - m_pConnParams.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; // min_int = 0x10*1.25ms = 20ms - m_pConnParams.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; // max_int = 0x20*1.25ms = 40ms - m_pConnParams.latency = BLE_GAP_INITIAL_CONN_LATENCY; // number of packets allowed to skip (extends max interval) - m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms + m_pConnParams.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; // min_int = 0x10*1.25ms = 20ms + m_pConnParams.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; // max_int = 0x20*1.25ms = 40ms + m_pConnParams.latency = BLE_GAP_INITIAL_CONN_LATENCY; // number of packets allowed to skip (extends max interval) + 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_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units + + m_preDiscover = preDiscover; } // NimBLEClient @@ -450,10 +452,12 @@ bool NimBLEClient::retrieveServices() { } } */ - 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; + } } } diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index 72069c88..8552351e 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; + 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 d85eae1f..250dbb6a 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -115,13 +115,13 @@ void NimBLEDevice::stopAdvertising() { * each client can connect to 1 peripheral device. * @return A reference to the new client object. */ -/* 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 b2731c23..be32b6f3 100644 --- a/src/NimBLEDevice.h +++ b/src/NimBLEDevice.h @@ -82,11 +82,11 @@ class NimBLEDevice { static NimBLEAddress getAddress(); static std::string toString(); static NimBLEScan* getScan(); // Get the scan object - static NimBLEClient* createClient(); - static NimBLEServer* createServer(); + static NimBLEClient* createClient(bool preDiscover = true); + static NimBLEServer* createServer(); static bool deleteClient(NimBLEClient* pClient); static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); - static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); + static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); static void setCustomGapHandler(gap_event_handler handler); static void setSecurityAuth(bool bonding, bool mitm, bool sc); static void setSecurityAuth(uint8_t auth_req); @@ -102,8 +102,8 @@ class NimBLEDevice { static void addIgnored(NimBLEAddress address); static void removeIgnored(NimBLEAddress address); static NimBLEAdvertising* getAdvertising(); - static void startAdvertising(); - static void stopAdvertising(); + static void startAdvertising(); + static void stopAdvertising(); static NimBLEClient* getClientByID(uint16_t conn_id); static NimBLEClient* getClientByPeerAddress(NimBLEAddress peer_addr); static NimBLEClient* getDisconnectedClient(); diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 96b49b90..021a33f3 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -121,7 +121,18 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, /* service->m_characteristicMap.insert(std::pair(pRemoteCharacteristic->getUUID().toString(), pRemoteCharacteristic)); */ - service->m_characteristicVector.push_back(pRemoteCharacteristic); + auto it = service->m_characteristicVector.begin(); + for(; it != service->m_characteristicVector.end(); ++it) { + if((*it)->getUUID() == pRemoteCharacteristic->getUUID()) { // This characteristic was found earlier, so delete it + NIMBLE_LOGD(LOG_TAG,"Characteristic %s found earlier, replacing", std::string(it->uuid).c_str()); + delete *it; + *it = pRemoteCharacteristic; + break; + } + } + if(it == service->m_characteristicVector.end()) { + service->m_characteristicVector.push_back(pRemoteCharacteristic); + } /* service->m_characteristicMapByHandle.insert(std::pair(chr->val_handle, pRemoteCharacteristic)); */ @@ -245,6 +256,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, "<< retrieveCharacteristics()"); + return true; + } + + NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristics"); + 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 e661a912..0c093f9d 100644 --- a/src/NimBLERemoteService.h +++ b/src/NimBLERemoteService.h @@ -61,6 +61,7 @@ class NimBLERemoteService { // Private methods bool retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server. + 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); From 67701b395b0f0e8d1337e84e846cf5fb70a9aa67 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Sun, 10 May 2020 13:05:24 +0200 Subject: [PATCH 4/4] Optional no automatic discovery of characteristics and descriptors, leading to faster connections, less heap usage and less drainage of the peripheral's battery. Characteristics are retrieved only when needed --- src/NimBLERemoteCharacteristic.cpp | 5 +++-- src/NimBLERemoteCharacteristic.h | 5 +++-- src/NimBLERemoteService.cpp | 27 +++++++++++++++++++++------ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index eab396c2..25de823c 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -110,7 +110,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 @@ -216,7 +217,7 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(uint16_t endHdl) { /** - * @brief Retrieve the map of descriptors keyed by UUID. + * @brief Retrieve the vector of descriptors keyed by UUID. */ std::vector* NimBLERemoteCharacteristic::getDescriptors() { return &m_descriptorVector; diff --git a/src/NimBLERemoteCharacteristic.h b/src/NimBLERemoteCharacteristic.h index 88cf293f..ca738252 100644 --- a/src/NimBLERemoteCharacteristic.h +++ b/src/NimBLERemoteCharacteristic.h @@ -42,10 +42,11 @@ class NimBLERemoteCharacteristic { bool canBroadcast(); bool canIndicate(); bool canNotify(); - bool canRead(); +// bool canRead(); + bool canRead() const; bool canWrite(); bool canWriteNoResponse(); - NimBLERemoteDescriptor* getDescriptor(NimBLEUUID uuid); + NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid); std::vector* getDescriptors(); uint16_t getHandle(); uint16_t getDefHandle(); diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 4168e470..a735a898 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -77,6 +77,13 @@ 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) { /* std::string v = uuid.toString(); @@ -91,6 +98,13 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU 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; @@ -124,9 +138,10 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, auto it = service->m_characteristicVector.begin(); for(; it != service->m_characteristicVector.end(); ++it) { if((*it)->getUUID() == pRemoteCharacteristic->getUUID()) { // This characteristic was found earlier, so delete it - NIMBLE_LOGD(LOG_TAG,"Characteristic %s found earlier, replacing", std::string(it->uuid).c_str()); - delete *it; - *it = pRemoteCharacteristic; + NIMBLE_LOGD(LOG_TAG,"Characteristic %s already found", std::string((*it)->getUUID()).c_str()); +// delete *it; +// *it = pRemoteCharacteristic; + delete pRemoteCharacteristic; break; } } @@ -273,7 +288,7 @@ bool NimBLERemoteService::retrieveCharacteristic(const NimBLEUUID &uuid) { rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), m_startHandle, m_endHandle, - uuid.getNative()->u, + &uuid.getNative()->u, NimBLERemoteService::characteristicDiscCB, this); if (rc != 0) { @@ -288,11 +303,11 @@ bool NimBLERemoteService::retrieveCharacteristic(const NimBLEUUID &uuid) { if(success){ NIMBLE_LOGD(LOG_TAG, "Found UUID: %s", std::string(uuid).c_str()); - NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); + NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristic(%s)", std::string(uuid).c_str()); return true; } - NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristics"); + NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristic(%s)", std::string(uuid).c_str()); return false; } // retrieveCharacteristics