[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
This commit is contained in:
David Robertson 2021-02-08 15:28:32 +00:00 committed by GitHub
parent 28d6492ea4
commit 7dd4d68806
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 157 additions and 53 deletions

View file

@ -101,9 +101,9 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
/** /**
* @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. * @brief Return the BLE Descriptor for the given UUID.
* @param [in] uuid The UUID of the descriptor that we wish to retrieve. * @param [in] uuid The UUID of the descriptor.
* @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. * @return A pointer to the descriptor object or nullptr if not found.
*/ */
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
return getDescriptorByUUID(NimBLEUUID(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. * @brief Return the BLE Descriptor for the given UUID.
* @param [in] uuid The UUID of the descriptor that we wish to retrieve. * @param [in] uuid The UUID of the descriptor.
* @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. * @return A pointer to the descriptor object or nullptr if not found.
*/ */
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) { NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
for (auto &it : m_dscVec) { for (auto &it : m_dscVec) {
@ -124,6 +124,20 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uu
return nullptr; return nullptr;
} // getDescriptorByUUID } // 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. * @brief Get the handle of the characteristic.

View file

@ -59,6 +59,17 @@ class NimBLECharacteristicCallbacks;
*/ */
class NimBLECharacteristic { class NimBLECharacteristic {
public: 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, NimBLEDescriptor* createDescriptor(const char* uuid,
uint32_t properties = uint32_t properties =
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ |
@ -72,9 +83,10 @@ public:
NimBLEDescriptor* getDescriptorByUUID(const char* uuid); NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid); NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
NimBLEUUID getUUID(); NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
std::string getValue(time_t *timestamp = nullptr);
std::string getValue(time_t *timestamp = nullptr);
size_t getDataLength();
/** /**
* @brief A template to convert the characteristic data to <type\>. * @brief A template to convert the characteristic data to <type\>.
* @tparam T The type to convert the data to. * @tparam T The type to convert the data to.
@ -92,25 +104,20 @@ public:
return *((T *)pData); 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 uint8_t* data, size_t size);
void setValue(const std::string &value); void setValue(const std::string &value);
/** /**
* @brief Convenience template to set the characteristic value to <type\>val. * @brief Convenience template to set the characteristic value to <type\>val.
* @param [in] s The value to set. * @param [in] s The value to set.
*/ */
template<typename T> template<typename T>
void setValue(const T &s) { void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T)); setValue((uint8_t*)&s, sizeof(T));
} }
std::string toString();
uint16_t getHandle();
size_t getSubscribedCount();
private: private:

View file

@ -122,11 +122,17 @@ uint8_t* NimBLEDescriptor::getValue() {
return m_value.attr_value; return m_value.attr_value;
} // getValue } // 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, int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, struct ble_gatt_access_ctxt *ctxt,
void *arg) void *arg) {
{
const ble_uuid_t *uuid; const ble_uuid_t *uuid;
int rc; int rc;
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg; NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;

View file

@ -44,20 +44,23 @@ class NimBLEDescriptorCallbacks;
class NimBLEDescriptor { class NimBLEDescriptor {
public: public:
uint16_t getHandle(); uint16_t getHandle();
size_t getLength();
NimBLEUUID getUUID(); 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(); 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 <type\>val. * @brief Convenience template to set the descriptor value to <type\>val.
* @param [in] s The value to set. * @param [in] s The value to set.
*/ */
template<typename T> template<typename T>
void setValue(const T &s) { void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T)); setValue((uint8_t*)&s, sizeof(T));
} }

View file

@ -104,28 +104,47 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
/** /**
* @brief Get a %BLE Service by its UUID * @brief Get a %BLE Service by its UUID
* @param [in] uuid The UUID of the new service. * @param [in] uuid The UUID of the service.
* @return A reference to the service object. * @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) { NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) {
return getServiceByUUID(NimBLEUUID(uuid)); return getServiceByUUID(NimBLEUUID(uuid), instanceId);
} // getServiceByUUID } // getServiceByUUID
/** /**
* @brief Get a %BLE Service by its UUID * @brief Get a %BLE Service by its UUID
* @param [in] uuid The UUID of the new service. * @param [in] uuid The UUID of the service.
* @return A reference to the service object. * @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) { for (auto &it : m_svcVec) {
if (it->getUUID() == uuid) { if (it->getUUID() == uuid) {
return it; if (position == instanceId){
return it;
}
position++;
} }
} }
return nullptr; return nullptr;
} // getServiceByUUID } // 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. * @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) { if(rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
} }
} // updateConnParams }// updateConnParams
/** Default callback handlers */ /** Default callback handlers */

View file

@ -49,8 +49,9 @@ public:
void startAdvertising(); void startAdvertising();
void stopAdvertising(); void stopAdvertising();
void start(); void start();
NimBLEService* getServiceByUUID(const char* uuid); NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid); NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
NimBLEService* getServiceByHandle(uint16_t handle);
int disconnect(uint16_t connID, int disconnect(uint16_t connID,
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
void updateConnParams(uint16_t conn_handle, void updateConnParams(uint16_t conn_handle,

View file

@ -233,9 +233,9 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
*/ */
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) { NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this); NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
// Check that we don't add the same characteristic twice.
if (getCharacteristic(uuid) != nullptr) { 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()); 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. * @brief Get a pointer to the characteristic object with the specified UUID.
* @param [in] uuid The UUID of the characteristic. * @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. * @return A pointer to the characteristic object or nullptr if not found.
*/ */
NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) { NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) {
return getCharacteristic(NimBLEUUID(uuid)); return getCharacteristic(NimBLEUUID(uuid), instanceId);
} }
/** /**
* @brief Get a pointer to the characteristic object with the specified UUID. * @brief Get a pointer to the characteristic object with the specified UUID.
* @param [in] uuid The UUID of the characteristic. * @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. * @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) { for (auto &it : m_chrVec) {
if (it->getUUID() == uuid) { if (it->getUUID() == uuid) {
return it; if (position == instanceId) {
return it;
}
position++;
} }
} }
return nullptr; 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<NimBLECharacteristic *> NimBLEService::getCharacteristics() {
return m_chrVec;
}
/**
* @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
*/
std::vector<NimBLECharacteristic *> 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<NimBLECharacteristic *> NimBLEService::getCharacteristics(const NimBLEUUID &uuid) {
std::vector<NimBLECharacteristic*> result;
for (auto &it : m_chrVec) {
if (it->getUUID() == uuid) {
result.push_back(it);
}
}
return result;
}
/** /**
* @brief Return a string representation of this service. * @brief Return a string representation of this service.
@ -295,7 +339,7 @@ std::string NimBLEService::toString() {
*/ */
NimBLEServer* NimBLEService::getServer() { NimBLEServer* NimBLEService::getServer() {
return m_pServer; return m_pServer;
} // getServer }// getServer
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View file

@ -35,6 +35,16 @@ class NimBLECharacteristic;
*/ */
class NimBLEService { class NimBLEService {
public: public:
NimBLEServer* getServer();
NimBLEUUID getUUID();
uint16_t getHandle();
std::string toString();
void dump();
bool start();
NimBLECharacteristic* createCharacteristic(const char* uuid, NimBLECharacteristic* createCharacteristic(const char* uuid,
uint32_t properties = uint32_t properties =
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ |
@ -45,14 +55,14 @@ public:
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE); NIMBLE_PROPERTY::WRITE);
void dump(); NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0);
NimBLECharacteristic* getCharacteristic(const char* uuid); NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0);
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid); NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle);
NimBLEUUID getUUID();
NimBLEServer* getServer(); std::vector<NimBLECharacteristic*> getCharacteristics();
bool start(); std::vector<NimBLECharacteristic*> getCharacteristics(const char* uuid);
std::string toString(); std::vector<NimBLECharacteristic*> getCharacteristics(const NimBLEUUID &uuid);
uint16_t getHandle();
private: private:
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer); NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);