esp-nimble-cpp  1.4.1
NimBLEAttValue.h
1 /*
2  * NimBLEAttValue.h
3  *
4  * Created: on March 18, 2021
5  * Author H2zero
6  *
7  */
8 
9 #ifndef MAIN_NIMBLEATTVALUE_H_
10 #define MAIN_NIMBLEATTVALUE_H_
11 #include "nimconfig.h"
12 #if defined(CONFIG_BT_ENABLED)
13 
14 #ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
15 #include <Arduino.h>
16 #endif
17 
18 #include "NimBLELog.h"
19 
20 /**** FIX COMPILATION ****/
21 #undef min
22 #undef max
23 /**************************/
24 
25 #include <string>
26 #include <vector>
27 
28 #ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
29 # define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
30 #endif
31 
32 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
33 # include <time.h>
34 #endif
35 
36 #if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
37 # define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
38 #elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN
39 # error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
40 #elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1
41 # error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
42 #endif
43 
44 
45 /* Used to determine if the type passed to a template has a c_str() and length() method. */
46 template <typename T, typename = void, typename = void>
47 struct Has_c_str_len : std::false_type {};
48 
49 template <typename T>
50 struct Has_c_str_len<T, decltype(void(std::declval<T &>().c_str())),
51  decltype(void(std::declval<T &>().length()))> : std::true_type {};
52 
53 
61 {
62  uint8_t* m_attr_value = nullptr;
63  uint16_t m_attr_max_len = 0;
64  uint16_t m_attr_len = 0;
65  uint16_t m_capacity = 0;
66 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
67  time_t m_timestamp = 0;
68 #endif
69  void deepCopy(const NimBLEAttValue & source);
70 
71 public:
78  uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
79 
86  NimBLEAttValue(const uint8_t *value, uint16_t len,
87  uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
88 
94  NimBLEAttValue(std::initializer_list<uint8_t> list,
95  uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
96  :NimBLEAttValue(list.begin(), (uint16_t)list.size(), max_len){}
97 
103  NimBLEAttValue(const char *value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
104  :NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len){}
105 
111  NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
112  :NimBLEAttValue((uint8_t*)str.data(), (uint16_t)str.length(), max_len){}
113 
119  NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
120  :NimBLEAttValue(&vec[0], (uint16_t)vec.size(), max_len){}
121 
122 #ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
128  NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
129  :NimBLEAttValue((uint8_t*)str.c_str(), str.length(), max_len){}
130 #endif
131 
133  NimBLEAttValue(const NimBLEAttValue & source) { deepCopy(source); }
134 
136  NimBLEAttValue(NimBLEAttValue && source) { *this = std::move(source); }
137 
139  ~NimBLEAttValue();
140 
142  uint16_t max_size() const { return m_attr_max_len; }
143 
145  uint16_t capacity() const { return m_capacity; }
146 
148  uint16_t length() const { return m_attr_len; }
149 
151  uint16_t size() const { return m_attr_len; }
152 
154  const uint8_t* data() const { return m_attr_value; }
155 
157  const char* c_str() const { return (const char*)m_attr_value; }
158 
160  const uint8_t* begin() const { return m_attr_value; }
161 
163  const uint8_t* end() const { return m_attr_value + m_attr_len; }
164 
165 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
167  time_t getTimeStamp() const { return m_timestamp; }
168 
170  void setTimeStamp() { m_timestamp = time(nullptr); }
171 
176  void setTimeStamp(time_t t) { m_timestamp = t; }
177 #else
178  time_t getTimeStamp() const { return 0; }
179  void setTimeStamp() { }
180  void setTimeStamp(time_t t) { }
181 #endif
182 
189  bool setValue(const uint8_t *value, uint16_t len);
190 
195  bool setValue(const char* s) {
196  return setValue((uint8_t*)s, (uint16_t)strlen(s)); }
197 
203  const uint8_t* getValue(time_t *timestamp);
204 
211  NimBLEAttValue& append(const uint8_t *value, uint16_t len);
212 
213 
214  /*********************** Template Functions ************************/
215 
221  template<typename T>
222 #ifdef _DOXYGEN_
223  bool
224 #else
225  typename std::enable_if<!Has_c_str_len<T>::value, bool>::type
226 #endif
227  setValue(const T &s) {
228  return setValue((uint8_t*)&s, sizeof(T));
229  }
230 
236  template<typename T>
237 #ifdef _DOXYGEN_
238  bool
239 #else
240  typename std::enable_if<Has_c_str_len<T>::value, bool>::type
241 #endif
242  setValue(const T & s) {
243  return setValue((uint8_t*)s.c_str(), (uint16_t)s.length());
244  }
245 
256  template<typename T>
257  T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
258  if(!skipSizeCheck && size() < sizeof(T)) {
259  return T();
260  }
261  return *((T *)getValue(timestamp));
262  }
263 
264 
265  /*********************** Operators ************************/
266 
268  uint8_t operator [](int pos) const {
269  assert(pos < m_attr_len && "out of range"); return m_attr_value[pos]; }
270 
272  operator std::vector<uint8_t>() const {
273  return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
274 
276  operator std::string() const {
277  return std::string((char*)m_attr_value, m_attr_len); }
278 
280  operator const uint8_t*() const { return m_attr_value; }
281 
284  return append(source.data(), source.size()); }
285 
287  NimBLEAttValue& operator =(const std::string & source) {
288  setValue((uint8_t*)source.data(), (uint16_t)source.size()); return *this; }
289 
292 
294  NimBLEAttValue& operator =(const NimBLEAttValue & source);
295 
297  bool operator ==(const NimBLEAttValue & source) {
298  return (m_attr_len == source.size()) ?
299  memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false; }
300 
302  bool operator !=(const NimBLEAttValue & source){ return !(*this == source); }
303 
304 #ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
306  operator String() const { return String((char*)m_attr_value); }
307 #endif
308 
309 };
310 
311 
312 inline NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len) {
313  m_attr_value = (uint8_t*)calloc(init_len + 1, 1);
314  assert(m_attr_value && "No Mem");
315  m_attr_max_len = std::min(BLE_ATT_ATTR_MAX_LEN, (int)max_len);
316  m_attr_len = 0;
317  m_capacity = init_len;
318  setTimeStamp(0);
319 }
320 
321 inline NimBLEAttValue::NimBLEAttValue(const uint8_t *value, uint16_t len, uint16_t max_len)
322 : NimBLEAttValue(len, max_len) {
323  memcpy(m_attr_value, value, len);
324  m_attr_value[len] = '\0';
325  m_attr_len = len;
326 }
327 
329  if(m_attr_value != nullptr) {
330  free(m_attr_value);
331  }
332 }
333 
335  if (this != &source){
336  free(m_attr_value);
337 
338  m_attr_value = source.m_attr_value;
339  m_attr_max_len = source.m_attr_max_len;
340  m_attr_len = source.m_attr_len;
341  m_capacity = source.m_capacity;
342  setTimeStamp(source.getTimeStamp());
343  source.m_attr_value = nullptr;
344  }
345  return *this;
346 }
347 
349  if (this != &source) {
350  deepCopy(source);
351  }
352  return *this;
353 }
354 
355 inline void NimBLEAttValue::deepCopy(const NimBLEAttValue & source) {
356  uint8_t* res = (uint8_t*)realloc( m_attr_value, source.m_capacity + 1);
357  assert(res && "deepCopy: realloc failed");
358 
359  ble_npl_hw_enter_critical();
360  m_attr_value = res;
361  m_attr_max_len = source.m_attr_max_len;
362  m_attr_len = source.m_attr_len;
363  m_capacity = source.m_capacity;
364  setTimeStamp(source.getTimeStamp());
365  memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1);
366  ble_npl_hw_exit_critical(0);
367 }
368 
369 inline const uint8_t* NimBLEAttValue::getValue(time_t *timestamp) {
370  if(timestamp != nullptr) {
371 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
372  *timestamp = m_timestamp;
373 #else
374  *timestamp = 0;
375 #endif
376  }
377  return m_attr_value;
378 }
379 
380 inline bool NimBLEAttValue::setValue(const uint8_t *value, uint16_t len) {
381  if (len > m_attr_max_len) {
382  NIMBLE_LOGE("NimBLEAttValue", "value exceeds max, len=%u, max=%u",
383  len, m_attr_max_len);
384  return false;
385  }
386 
387  uint8_t *res = m_attr_value;
388  if (len > m_capacity) {
389  res = (uint8_t*)realloc(m_attr_value, (len + 1));
390  m_capacity = len;
391  }
392  assert(res && "setValue: realloc failed");
393 
394 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
395  time_t t = time(nullptr);
396 #else
397  time_t t = 0;
398 #endif
399 
400  ble_npl_hw_enter_critical();
401  m_attr_value = res;
402  memcpy(m_attr_value, value, len);
403  m_attr_value[len] = '\0';
404  m_attr_len = len;
405  setTimeStamp(t);
406  ble_npl_hw_exit_critical(0);
407  return true;
408 }
409 
410 inline NimBLEAttValue& NimBLEAttValue::append(const uint8_t *value, uint16_t len) {
411  if (len < 1) {
412  return *this;
413  }
414 
415  if ((m_attr_len + len) > m_attr_max_len) {
416  NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u",
417  len, m_attr_max_len);
418  return *this;
419  }
420 
421  uint8_t* res = m_attr_value;
422  uint16_t new_len = m_attr_len + len;
423  if (new_len > m_capacity) {
424  res = (uint8_t*)realloc(m_attr_value, (new_len + 1));
425  m_capacity = new_len;
426  }
427  assert(res && "append: realloc failed");
428 
429 #if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
430  time_t t = time(nullptr);
431 #else
432  time_t t = 0;
433 #endif
434 
435  ble_npl_hw_enter_critical();
436  m_attr_value = res;
437  memcpy(m_attr_value + m_attr_len, value, len);
438  m_attr_len = new_len;
439  m_attr_value[m_attr_len] = '\0';
440  setTimeStamp(t);
441  ble_npl_hw_exit_critical(0);
442 
443  return *this;
444 }
445 
446 #endif /*(CONFIG_BT_ENABLED) */
447 #endif /* MAIN_NIMBLEATTVALUE_H_ */
A specialized container class to hold BLE attribute values.
Definition: NimBLEAttValue.h:61
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:119
~NimBLEAttValue()
Destructor.
Definition: NimBLEAttValue.h:328
NimBLEAttValue & operator+=(const NimBLEAttValue &source)
Operator; Append another NimBLEAttValue.
Definition: NimBLEAttValue.h:283
T getValue(time_t *timestamp=nullptr, bool skipSizeCheck=false)
Template to return the value as a <type>.
Definition: NimBLEAttValue.h:257
uint16_t length() const
Returns the current length of the value in bytes.
Definition: NimBLEAttValue.h:148
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:103
uint16_t capacity() const
Returns the currently allocated capacity in bytes.
Definition: NimBLEAttValue.h:145
const uint8_t * end() const
Iterator end.
Definition: NimBLEAttValue.h:163
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:111
bool setValue(const uint8_t *value, uint16_t len)
Set the value from a buffer.
Definition: NimBLEAttValue.h:380
const uint8_t * getValue(time_t *timestamp)
Get a pointer to the value buffer with timestamp.
Definition: NimBLEAttValue.h:369
const uint8_t * begin() const
Iterator begin.
Definition: NimBLEAttValue.h:160
NimBLEAttValue(std::initializer_list< uint8_t > list, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initializer list.
Definition: NimBLEAttValue.h:94
NimBLEAttValue(const NimBLEAttValue &source)
Copy constructor.
Definition: NimBLEAttValue.h:133
NimBLEAttValue(NimBLEAttValue &&source)
Move constructor.
Definition: NimBLEAttValue.h:136
uint8_t operator[](int pos) const
Subscript operator.
Definition: NimBLEAttValue.h:268
bool operator==(const NimBLEAttValue &source)
Equality operator.
Definition: NimBLEAttValue.h:297
bool setValue(const char *s)
Set value to the value of const char*.
Definition: NimBLEAttValue.h:195
bool operator!=(const NimBLEAttValue &source)
Inequality operator.
Definition: NimBLEAttValue.h:302
const uint8_t * data() const
Returns a pointer to the internal buffer of the value.
Definition: NimBLEAttValue.h:154
NimBLEAttValue & operator=(const std::string &source)
Operator; Set the value from a std::string source.
Definition: NimBLEAttValue.h:287
NimBLEAttValue & append(const uint8_t *value, uint16_t len)
Append data to the value.
Definition: NimBLEAttValue.h:410
const char * c_str() const
Returns a pointer to the internal buffer of the value as a const char*.
Definition: NimBLEAttValue.h:157
NimBLEAttValue(uint16_t init_len=CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Default constructor.
Definition: NimBLEAttValue.h:312
uint16_t size() const
Returns the current size of the value in bytes.
Definition: NimBLEAttValue.h:151
uint16_t max_size() const
Returns the max size in bytes.
Definition: NimBLEAttValue.h:142
bool setValue(const T &s)
Template to set value to the value of <type>val.
Definition: NimBLEAttValue.h:227
#define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
Uncomment to set the default allocation size (bytes) for each attribute if not specified when the con...
Definition: nimconfig.h:56