Breaking: Use std::vector instead of std::map in client classes (#46)

* Exchange map for vector, saving 1,076 bytes of program memory and 5,024 bytes of heap for a small device (LYWSD03MMC)

* 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)

* Change NimBLEScan container from std::map to std::vector

* Add function to get advertised device by address

* Update documentation
This commit is contained in:
h2zero 2020-05-17 20:21:35 -06:00
parent fc1022a46d
commit 6f4ee4b498
10 changed files with 169 additions and 142 deletions

View file

@ -100,7 +100,7 @@ The `BLEAdvertisedDeviceCallbacks` class `onResult()` method now receives a poin
Defined as: Defined as:
``` ```
bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true); bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true);
bool connect(NimBLEAddress address, uint8_t type = BLE_ADDR_TYPE_PUBLIC, bool refreshServices = true); bool connect(NimBLEAddress address, uint8_t type = BLE_ADDR_PUBLIC, bool refreshServices = true);
``` ```
If set to false the client will use the services database it retrieved from the peripheral last time it connected. If set to false the client will use the services database it retrieved from the peripheral last time it connected.
This allows for faster connections and power saving if the devices just dropped connection and want to reconnect. This allows for faster connections and power saving if the devices just dropped connection and want to reconnect.
@ -111,6 +111,17 @@ NimBLERemoteCharacteristic::registerForNotify();
``` ```
Now return true or false to indicate success or failure so you can choose to disconnect or try again. Now return true or false to indicate success or failure so you can choose to disconnect or try again.
```
NimBLEClient::getServices()
NimBLERemoteService::getCharacteristics()
```
Now return a pointer to a `std::vector` of the respective object database instead of `std::map`.
`NimBLERemoteService::getCharacteristicsByHandle()`
Has been removed from the API as it is no longer maintained in the library.
The last two above changes reduce the heap usage significantly with minimal application code adjustments.
#### Client Security: #### Client Security:
The client will automatically initiate security when the peripheral responds that it's required. The client will automatically initiate security when the peripheral responds that it's required.
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below. The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.

View file

@ -1,7 +1,14 @@
# *** UPDATE *** # *** UPDATE ***
Client long read/write characteristics/descriptors now working. **Breaking change:** Client and scan now use `std::vector` instead of `std::map` for storing the remote attribute database.
We are now nearing 100% replacement of the original cpp_utils BLE library :smile:
This change will affect your application code if you use `NimBLEClient::getServices()` or `NimBLERemoteService::getCharacteristics()`
in your application as they now return a pointer to `std::vector` of the respective attributes.
In addition `NimBLERemoteService::getCharacteristicsByHandle()` has been removed as it is no longer maintained in the library.
These changes were necessary due to the amount of resources required to use `std::map`, it was not justifed by any benfit it provided.
It is expected that there will be minimal impact on most applications, if you need help adjusting your code please create an issue.
# esp-nimble-cpp # esp-nimble-cpp
NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the @nkolban cpp_uitls API. NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the @nkolban cpp_uitls API.

View file

