From 7dd4d6880632d7a75c52a952b710bb1ce58c626f Mon Sep 17 00:00:00 2001 From: David Robertson Date: Mon, 8 Feb 2021 15:28:32 +0000 Subject: [PATCH] [NimBLEServer] Support duplicate characteristics (#36) * Add method to get all characteristics of a service * Added method on NimBLEDescriptor to get the value out as a std::string * Added methods to get things by handle where UUID could be used already. * Added helper methods for getting a list of characteristics with a given UUID and service * Demote the warning log for adding duplicate characteristics to a debug level log. * Add methods to get services and characteristics using UUID + index --- src/NimBLECharacteristic.cpp | 26 +++++++++++---- src/NimBLECharacteristic.h | 29 ++++++++++------- src/NimBLEDescriptor.cpp | 10 ++++-- src/NimBLEDescriptor.h | 15 +++++---- src/NimBLEServer.cpp | 37 +++++++++++++++------ src/NimBLEServer.h | 5 +-- src/NimBLEService.cpp | 62 ++++++++++++++++++++++++++++++------ src/NimBLEService.h | 26 ++++++++++----- 8 files changed, 157 insertions(+), 53 deletions(-) diff --git a/src/NimBLECharacteristic.cpp b/src/NimBLECharacteristic.cpp index e9a5a49..c820b2b 100644 --- a/src/NimBLECharacteristic.cpp +++ b/src/NimBLECharacteristic.cpp @@ -101,9 +101,9 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, /** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] uuid The UUID of the descriptor that we wish to retrieve. - * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + * @brief Return the BLE Descriptor for the given UUID. + * @param [in] uuid The UUID of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. */ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { return getDescriptorByUUID(NimBLEUUID(uuid)); @@ -111,9 +111,9 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { /** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] uuid The UUID of the descriptor that we wish to retrieve. - * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + * @brief Return the BLE Descriptor for the given UUID. + * @param [in] uuid The UUID of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. */ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) { for (auto &it : m_dscVec) { @@ -124,6 +124,20 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uu return nullptr; } // getDescriptorByUUID +/** + * @brief Return the BLE Descriptor for the given handle. + * @param [in] uuid The handle of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. + */ +NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) { + for (auto &it : m_dscVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} + /** * @brief Get the handle of the characteristic. diff --git a/src/NimBLECharacteristic.h b/src/NimBLECharacteristic.h index 1c7418a..9bb9d07 100644 --- a/src/NimBLECharacteristic.h +++ b/src/NimBLECharacteristic.h @@ -59,6 +59,17 @@ class NimBLECharacteristicCallbacks; */ class NimBLECharacteristic { public: + + uint16_t getHandle(); + NimBLEUUID getUUID(); + std::string toString(); + + void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); + + void indicate(); + void notify(bool is_notification = true); + size_t getSubscribedCount(); + NimBLEDescriptor* createDescriptor(const char* uuid, uint32_t properties = NIMBLE_PROPERTY::READ | @@ -72,9 +83,10 @@ public: NimBLEDescriptor* getDescriptorByUUID(const char* uuid); NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid); - NimBLEUUID getUUID(); - std::string getValue(time_t *timestamp = nullptr); + NimBLEDescriptor* getDescriptorByHandle(uint16_t handle); + std::string getValue(time_t *timestamp = nullptr); + size_t getDataLength(); /** * @brief A template to convert the characteristic data to . * @tparam T The type to convert the data to. @@ -92,25 +104,20 @@ public: return *((T *)pData); } - size_t getDataLength(); - void indicate(); - void notify(bool is_notification = true); - void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); void setValue(const uint8_t* data, size_t size); void setValue(const std::string &value); - /** * @brief Convenience template to set the characteristic value to val. * @param [in] s The value to set. */ template - void setValue(const T &s) { + void setValue(const T &s) { setValue((uint8_t*)&s, sizeof(T)); } - std::string toString(); - uint16_t getHandle(); - size_t getSubscribedCount(); + + + private: diff --git a/src/NimBLEDescriptor.cpp b/src/NimBLEDescriptor.cpp index e8f7f9f..95c3291 100644 --- a/src/NimBLEDescriptor.cpp +++ b/src/NimBLEDescriptor.cpp @@ -122,11 +122,17 @@ uint8_t* NimBLEDescriptor::getValue() { return m_value.attr_value; } // getValue +/** + * @brief Get the value of this descriptor as a string. + * @return A std::string instance containing a copy of the descriptor's value. + */ +std::string NimBLEDescriptor::getStringValue() { + return std::string((char *) m_value.attr_value, m_value.attr_len); +} int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ + void *arg) { const ble_uuid_t *uuid; int rc; NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg; diff --git a/src/NimBLEDescriptor.h b/src/NimBLEDescriptor.h index 16b6edc..76318b7 100644 --- a/src/NimBLEDescriptor.h +++ b/src/NimBLEDescriptor.h @@ -44,20 +44,23 @@ class NimBLEDescriptorCallbacks; class NimBLEDescriptor { public: uint16_t getHandle(); - size_t getLength(); NimBLEUUID getUUID(); - uint8_t* getValue(); - void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); - void setValue(const uint8_t* data, size_t size); - void setValue(const std::string &value); std::string toString(); + void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); + + size_t getLength(); + uint8_t* getValue(); + std::string getStringValue(); + + void setValue(const uint8_t* data, size_t size); + void setValue(const std::string &value); /** * @brief Convenience template to set the descriptor value to val. * @param [in] s The value to set. */ template - void setValue(const T &s) { + void setValue(const T &s) { setValue((uint8_t*)&s, sizeof(T)); } diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index fd5d826..423e879 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -104,28 +104,47 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH /** * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the new service. - * @return A reference to the service object. + * @param [in] uuid The UUID of the service. + * @param instanceId The index of the service to return (used when multiple services have the same UUID). + * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) { - return getServiceByUUID(NimBLEUUID(uuid)); +NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) { + return getServiceByUUID(NimBLEUUID(uuid), instanceId); } // getServiceByUUID /** * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the new service. - * @return A reference to the service object. + * @param [in] uuid The UUID of the service. + * @param instanceId The index of the service to return (used when multiple services have the same UUID). + * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) { +NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) { + uint16_t position = 0; for (auto &it : m_svcVec) { if (it->getUUID() == uuid) { - return it; + if (position == instanceId){ + return it; + } + position++; } } return nullptr; } // getServiceByUUID +/** + * @brief Get a %BLE Service by its handle + * @param handle The handle of the service. + * @return A pointer to the service object or nullptr if not found. + */ +NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) { + for (auto &it : m_svcVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} /** * @brief Retrieve the advertising object that can be used to advertise the existence of the server. @@ -646,7 +665,7 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle, if(rc != 0) { NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } -} // updateConnParams +}// updateConnParams /** Default callback handlers */ diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index bedf9cf..aaaf287 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -49,8 +49,9 @@ public: void startAdvertising(); void stopAdvertising(); void start(); - NimBLEService* getServiceByUUID(const char* uuid); - NimBLEService* getServiceByUUID(const NimBLEUUID &uuid); + NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0); + NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0); + NimBLEService* getServiceByHandle(uint16_t handle); int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); void updateConnParams(uint16_t conn_handle, diff --git a/src/NimBLEService.cpp b/src/NimBLEService.cpp index 3420da2..a830eec 100644 --- a/src/NimBLEService.cpp +++ b/src/NimBLEService.cpp @@ -233,9 +233,9 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint */ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) { NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this); - // Check that we don't add the same characteristic twice. + if (getCharacteristic(uuid) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", + NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", std::string(uuid).c_str()); } @@ -249,28 +249,72 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid /** * @brief Get a pointer to the characteristic object with the specified UUID. * @param [in] uuid The UUID of the characteristic. + * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). * @return A pointer to the characteristic object or nullptr if not found. */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) { - return getCharacteristic(NimBLEUUID(uuid)); +NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) { + return getCharacteristic(NimBLEUUID(uuid), instanceId); } - /** * @brief Get a pointer to the characteristic object with the specified UUID. * @param [in] uuid The UUID of the characteristic. + * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). * @return A pointer to the characteristic object or nullptr if not found. */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) { +NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) { + uint16_t position = 0; for (auto &it : m_chrVec) { if (it->getUUID() == uuid) { - return it; + if (position == instanceId) { + return it; + } + position++; } } - return nullptr; } +/** + * @brief Get a pointer to the characteristic object with the specified handle. + * @param handle The handle of the characteristic. + * @return A pointer to the characteristic object or nullptr if not found. + */ +NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) { + for (auto &it : m_chrVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} + +/** + * @return A vector containing pointers to each characteristic associated with this service. + */ +std::vector NimBLEService::getCharacteristics() { + return m_chrVec; +} + +/** + * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. + */ +std::vector NimBLEService::getCharacteristics(const char *uuid) { + return getCharacteristics(NimBLEUUID(uuid)); +} + +/** + * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. + */ +std::vector NimBLEService::getCharacteristics(const NimBLEUUID &uuid) { + std::vector result; + for (auto &it : m_chrVec) { + if (it->getUUID() == uuid) { + result.push_back(it); + } + } + return result; +} /** * @brief Return a string representation of this service. @@ -295,7 +339,7 @@ std::string NimBLEService::toString() { */ NimBLEServer* NimBLEService::getServer() { return m_pServer; -} // getServer +}// getServer #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #endif // CONFIG_BT_ENABLED diff --git a/src/NimBLEService.h b/src/NimBLEService.h index 191d97f..1203d3e 100644 --- a/src/NimBLEService.h +++ b/src/NimBLEService.h @@ -35,6 +35,16 @@ class NimBLECharacteristic; */ class NimBLEService { public: + + NimBLEServer* getServer(); + + NimBLEUUID getUUID(); + uint16_t getHandle(); + std::string toString(); + void dump(); + + bool start(); + NimBLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties = NIMBLE_PROPERTY::READ | @@ -45,14 +55,14 @@ public: NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE); - void dump(); - NimBLECharacteristic* getCharacteristic(const char* uuid); - NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid); - NimBLEUUID getUUID(); - NimBLEServer* getServer(); - bool start(); - std::string toString(); - uint16_t getHandle(); + NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0); + NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0); + NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle); + + std::vector getCharacteristics(); + std::vector getCharacteristics(const char* uuid); + std::vector getCharacteristics(const NimBLEUUID &uuid); + private: NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);