[BREAKING] Refactor attributes

Refactor attributes to reduce code duplication and improve maintainability.

* Add attribute base classes to provide common code.
* Add const where possible to functions and parameters.
* `NimBLECharacteristic::notify` no longer takes a `bool is_notification` parameter, instead `indicate()` should be called to send indications.
* `NimBLECharacteristic::indicate` now takes the same parameters as `notify`.
* `NimBLECharacteristicCallbacks` and `NimBLEDescriptorCallbacks` methods now take `const NimBLEConnInfo&` instead of non-const.
* `NimBLECharacteristic::onNotify` callback removed as unnecessary, the library does not call notify without app input.
* `NimBLERemoteCharacteristic::getRemoteService` now returns a `const NimBLERemoteService*` instead of non-const.
* Add NimBLEUUID constructor that takes a reference to `ble_uuid_any_t`.
* `NimBLERemoteService::getCharacteristics` now returns a `const std::vector<NimBLERemoteCharacteristic*>&` instead of non-const `std::vector<NimBLERemoteCharacteristic*>*`
* `NimBLERemoteService::getValue` now returns `NimBLEAttValue` instead of `std::string`
* `NimBLEService::getCharacteristics` now returns a `const std::vector<NimBLECharacteristic*>&` instead of a copy of std::vector<NimBLECharacteristic *>.
* Remove const requirement for NimBLEConnInfo parameter in callbacks.
  Const is unnecessary as the data can't be changed by application code.