@ -43,8 +43,8 @@ static NimBLEClientCallbacks defaultCallbacks;
* Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own * Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own
* zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors. * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors.
* *
* We will assume that a NimBLERemoteService contains a map that maps NimBLEUUIDs to the set of owned characteristics * We will assume that a NimBLERemoteService contains a vector of owned characteristics
* and that a NimBLECharacteristic contains a map that maps NimBLEUUIDs to the set of owned descriptors. * and that a NimBLECharacteristic contains a vector of owned descriptors.
* *
* *
*/ */
@ -90,10 +90,11 @@ NimBLEClient::~NimBLEClient() {
void NimBLEClient::clearServices() { void NimBLEClient::clearServices() {
NIMBLE_LOGD(LOG_TAG, ">> clearServices"); NIMBLE_LOGD(LOG_TAG, ">> clearServices");
// Delete all the services. // Delete all the services.
for (auto &myPair : m_servicesMap) { for(auto &it: m_servicesVector) {
delete myPair.second; delete it;
} }
m_servicesMap.clear(); m_servicesVector.clear();
m_haveServices = false; m_haveServices = false;
NIMBLE_LOGD(LOG_TAG, "<< clearServices"); NIMBLE_LOGD(LOG_TAG, "<< clearServices");
} // clearServices } // clearServices
@ -368,23 +369,24 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
if (!m_haveServices) { if (!m_haveServices) {
return nullptr; return nullptr;
} }
std::string uuidStr = uuid.toString();
for (auto &myPair : m_servicesMap) { for(auto &it: m_servicesVector) {
if (myPair.first == uuidStr) { if(it->getUUID() == uuid) {
NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
return myPair.second; return it;
} }
} }
NIMBLE_LOGD(LOG_TAG, "<< getService: not found"); NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
return nullptr; return nullptr;
} // getService } // getService
/** /**
* @Get a pointer to the map of found services. * @Get a pointer to the vector of found services.
*/ */
std::map<std::string, NimBLERemoteService*>* NimBLEClient::getServices() { std::vector<NimBLERemoteService*>* NimBLEClient::getServices() {
return &m_servicesMap; return &m_servicesVector;
} }
@ -425,8 +427,8 @@ bool NimBLEClient::retrieveServices() {
// If sucessful, remember that we now have services. // If sucessful, remember that we now have services.
m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0); m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0);
if(m_haveServices){ if(m_haveServices){
for (auto &myPair : m_servicesMap) { for (auto &it: m_servicesVector) {
if(!m_isConnected || !myPair.second->retrieveCharacteristics()) { if(!m_isConnected || !it->retrieveCharacteristics()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting"); NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting");
return false; return false;
} }
@ -463,9 +465,9 @@ int NimBLEClient::serviceDiscoveredCB(
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a service - add it to the map // Found a service - add it to the vector
NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service); NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service);
peer->m_servicesMap.insert(std::pair<std::string, NimBLERemoteService*>(pRemoteService->getUUID().toString(), pRemoteService)); peer->m_servicesVector.push_back(pRemoteService);
break; break;
} }
case BLE_HS_EDONE:{ case BLE_HS_EDONE:{
@ -662,20 +664,25 @@ uint16_t NimBLEClient::getMTU() {
if(!client->m_haveServices) if(!client->m_haveServices)
return 0; return 0;
for(auto &sPair : client->m_servicesMap){ for(auto &it: client->m_servicesVector) {
// Dont waste cycles searching services without this handle in their range // Dont waste cycles searching services without this handle in their range
if(sPair.second->getEndHandle() < event->notify_rx.attr_handle) { if(it->getEndHandle() < event->notify_rx.attr_handle) {
continue; continue;
} }
auto cMap = sPair.second->getCharacteristicsByHandle();
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", sPair.second->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) { auto cVector = it->getCharacteristics();
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", characteristic->second->toString().c_str()); NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", it->getUUID().toString().c_str(),event->notify_rx.attr_handle);
characteristic->second->m_notifyCallback(characteristic->second, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); 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; break;
@ -851,8 +858,9 @@ void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, b
std::string NimBLEClient::toString() { std::string NimBLEClient::toString() {
std::string res = "peer address: " + m_peerAddress.toString(); std::string res = "peer address: " + m_peerAddress.toString();
res += "\nServices:\n"; res += "\nServices:\n";
for (auto &myPair : m_servicesMap) {
res += myPair.second->toString() + "\n"; for(auto &it: m_servicesVector) {
res += it->toString() + "\n";
} }
return res; return res;

View file

@ -24,7 +24,7 @@
#include "NimBLEAdvertisedDevice.h" #include "NimBLEAdvertisedDevice.h"
#include "NimBLERemoteService.h" #include "NimBLERemoteService.h"
#include <map> #include <vector>
#include <string> #include <string>
class NimBLERemoteService; class NimBLERemoteService;
@ -41,7 +41,8 @@ public:
int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); // Disconnect from the remote BLE Server 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 NimBLEAddress getPeerAddress(); // Get the address of the remote BLE Server
int getRssi(); // Get the RSSI of the remote BLE Server int getRssi(); // Get the RSSI of the remote BLE Server
std::map<std::string, NimBLERemoteService*>* getServices(); // Get a map of the services offered by the remote BLE Server
std::vector<NimBLERemoteService*>* 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(const char* uuid); // Get a reference to a specified service offered by the remote BLE server.
NimBLERemoteService* getService(const NimBLEUUID &uuid); // Get a reference to a specified service offered by the remote BLE server. NimBLERemoteService* getService(const NimBLEUUID &uuid); // Get a reference to a specified service offered by the remote BLE server.
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID); // Get the value of a given characteristic at a given service. std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID); // Get the value of a given characteristic at a given service.
@ -87,7 +88,7 @@ private:
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security"); FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security");
std::map<std::string, NimBLERemoteService*> m_servicesMap; std::vector<NimBLERemoteService*> m_servicesVector;
private: private:
friend class NimBLEClientCallbacks; friend class NimBLEClientCallbacks;

View file

@ -157,10 +157,9 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a descriptor - add it to the map // Found a descriptor - add it to the vector
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc); NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
characteristic->m_descriptorMap.insert(std::pair<std::string, NimBLERemoteDescriptor*>(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
break; break;
} }
case BLE_HS_EDONE:{ case BLE_HS_EDONE:{
@ -212,15 +211,15 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(uint16_t endHdl) {
} }
return true; return true;
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size()); NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
} // getDescriptors } // getDescriptors
/** /**
* @brief Retrieve the map of descriptors keyed by UUID. * @brief Retrieve the vector of descriptors.
*/ */
std::map<std::string, NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors() { std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors() {
return &m_descriptorMap; return &m_descriptorVector;
} // getDescriptors } // getDescriptors
@ -248,11 +247,11 @@ uint16_t NimBLERemoteCharacteristic::getDefHandle() {
*/ */
NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) { NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
std::string v = uuid.toString();
for (auto &myPair : m_descriptorMap) { for(auto &it: m_descriptorVector) {
if (myPair.first == v) { if(it->getUUID() == uuid) {
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found"); NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found");
return myPair.second; return it;
} }
} }
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found"); NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
@ -444,19 +443,18 @@ bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallbac
/** /**
* @brief Delete the descriptors in the descriptor map. * @brief Delete the descriptors in the descriptor vector.
* We maintain a map called m_descriptorMap that contains pointers to BLERemoteDescriptors * We maintain a vector called m_descriptorVector that contains pointers to BLERemoteDescriptors
* object references. Since we allocated these in this class, we are also responsible for deleteing * object references. Since we allocated these in this class, we are also responsible for deleteing
* them. This method does just that. * them. This method does just that.
* @return N/A. * @return N/A.
*/ */
void NimBLERemoteCharacteristic::removeDescriptors() { void NimBLERemoteCharacteristic::removeDescriptors() {
// Iterate through all the descriptors releasing their storage and erasing them from the map. // Iterate through all the descriptors releasing their storage and erasing them from the vector.
for (auto &myPair : m_descriptorMap) { for(auto &it: m_descriptorVector) {
m_descriptorMap.erase(myPair.first); delete it;
delete myPair.second;
} }
m_descriptorMap.clear(); // Technically not neeeded, but just to be sure. m_descriptorVector.clear();
} // removeCharacteristics } // removeCharacteristics
@ -478,8 +476,8 @@ std::string NimBLERemoteCharacteristic::toString() {
snprintf(val, sizeof(val), "%02x", m_charProp); snprintf(val, sizeof(val), "%02x", m_charProp);
res += val; res += val;
for (auto &myPair : m_descriptorMap) { for(auto &it: m_descriptorVector) {
res += "\n" + myPair.second->toString(); res += "\n" + it->toString();
} }
return res; return res;
@ -645,8 +643,8 @@ size_t NimBLERemoteCharacteristic::getDataLength() {
void NimBLERemoteCharacteristic::releaseSemaphores() { void NimBLERemoteCharacteristic::releaseSemaphores() {
for (auto &dPair : m_descriptorMap) { for (auto &it: m_descriptorVector) {
dPair.second->releaseSemaphores(); it->releaseSemaphores();
} }
m_semaphoreWriteCharEvt.give(1); m_semaphoreWriteCharEvt.give(1);
m_semaphoreGetDescEvt.give(1); m_semaphoreGetDescEvt.give(1);

View file

@ -26,7 +26,7 @@
#include "NimBLERemoteDescriptor.h" #include "NimBLERemoteDescriptor.h"
//#include <string> //#include <string>
#include <map> #include <vector>
class NimBLERemoteService; class NimBLERemoteService;
class NimBLERemoteDescriptor; class NimBLERemoteDescriptor;
@ -49,7 +49,7 @@ public:
bool canWrite(); bool canWrite();
bool canWriteNoResponse(); bool canWriteNoResponse();
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid); NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
std::map<std::string, NimBLERemoteDescriptor*>* getDescriptors(); std::vector<NimBLERemoteDescriptor*>* getDescriptors();
uint16_t getHandle(); uint16_t getHandle();
uint16_t getDefHandle(); uint16_t getDefHandle();
NimBLEUUID getUUID(); NimBLEUUID getUUID();
@ -98,8 +98,8 @@ private:
size_t m_dataLen; size_t m_dataLen;
notify_callback m_notifyCallback; notify_callback m_notifyCallback;
// We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID. // We maintain a vector of descriptors owned by this characteristic.
std::map<std::string, NimBLERemoteDescriptor*> m_descriptorMap; std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
}; // BLERemoteCharacteristic }; // BLERemoteCharacteristic
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)

View file

@ -81,10 +81,9 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u
*/ */
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) { NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
if (m_haveCharacteristics) { if (m_haveCharacteristics) {
std::string v = uuid.toString(); for(auto &it: m_characteristicVector) {
for (auto &myPair : m_characteristicMap) { if(it->getUUID() == uuid) {
if (myPair.first == v) { return it;
return myPair.second;
} }
} }
} }
@ -112,10 +111,9 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a service - add it to the map // Found a service - add it to the vector
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
service->m_characteristicMap.insert(std::pair<std::string, NimBLERemoteCharacteristic*>(pRemoteCharacteristic->getUUID().toString(), pRemoteCharacteristic)); service->m_characteristicVector.push_back(pRemoteCharacteristic);
service->m_characteristicMapByHandle.insert(std::pair<uint16_t, NimBLERemoteCharacteristic*>(chr->val_handle, pRemoteCharacteristic));
break; break;
} }
case BLE_HS_EDONE:{ case BLE_HS_EDONE:{
@ -171,17 +169,18 @@ bool NimBLERemoteService::retrieveCharacteristics() {
m_haveCharacteristics = (m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0); m_haveCharacteristics = (m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0);
if(m_haveCharacteristics){ if(m_haveCharacteristics){
uint16_t endHdl = 0xFFFF; 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 %d Characteristics", m_characteristicVector.size());
NIMBLE_LOGD(LOG_TAG, "Found UUID: %s Handle: %d Def Handle: %d", (*it).second->getUUID().toString().c_str(), (*it).second->getHandle(), (*it).second->getDefHandle()); 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 // 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 // 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 // Make sure we don't go past the service end handle
if(++it != m_characteristicMapByHandle.cend()){ if(++it != m_characteristicVector.cend()){
NIMBLE_LOGD(LOG_TAG, "Next UUID: %s Handle: %d Def Handle: %d", (*it).second->getUUID().toString().c_str(), (*it).second->getHandle(),(*it).second->getDefHandle()); NIMBLE_LOGD(LOG_TAG, "Next UUID: %s Handle: %d Def Handle: %d", (*it)->getUUID().toString().c_str(), (*it)->getHandle(),(*it)->getDefHandle());
endHdl = (*it).second->getDefHandle()-1; endHdl = (*it)->getDefHandle()-1;
} }
else{ else{
NIMBLE_LOGD(LOG_TAG, "END CHARS"); NIMBLE_LOGD(LOG_TAG, "END CHARS");
@ -190,8 +189,8 @@ bool NimBLERemoteService::retrieveCharacteristics() {
--it; --it;
//If there is no handles between this characteristic and the next there is no descriptor so skip to the next //If there is no handles between this characteristic and the next there is no descriptor so skip to the next
if((*it).second->getHandle() != endHdl){ if((*it)->getHandle() != endHdl){
if(!m_pClient->m_isConnected || !(*it).second->retrieveDescriptors(endHdl)) { if(!m_pClient->m_isConnected || !(*it)->retrieveDescriptors(endHdl)) {
return false; return false;
} }
} }
@ -209,23 +208,14 @@ bool NimBLERemoteService::retrieveCharacteristics() {
/** /**
* @brief Retrieve a map of all the characteristics of this service. * @brief Retrieve a vector of all the characteristics of this service.
* @return A map of all the characteristics of this service. * @return A vector of all the characteristics of this service.
*/ */
std::map<std::string, NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics() { std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics() {
return &m_characteristicMap; return &m_characteristicVector;
} // getCharacteristics } // getCharacteristics
/**
* @brief Retrieve a map of all the characteristics of this service.
* @return A map of all the characteristics of this service.
*/
std::map<uint16_t, NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristicsByHandle() {
return &m_characteristicMapByHandle;
} // getCharacteristicsByHandle
/** /**
* @brief Get the client associated with this service. * @brief Get the client associated with this service.
* @return A reference to the client associated with this service. * @return A reference to the client associated with this service.
@ -301,20 +291,17 @@ bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const s
/** /**
* @brief Delete the characteristics in the characteristics map. * @brief Delete the characteristics in the characteristics vector.
* We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic * We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic
* object references. Since we allocated these in this class, we are also responsible for deleteing * object references. Since we allocated these in this class, we are also responsible for deleting
* them. This method does just that. * them. This method does just that.
* @return N/A. * @return N/A.
*/ */
void NimBLERemoteService::removeCharacteristics() { void NimBLERemoteService::removeCharacteristics() {
m_characteristicMap.clear(); // Clear the map for(auto &it: m_characteristicVector) {
delete it;
for (auto &myPair : m_characteristicMapByHandle) {
delete myPair.second;
} }
m_characteristicMapByHandle.clear(); // Clear the map m_characteristicVector.clear(); // Clear the vector
} // removeCharacteristics } // removeCharacteristics
@ -338,8 +325,8 @@ std::string NimBLERemoteService::toString() {
res += " 0x"; res += " 0x";
res += val; res += val;
for (auto &myPair : m_characteristicMap) { for (auto &it: m_characteristicVector) {
res += "\n" + myPair.second->toString(); res += "\n" + it->toString();
} }
return res; return res;
@ -351,8 +338,8 @@ std::string NimBLERemoteService::toString() {
* Will release all characteristic and subsequently all descriptor semaphores for this service. * Will release all characteristic and subsequently all descriptor semaphores for this service.
*/ */
void NimBLERemoteService::releaseSemaphores() { void NimBLERemoteService::releaseSemaphores() {
for (auto &cPair : m_characteristicMapByHandle) { for(auto &it: m_characteristicVector) {
cPair.second->releaseSemaphores(); it->releaseSemaphores();
} }
m_semaphoreGetCharEvt.give(1); m_semaphoreGetCharEvt.give(1);
} }

View file

@ -25,7 +25,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "NimBLERemoteCharacteristic.h" #include "NimBLERemoteCharacteristic.h"
#include <map> #include <vector>
class NimBLEClient; class NimBLEClient;
class NimBLERemoteCharacteristic; class NimBLERemoteCharacteristic;
@ -42,8 +42,7 @@ public:
NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference. NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference.
NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &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. // BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference.
std::map<std::string, NimBLERemoteCharacteristic*>* getCharacteristics(); std::vector<NimBLERemoteCharacteristic*>* getCharacteristics();
std::map<uint16_t, NimBLERemoteCharacteristic*>* getCharacteristicsByHandle(); // Get the characteristics map.
// void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap); // void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap);
NimBLEClient* getClient(void); // Get a reference to the client associated with this service. NimBLEClient* getClient(void); // Get a reference to the client associated with this service.
@ -74,11 +73,8 @@ private:
// Properties // Properties
// We maintain a map of characteristics owned by this service keyed by a string representation of the UUID. // We maintain a vector of characteristics owned by this service.
std::map<std::string, NimBLERemoteCharacteristic*> m_characteristicMap; std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
// We maintain a map of characteristics owned by this service keyed by a handle.
std::map<uint16_t, NimBLERemoteCharacteristic*> m_characteristicMapByHandle;
bool m_haveCharacteristics; // Have we previously obtained the characteristics. bool m_haveCharacteristics; // Have we previously obtained the characteristics.
NimBLEClient* m_pClient; NimBLEClient* m_pClient;

View file

@ -117,13 +117,15 @@ NimBLEScan::NimBLEScan() {
NimBLEAdvertisedDevice* advertisedDevice = nullptr; NimBLEAdvertisedDevice* advertisedDevice = nullptr;
// If we've seen this device before get a pointer to it from the map // If we've seen this device before get a pointer to it from the vector
auto it = pScan->m_scanResults.m_advertisedDevicesMap.find(advertisedAddress.toString()); for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
if(it != pScan->m_scanResults.m_advertisedDevicesMap.cend()) { if(it->getAddress() == advertisedAddress) {
advertisedDevice = (*it).second; advertisedDevice = it;
break;
}
} }
// If we haven't seen this device before; create a new instance and insert it in the map. // If we haven't seen this device before; create a new instance and insert it in the vector.
// Otherwise just update the relevant parameters of the already known device. // Otherwise just update the relevant parameters of the already known device.
if(advertisedDevice == nullptr){ if(advertisedDevice == nullptr){
advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice = new NimBLEAdvertisedDevice();
@ -131,7 +133,7 @@ NimBLEScan::NimBLEScan() {
advertisedDevice->setAddress(advertisedAddress); advertisedDevice->setAddress(advertisedAddress);
//NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type)); //NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type));
advertisedDevice->setAdvType(event->disc.event_type); advertisedDevice->setAdvType(event->disc.event_type);
pScan->m_scanResults.m_advertisedDevicesMap.insert(std::pair<std::string, NimBLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice)); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str());
} }
else{ else{
@ -262,7 +264,7 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
} }
// if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals // if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
// then we should not clear map or we will connect the same device few times // then we should not clear vector or we will connect the same device few times
if(!is_continue) { if(!is_continue) {
clearResults(); clearResults();
} }
@ -330,9 +332,14 @@ void NimBLEScan::stop() {
// delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address // delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address
void NimBLEScan::erase(const NimBLEAddress &address) { void NimBLEScan::erase(const NimBLEAddress &address) {
NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
NimBLEAdvertisedDevice *advertisedDevice = m_scanResults.m_advertisedDevicesMap.find(address.toString())->second;
m_scanResults.m_advertisedDevicesMap.erase(address.toString()); for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.begin(); ++it) {
delete advertisedDevice; if((*it)->getAddress() == address) {
delete *it;
m_scanResults.m_advertisedDevicesVector.erase(it);
break;
}
}
} }
@ -359,10 +366,10 @@ NimBLEScanResults NimBLEScan::getResults() {
* @brief Clear the results of the scan. * @brief Clear the results of the scan.
*/ */
void NimBLEScan::clearResults() { void NimBLEScan::clearResults() {
for(auto _dev : m_scanResults.m_advertisedDevicesMap){ for(auto &it: m_scanResults.m_advertisedDevicesVector) {
delete _dev.second; delete it;
} }
m_scanResults.m_advertisedDevicesMap.clear(); m_scanResults.m_advertisedDevicesVector.clear();
} }
@ -382,7 +389,7 @@ void NimBLEScanResults::dump() {
* @return The number of devices found in the last scan. * @return The number of devices found in the last scan.
*/ */
int NimBLEScanResults::getCount() { int NimBLEScanResults::getCount() {
return m_advertisedDevicesMap.size(); return m_advertisedDevicesVector.size();
} // getCount } // getCount
@ -393,14 +400,24 @@ int NimBLEScanResults::getCount() {
* @return The device at the specified index. * @return The device at the specified index.
*/ */
NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) { NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) {
uint32_t x = 0; return *m_advertisedDevicesVector[i];
NimBLEAdvertisedDevice dev = *m_advertisedDevicesMap.begin()->second; }
for (auto it = m_advertisedDevicesMap.begin(); it != m_advertisedDevicesMap.end(); it++) {
dev = *it->second;
if (x==i) break; /**
x++; * @brief Return a pointer to the specified device at the given address.
* If the address is not found a nullptr is returned.
* @param [in] address The address of the device.
* @return A pointer to the device at the specified address.
*/
NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &address) {
for(size_t index = 0; index < m_advertisedDevicesVector.size(); index++) {
if(m_advertisedDevicesVector[index]->getAddress() == address) {
return m_advertisedDevicesVector[index];
} }
return dev; }
return nullptr;
} }
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)

View file

@ -24,12 +24,13 @@
#include "host/ble_gap.h" #include "host/ble_gap.h"
#include <map> #include <vector>
class NimBLEDevice; class NimBLEDevice;
class NimBLEScan; class NimBLEScan;
class NimBLEAdvertisedDevice; class NimBLEAdvertisedDevice;
class NimBLEAdvertisedDeviceCallbacks; class NimBLEAdvertisedDeviceCallbacks;
class NimBLEAddress;
/** /**
* @brief The result of having performed a scan. * @brief The result of having performed a scan.
@ -43,10 +44,11 @@ public:
void dump(); void dump();
int getCount(); int getCount();
NimBLEAdvertisedDevice getDevice(uint32_t i); NimBLEAdvertisedDevice getDevice(uint32_t i);
NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address);
private: private:
friend NimBLEScan; friend NimBLEScan;
std::map<std::string, NimBLEAdvertisedDevice*> m_advertisedDevicesMap; std::vector<NimBLEAdvertisedDevice*> m_advertisedDevicesVector;
}; };
/** /**