esp-nimble-cpp 2.5.0
Loading...
Searching...
No Matches
NimBLEAttValue.h
1/*
2 * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and
3 * esp-nimble-cpp, NimBLE-Arduino contributors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef NIMBLE_CPP_ATTVALUE_H
19#define NIMBLE_CPP_ATTVALUE_H
20
21#include "syscfg/syscfg.h"
22#if CONFIG_BT_NIMBLE_ENABLED
23
24/* Enables the use of Arduino String class for attribute values */
25# ifndef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
26# define NIMBLE_CPP_ARDUINO_STRING_AVAILABLE (__has_include(<Arduino.h>))
27# endif
28
29# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
30# include <WString.h>
31# endif
32
33# include <string>
34# include <vector>
35# include <ctime>
36# include <cstring>
37# include <cstdint>
38
39# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
40# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
41# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
42# else
43# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
44# endif
45# endif
46
47# ifndef BLE_ATT_ATTR_MAX_LEN
48# define BLE_ATT_ATTR_MAX_LEN 512
49# endif
50
51# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
52# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
53# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
54# else
55# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
56# endif
57# endif
58
59# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) > BLE_ATT_ATTR_MAX_LEN
60# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
61# elif MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) < 1
62# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
63# endif
64
65/* Used to determine if the type passed to a template has a data() and size() method. */
66template <typename T, typename = void, typename = void>
67struct Has_data_size : std::false_type {};
68
69template <typename T>
70struct Has_data_size<T, decltype(void(std::declval<T&>().data())), decltype(void(std::declval<T&>().size()))>
71 : std::true_type {};
72
73/* Used to determine if the type passed to a template has a c_str() and length() method. */
74template <typename T, typename = void, typename = void>
75struct Has_c_str_length : std::false_type {};
76
77template <typename T>
78struct Has_c_str_length<T, decltype(void(std::declval<T&>().c_str())), decltype(void(std::declval<T&>().length()))>
79 : std::true_type {};
80
81/* Used to determine if the type passed to a template has a value_type member (std::vector, std::array, std::string, etc.). */
82template <typename T, typename = void>
83struct Has_value_type : std::false_type {};
84
85template <typename T>
86struct Has_value_type<T, decltype(void(sizeof(typename T::value_type)))>
87 : std::true_type {};
88
96 uint8_t* m_attr_value{};
97 uint16_t m_attr_max_len{};
98 uint16_t m_attr_len{};
99 uint16_t m_capacity{};
100# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
101 time_t m_timestamp{};
102# endif
103 void deepCopy(const NimBLEAttValue& source);
104
105 public:
111 NimBLEAttValue(uint16_t init_len = MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH), uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
112
119 NimBLEAttValue(const uint8_t* value, uint16_t len, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
120
126 NimBLEAttValue(const char* value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
127 : NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len) {}
128
134 NimBLEAttValue(std::initializer_list<uint8_t> list, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
135 : NimBLEAttValue(list.begin(), list.size(), max_len) {}
136
142 NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
143 : NimBLEAttValue(reinterpret_cast<const uint8_t*>(&str[0]), str.length(), max_len) {}
144
150 NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
151 : NimBLEAttValue(&vec[0], vec.size(), max_len) {}
152
153# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
159 NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
160 : NimBLEAttValue(reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), max_len) {}
161# endif
162
164 NimBLEAttValue(const NimBLEAttValue& source) { deepCopy(source); }
165
167 NimBLEAttValue(NimBLEAttValue&& source) { *this = std::move(source); }
168
171
173 uint16_t max_size() const { return m_attr_max_len; }
174
176 uint16_t capacity() const { return m_capacity; }
177
179 uint16_t length() const { return m_attr_len; }
180
182 uint16_t size() const { return m_attr_len; }
183
185 const uint8_t* data() const { return m_attr_value; }
186
188 const char* c_str() const { return reinterpret_cast<const char*>(m_attr_value); }
189
191 const uint8_t* begin() const { return m_attr_value; }
192
194 const uint8_t* end() const { return m_attr_value + m_attr_len; }
195
196# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
198 time_t getTimeStamp() const { return m_timestamp; }
199
201 void setTimeStamp() { m_timestamp = time(nullptr); }
202
207 void setTimeStamp(time_t t) { m_timestamp = t; }
208# else
209 time_t getTimeStamp() const { return 0; }
210 void setTimeStamp() {}
211 void setTimeStamp(time_t t) {}
212# endif
213
220 bool setValue(const uint8_t* value, uint16_t len);
221
227 bool setValue(const char* s, uint16_t len = 0) {
228 if (len == 0) {
229 len = strlen(s);
230 }
231 return setValue(reinterpret_cast<const uint8_t*>(s), len);
232 }
233
234 const NimBLEAttValue& getValue(time_t* timestamp = nullptr) const {
235 if (timestamp != nullptr) {
236# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
237 *timestamp = m_timestamp;
238# else
239 *timestamp = 0;
240# endif
241 }
242 return *this;
243 }
244
251 NimBLEAttValue& append(const uint8_t* value, uint16_t len);
252
253 /*********************** Template Functions ************************/
254
255# if __cplusplus < 201703L
261 template <typename T>
262# ifdef _DOXYGEN_
263 bool
264# else
265 typename std::enable_if<std::is_array<T>::value &&
266 std::is_same<typename std::remove_extent<T>::type, char>::value,
267 bool>::type
268# endif
269 setValue(const T& s) {
270 return setValue(reinterpret_cast<const uint8_t*>(s), strnlen(s, sizeof(T)));
271 }
272
279 template <typename T>
280# ifdef _DOXYGEN_
281 bool
282# else
283 typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value &&
284 !(std::is_array<T>::value &&
285 std::is_same<typename std::remove_extent<T>::type, char>::value),
286 bool>::type
287# endif
288 setValue(const T& v) {
289 return setValue(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
290 }
291
297 template <typename T>
298# ifdef _DOXYGEN_
299 bool
300# else
301 typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
302# endif
303 setValue(const T& s) {
304 return setValue(reinterpret_cast<const uint8_t*>(s.c_str()), s.length());
305 }
306
313 template <typename T>
314# ifdef _DOXYGEN_
315 bool
316# else
317 typename std::enable_if<Has_data_size<T>::value && Has_value_type<T>::value, bool>::type
318# endif
319 setValue(const T& v) {
320 return setValue(
321 reinterpret_cast<const uint8_t*>(v.data()),
322 v.size() * sizeof(typename T::value_type)
323 );
324 }
325
331 template <typename T>
332# ifdef _DOXYGEN_
333 bool
334# else
335 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
336# endif
337 setValue(const T& v) {
338 return setValue(reinterpret_cast<const uint8_t*>(v.data()), v.size());
339 }
340
341# else
347 template <typename T>
348 typename std::enable_if<!std::is_pointer<T>::value, bool>::type setValue(const T& s) {
349 if constexpr (Has_data_size<T>::value) {
350 if constexpr (Has_value_type<T>::value) {
351 return setValue(reinterpret_cast<const uint8_t*>(s.data()), s.size() * sizeof(typename T::value_type));
352 } else {
353 return setValue(reinterpret_cast<const uint8_t*>(s.data()), s.size());
354 }
355 } else if constexpr (Has_c_str_length<T>::value) {
356 return setValue(reinterpret_cast<const uint8_t*>(s.c_str()), s.length());
357 } else if constexpr (std::is_array<T>::value &&
358 std::is_same<typename std::remove_extent<T>::type, char>::value) {
359 return setValue(reinterpret_cast<const uint8_t*>(s), strnlen(s, sizeof(s)));
360 } else {
361 return setValue(reinterpret_cast<const uint8_t*>(&s), sizeof(s));
362 }
363 }
364# endif
365
376 template <typename T>
377 T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
378 if (timestamp != nullptr) {
379# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
380 *timestamp = m_timestamp;
381# else
382 *timestamp = 0;
383# endif
384 }
385
386 if (!skipSizeCheck && size() < sizeof(T)) {
387 return T();
388 }
389 return *(reinterpret_cast<const T*>(m_attr_value));
390 }
391
392 /*********************** Operators ************************/
393
395 uint8_t operator[](int pos) const;
396
398 operator std::vector<uint8_t>() const { return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
399
401 operator std::string() const { return std::string(reinterpret_cast<char*>(m_attr_value), m_attr_len); }
402
404 operator const uint8_t*() const { return m_attr_value; }
405
407 NimBLEAttValue& operator+=(const NimBLEAttValue& source) { return append(source.data(), source.size()); }
408
410 NimBLEAttValue& operator=(const std::string& source) {
411 setValue(reinterpret_cast<const uint8_t*>(&source[0]), source.size());
412 return *this;
413 }
414
417
420
422 bool operator==(const NimBLEAttValue& source) const {
423 return (m_attr_len == source.size()) ? memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false;
424 }
425
427 bool operator!=(const NimBLEAttValue& source) const { return !(*this == source); }
428
429# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
431 operator String() const { return String(reinterpret_cast<char*>(m_attr_value)); }
432# endif
433};
434
435#endif // CONFIG_BT_NIMBLE_ENABLED
436#endif // NIMBLE_CPP_ATTVALUE_H_
A specialized container class to hold BLE attribute values.
Definition NimBLEAttValue.h:95
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:150
~NimBLEAttValue()
Destructor.
Definition NimBLEAttValue.cpp:58
uint16_t length() const
Returns the current length of the value in bytes.
Definition NimBLEAttValue.h:179
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:126
uint16_t capacity() const
Returns the currently allocated capacity in bytes.
Definition NimBLEAttValue.h:176
const char * c_str() const
Returns a pointer to the internal buffer of the value as a const char*.
Definition NimBLEAttValue.h:188
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:142
bool setValue(const uint8_t *value, uint16_t len)
Set the value from a buffer.
Definition NimBLEAttValue.cpp:107
NimBLEAttValue(std::initializer_list< uint8_t > list, uint16_t max_len=BLE_ATT_ATTR_MAX_LEN)
Construct with an initializer list.
Definition NimBLEAttValue.h:134
NimBLEAttValue & operator+=(const NimBLEAttValue &source)
Operator; Append another NimBLEAttValue.
Definition NimBLEAttValue.h:407
NimBLEAttValue(const NimBLEAttValue &source)
Copy constructor.
Definition NimBLEAttValue.h:164
NimBLEAttValue(NimBLEAttValue &&source)
Move constructor.
Definition NimBLEAttValue.h:167
const uint8_t * data() const
Returns a pointer to the internal buffer of the value.
Definition NimBLEAttValue.h:185
uint8_t operator[](int pos) const
Subscript operator.
Definition NimBLEAttValue.cpp:154
const uint8_t * end() const
Iterator end.
Definition NimBLEAttValue.h:194
bool setValue(const T &v)
Template to set value to the value of <type>val.
Definition NimBLEAttValue.h:288
NimBLEAttValue & append(const uint8_t *value, uint16_t len)
Append data to the value.
Definition NimBLEAttValue.cpp:115
uint16_t size() const
Returns the current size of the value in bytes.
Definition NimBLEAttValue.h:182
bool setValue(const char *s, uint16_t len=0)
Set value to the value of const char*.
Definition NimBLEAttValue.h:227
T getValue(time_t *timestamp=nullptr, bool skipSizeCheck=false) const
Template to return the value as a <type>.
Definition NimBLEAttValue.h:377
uint16_t max_size() const
Returns the max size in bytes.
Definition NimBLEAttValue.h:173
bool setValue(const T &s)
Template to set value to the value of a char array using strnlen.
Definition NimBLEAttValue.h:269
bool operator==(const NimBLEAttValue &source) const
Equality operator.
Definition NimBLEAttValue.h:422
NimBLEAttValue & operator=(const std::string &source)
Operator; Set the value from a std::string source.
Definition NimBLEAttValue.h:410
const uint8_t * begin() const
Iterator begin.
Definition NimBLEAttValue.h:191
bool operator!=(const NimBLEAttValue &source) const
Inequality operator.
Definition NimBLEAttValue.h:427