* Change NimBLERemoteCharacteristic::getRemoteService to return const pointer.
This commit is contained in:
h2zero
2024-09-24 14:59:54 -06:00
committed by h2zero
parent b4b3b0c455
commit 91210b8610
35 changed files with 1757 additions and 2536 deletions
+78 -143
View File
@@ -11,131 +11,71 @@
* Author: kolban
*/
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
#define MAIN_NIMBLECHARACTERISTIC_H_
#ifndef NIMBLE_CPP_CHARACTERISTIC_H_
#define NIMBLE_CPP_CHARACTERISTIC_H_
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#if defined(CONFIG_NIMBLE_CPP_IDF)
#include "host/ble_hs.h"
#else
#include "nimble/nimble/host/include/host/ble_hs.h"
#endif
/**** FIX COMPILATION ****/
#undef min
#undef max
/**************************/
typedef enum {
READ = BLE_GATT_CHR_F_READ,
READ_ENC = BLE_GATT_CHR_F_READ_ENC,
READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
WRITE = BLE_GATT_CHR_F_WRITE,
WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP,
WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC,
WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN,
WRITE_AUTHOR = BLE_GATT_CHR_F_WRITE_AUTHOR,
BROADCAST = BLE_GATT_CHR_F_BROADCAST,
NOTIFY = BLE_GATT_CHR_F_NOTIFY,
INDICATE = BLE_GATT_CHR_F_INDICATE
} NIMBLE_PROPERTY;
#include "NimBLEService.h"
#include "NimBLEDescriptor.h"
#include "NimBLEAttValue.h"
#include "NimBLEConnInfo.h"
#include <string>
#include <vector>
class NimBLEService;
class NimBLEDescriptor;
class NimBLECharacteristicCallbacks;
class NimBLECharacteristic;
# include "NimBLELocalValueAttribute.h"
# include "NimBLEServer.h"
# include "NimBLEService.h"
# include "NimBLEDescriptor.h"
# include "NimBLEAttValue.h"
# include "NimBLEConnInfo.h"
# include <string>
# include <vector>
/**
* @brief The model of a %BLE Characteristic.
* @brief The model of a BLE Characteristic.
*
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and
* can be read and written to by a %BLE client.
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE service and
* can be read and written to by a BLE client.
*/
class NimBLECharacteristic {
public:
NimBLECharacteristic(const char* uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
NimBLECharacteristic(const NimBLEUUID &uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
class NimBLECharacteristic : public NimBLELocalValueAttribute {
public:
NimBLECharacteristic(const char* uuid,
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
NimBLECharacteristic(const NimBLEUUID& uuid,
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
~NimBLECharacteristic();
uint16_t getHandle();
NimBLEUUID getUUID();
std::string toString();
void indicate();
void indicate(const uint8_t* value, size_t length);
void indicate(const std::vector<uint8_t>& value);
void notify(bool is_notification = true, uint16_t conn_handle = BLE_HCI_LE_CONN_HANDLE_MAX + 1);
void notify(const uint8_t* value, size_t length, bool is_notification = true, uint16_t conn_handle = BLE_HCI_LE_CONN_HANDLE_MAX + 1);
void notify(const std::vector<uint8_t>& value, bool is_notification = true, uint16_t conn_handle = BLE_HCI_LE_CONN_HANDLE_MAX + 1);
size_t getSubscribedCount();
void addDescriptor(NimBLEDescriptor *pDescriptor);
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
NimBLEService* getService();
uint16_t getProperties();
NimBLEAttValue getValue(time_t *timestamp = nullptr);
size_t getDataLength();
void setValue(const uint8_t* data, size_t size);
void setValue(const std::vector<uint8_t>& vec);
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
std::string toString() const;
size_t getSubscribedCount() const;
void addDescriptor(NimBLEDescriptor* pDescriptor);
void removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc = false);
uint16_t getProperties() const;
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
void indicate(uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void indicate(const uint8_t* value, size_t length, uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void indicate(const std::vector<uint8_t>& value, uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void notify(uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void notify(const uint8_t* value, size_t length, uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void notify(const std::vector<uint8_t>& value, uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
NimBLEDescriptor* createDescriptor(const char* uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);;
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
NimBLECharacteristicCallbacks* getCallbacks();
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
NimBLEDescriptor* createDescriptor(const NimBLEUUID& uuid,
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const;
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const;
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;
NimBLEService* getService() const;
NimBLECharacteristicCallbacks* getCallbacks() const;
/*********************** Template Functions ************************/
/**
* @brief Template to set the characteristic value to <type\>val.
* @param [in] s The value to set.
*/
template<typename T>
void setValue(const T &s) { m_value.setValue<T>(s); }
/**
* @brief Template to convert the characteristic data to <type\>.
* @tparam T The type to convert the data to.
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
* @details <b>Use:</b> <tt>getValue<type>(&timestamp, skipSizeCheck);</tt>
*/
template<typename T>
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
return m_value.getValue<T>(timestamp, skipSizeCheck);
}
/**
* @brief Template to send a notification from a class type that has a c_str() and length() method.
* @tparam T The a reference to a class containing the data to send.
@@ -143,14 +83,14 @@ public:
* @param[in] is_notification if true sends a notification, false sends an indication.
* @details Only used if the <type\> has a `c_str()` method.
*/
template<typename T>
#ifdef _DOXYGEN_
template <typename T>
# ifdef _DOXYGEN_
void
#else
# else
typename std::enable_if<Has_c_str_len<T>::value, void>::type
#endif
notify(const T& value, bool is_notification = true) {
notify((uint8_t*)value.c_str(), value.length(), is_notification);
# endif
notify(const T& value, bool is_notification = true) const {
notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), is_notification);
}
/**
@@ -159,39 +99,35 @@ public:
* @param[in] value The <type\>value to set.
* @details Only used if the <type\> has a `c_str()` method.
*/
template<typename T>
#ifdef _DOXYGEN_
template <typename T>
# ifdef _DOXYGEN_
void
#else
# else
typename std::enable_if<Has_c_str_len<T>::value, void>::type
#endif
indicate(const T& value) {
indicate((uint8_t*)value.c_str(), value.length());
# endif
indicate(const T& value) const {
indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length());
}
private:
private:
friend class NimBLEServer;
friend class NimBLEService;
friend class NimBLEServer;
friend class NimBLEService;
void setService(NimBLEService* pService);
void setSubscribe(const ble_gap_event* event, NimBLEConnInfo& connInfo);
void readEvent(NimBLEConnInfo& connInfo) override;
void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
void sendValue(const uint8_t* value,
size_t length,
bool is_notification = true,
uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE) const;
void setService(NimBLEService *pService);
void setSubscribe(struct ble_gap_event *event);
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
NimBLEUUID m_uuid;
uint16_t m_handle;
uint16_t m_properties;
NimBLECharacteristicCallbacks* m_pCallbacks;
NimBLEService* m_pService;
NimBLEAttValue m_value;
std::vector<NimBLEDescriptor*> m_dscVec;
uint8_t m_removed;
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
NimBLEService* m_pService{nullptr};
std::vector<NimBLEDescriptor*> m_vDescriptors{};
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec{};
}; // NimBLECharacteristic
/**
* @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
*
@@ -200,14 +136,13 @@ private:
* sub-classed instance of this class and will be notified when such an event happens.
*/
class NimBLECharacteristicCallbacks {
public:
virtual ~NimBLECharacteristicCallbacks(){}
public:
virtual ~NimBLECharacteristicCallbacks() {}
virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
virtual void onNotify(NimBLECharacteristic* pCharacteristic);
virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code);
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
};
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
#endif /*NIMBLE_CPP_CHARACTERISTIC_H_*/