18#ifndef NIMBLE_CPP_ATTVALUE_H
19#define NIMBLE_CPP_ATTVALUE_H
21#include "syscfg/syscfg.h"
22#if CONFIG_BT_NIMBLE_ENABLED
24# ifdef USING_NIMBLE_ARDUINO_HEADERS
25# include "nimble/nimble/include/nimble/nimble_npl.h"
27# include "nimble/nimble_npl.h"
31# ifndef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
32# define NIMBLE_CPP_ARDUINO_STRING_AVAILABLE (__has_include(<Arduino.h>))
35# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
46# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
47# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
48# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
50# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
54# ifndef BLE_ATT_ATTR_MAX_LEN
55# define BLE_ATT_ATTR_MAX_LEN 512
58# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
59# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
60# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
62# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
66# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) > BLE_ATT_ATTR_MAX_LEN
67# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
68# elif MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) < 1
69# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
73template <
typename T,
typename =
void,
typename =
void>
74struct Has_data_size : std::false_type {};
77struct Has_data_size<T, decltype(void(std::declval<T&>().data())), decltype(void(std::declval<T&>().size()))>
81template <
typename T,
typename =
void,
typename =
void>
82struct Has_c_str_length : std::false_type {};
85struct Has_c_str_length<T, decltype(void(std::declval<T&>().c_str())), decltype(void(std::declval<T&>().length()))>
89template <
typename T,
typename =
void>
90struct Has_value_type : std::false_type {};
93struct Has_value_type<T, decltype(void(sizeof(typename T::value_type)))>
103 uint8_t* m_attr_value{};
104 uint16_t m_attr_max_len{};
105 uint16_t m_attr_len{};
106 uint16_t m_capacity{};
107# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
108 time_t m_timestamp{};
114 static ble_npl_mutex m_mutex;
115 static std::atomic<bool> m_initialized;
116 static std::atomic<int> m_activeCount;
117 bool m_locked{
false};
122 m_activeCount.fetch_add(1);
124 if (m_initialized.load()) {
125 m_locked = (ble_npl_mutex_pend(&m_mutex, BLE_NPL_TIME_FOREVER) == BLE_NPL_OK);
129 if (!m_initialized.load() && m_locked) {
130 ble_npl_mutex_release(&m_mutex);
136 m_activeCount.fetch_sub(1);
141 ble_npl_mutex_release(&m_mutex);
146 if (!m_initialized.load()) {
147 if (ble_npl_mutex_init(&m_mutex) == BLE_NPL_OK) {
148 m_initialized.store(
true);
151 return m_initialized.load();
154 static void deinit() {
155 if (m_initialized.load()) {
157 m_initialized.store(
false);
160 while (m_activeCount.load() > 0) {
161 ble_npl_time_delay(1);
165 if (ble_npl_mutex_pend(&m_mutex, BLE_NPL_TIME_FOREVER) == BLE_NPL_OK) {
167 ble_npl_mutex_deinit(&m_mutex);
178 NimBLEAttValue(uint16_t init_len = MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH), uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
186 NimBLEAttValue(
const uint8_t* value, uint16_t len, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
194 :
NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len) {}
201 NimBLEAttValue(std::initializer_list<uint8_t> list, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
217 NimBLEAttValue(
const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
220# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
226 NimBLEAttValue(
const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
240 uint16_t
max_size()
const {
return m_attr_max_len; }
246 uint16_t
length()
const {
return m_attr_len; }
249 uint16_t
size()
const {
return m_attr_len; }
256 const uint8_t*
data()
const {
return m_attr_value; }
261 const char*
c_str()
const {
return reinterpret_cast<const char*
>(m_attr_value); }
264 const uint8_t*
begin()
const {
return m_attr_value; }
267 const uint8_t*
end()
const {
return m_attr_value + m_attr_len; }
269# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
271 time_t getTimeStamp()
const {
return m_timestamp; }
274 void setTimeStamp() { m_timestamp = time(
nullptr); }
280 void setTimeStamp(time_t t) { m_timestamp = t; }
282 time_t getTimeStamp()
const {
return 0; }
283 void setTimeStamp() {}
284 void setTimeStamp(time_t t) {}
293 bool setValue(
const uint8_t* value, uint16_t len);
304 return setValue(
reinterpret_cast<const uint8_t*
>(s), len);
307 const NimBLEAttValue& getValue(time_t* timestamp =
nullptr)
const {
308 if (timestamp !=
nullptr) {
309# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
310 *timestamp = m_timestamp;
335# if __cplusplus < 201703L
341 template <
typename T>
345 typename std::enable_if<std::is_array<T>::value && std::is_same<typename std::remove_extent<T>::type,
char>::value,
bool>::type
348 return setValue(
reinterpret_cast<const uint8_t*
>(s), strnlen(s,
sizeof(T)));
357 template <
typename T>
361 typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value &&
362 !(std::is_array<T>::value && std::is_same<typename std::remove_extent<T>::type,
char>::value),
366 return setValue(
reinterpret_cast<const uint8_t*
>(&v),
sizeof(T));
374 template <
typename T>
378 typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value,
bool>::type
381 return setValue(
reinterpret_cast<const uint8_t*
>(s.c_str()), s.length());
390 template <
typename T>
394 typename std::enable_if<Has_data_size<T>::value && Has_value_type<T>::value,
bool>::type
398 reinterpret_cast<const uint8_t*
>(v.data()),
399 v.size() *
sizeof(
typename T::value_type)
408 template <
typename T>
412 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value,
bool>::type
415 return setValue(
reinterpret_cast<const uint8_t*
>(v.data()), v.size());
424 template <
typename T>
425 typename std::enable_if<!std::is_pointer<T>::value,
bool>::type
setValue(
const T& s) {
426 if constexpr (Has_data_size<T>::value) {
427 if constexpr (Has_value_type<T>::value) {
428 return setValue(
reinterpret_cast<const uint8_t*
>(s.data()), s.size() *
sizeof(
typename T::value_type));
430 return setValue(
reinterpret_cast<const uint8_t*
>(s.data()), s.size());
432 }
else if constexpr (Has_c_str_length<T>::value) {
433 return setValue(
reinterpret_cast<const uint8_t*
>(s.c_str()), s.length());
434 }
else if constexpr (std::is_array<T>::value && std::is_same<typename std::remove_extent<T>::type,
char>::value) {
435 return setValue(
reinterpret_cast<const uint8_t*
>(s), strnlen(s,
sizeof(s)));
437 return setValue(
reinterpret_cast<const uint8_t*
>(&s),
sizeof(s));
452 template <
typename T>
453 T
getValue(time_t* timestamp =
nullptr,
bool skipSizeCheck =
false)
const {
455 if (timestamp !=
nullptr) {
456# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
457 *timestamp = m_timestamp;
463 if (!skipSizeCheck &&
size() <
sizeof(T)) {
466 return *(
reinterpret_cast<const T*
>(m_attr_value));
475 operator std::vector<uint8_t>()
const {
477 return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len);
481 operator std::string()
const {
483 return std::string(
reinterpret_cast<char*
>(m_attr_value), m_attr_len);
487 operator const uint8_t*()
const {
return m_attr_value; }
492 if (&source ==
this) {
494 std::vector<uint8_t> copy(m_attr_value, m_attr_value + m_attr_len);
495 return append(copy.data(), copy.size());
502 setValue(
reinterpret_cast<const uint8_t*
>(&source[0]), source.size());
515 return (m_attr_len == source.
size()) ? memcmp(m_attr_value, source.
data(), m_attr_len) == 0 :
false;
521# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
523 operator String()
const {
525 return String(
reinterpret_cast<char*
>(m_attr_value));
A specialized container class to hold BLE attribute values.
Definition NimBLEAttValue.h:102
NimBLEAttValue(const std::vector< uint8_t > vec, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initial value from a std::vector<uint8_t>.
Definition NimBLEAttValue.h:217
~NimBLEAttValue()
Destructor.
Definition NimBLEAttValue.cpp:91
uint16_t length() const
Returns the current length of the value in bytes.
Definition NimBLEAttValue.h:246
NimBLEAttValue(const char *value, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initial value from a const char string.
Definition NimBLEAttValue.h:193
uint16_t capacity() const
Returns the currently allocated capacity in bytes.
Definition NimBLEAttValue.h:243
const char * c_str() const
Returns a pointer to the internal buffer of the value as a const char*.
Definition NimBLEAttValue.h:261
NimBLEAttValue(const std::string str, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initial value from a std::string.
Definition NimBLEAttValue.h:209
bool setValue(const uint8_t *value, uint16_t len)
Set the value from a buffer.
Definition NimBLEAttValue.cpp:141
NimBLEAttValue(std::initializer_list< uint8_t > list, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initializer list.
Definition NimBLEAttValue.h:201
NimBLEAttValue & operator+=(const NimBLEAttValue &source)
Operator; Append another NimBLEAttValue.
Definition NimBLEAttValue.h:490
NimBLEAttValue(const NimBLEAttValue &source)
Copy constructor.
Definition NimBLEAttValue.h:231
NimBLEAttValue(NimBLEAttValue &&source)
Move constructor.
Definition NimBLEAttValue.h:234
const uint8_t * data() const
Returns a pointer to the internal buffer of the value.
Definition NimBLEAttValue.h:256
uint8_t operator[](int pos) const
Subscript operator.
Definition NimBLEAttValue.cpp:192
const uint8_t * end() const
Iterator end; see data() for thread safety restrictions.
Definition NimBLEAttValue.h:267
bool setValue(const T &v)
Template to set value to the value of <type>val.
Definition NimBLEAttValue.h:365
bool copyFrom(const NimBLEAttValue &source)
Copy the value from another NimBLEAttValue instance.
Definition NimBLEAttValue.h:331
NimBLEAttValue & append(const uint8_t *value, uint16_t len)
Append data to the value.
Definition NimBLEAttValue.cpp:150
uint16_t size() const
Returns the current size of the value in bytes.
Definition NimBLEAttValue.h:249
bool setValue(const char *s, uint16_t len=0)
Set value to the value of const char*.
Definition NimBLEAttValue.h:300
T getValue(time_t *timestamp=nullptr, bool skipSizeCheck=false) const
Template to return the value as a <type>.
Definition NimBLEAttValue.h:453
uint16_t max_size() const
Returns the max size in bytes.
Definition NimBLEAttValue.h:240
bool setValue(const T &s)
Template to set value to the value of a char array using strnlen.
Definition NimBLEAttValue.h:347
bool operator==(const NimBLEAttValue &source) const
Equality operator.
Definition NimBLEAttValue.h:513
NimBLEAttValue & operator=(const std::string &source)
Operator; Set the value from a std::string source.
Definition NimBLEAttValue.h:501
const uint8_t * begin() const
Iterator begin; see data() for thread safety restrictions.
Definition NimBLEAttValue.h:264
bool operator!=(const NimBLEAttValue &source) const
Inequality operator.
Definition NimBLEAttValue.h:519