esp-nimble-cpp 2.3.3
Loading...
Searching...
No Matches
NimBLECharacteristic.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_CHARACTERISTIC_H_
19#define NIMBLE_CPP_CHARACTERISTIC_H_
20
21#include "syscfg/syscfg.h"
22#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
23
24class NimBLECharacteristicCallbacks;
25class NimBLEService;
26class NimBLECharacteristic;
27class NimBLEDescriptor;
28class NimBLE2904;
29
30# include "NimBLELocalValueAttribute.h"
31
32# include <string>
33# include <vector>
34# include <array>
35
42class NimBLECharacteristic : public NimBLELocalValueAttribute {
43 public:
44 NimBLECharacteristic(const char* uuid,
45 uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
46 uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
47 NimBLEService* pService = nullptr);
48 NimBLECharacteristic(const NimBLEUUID& uuid,
49 uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
50 uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
51 NimBLEService* pService = nullptr);
52
53 ~NimBLECharacteristic();
54
55 std::string toString() const;
56 void addDescriptor(NimBLEDescriptor* pDescriptor);
57 void removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc = false);
58 uint16_t getProperties() const;
59 void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
60 bool indicate(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
61 bool indicate(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
62 bool notify(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
63 bool notify(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
64
65 NimBLEDescriptor* createDescriptor(const char* uuid,
66 uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
67 uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
68 NimBLEDescriptor* createDescriptor(const NimBLEUUID& uuid,
69 uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
70 uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
71 NimBLE2904* create2904();
72 NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const;
73 NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const;
74 NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;
75 NimBLEService* getService() const;
76
77 NimBLECharacteristicCallbacks* getCallbacks() const;
78
79 /*********************** Template Functions ************************/
80
81# if __cplusplus < 201703L
88 template <typename T>
89# ifdef _DOXYGEN_
90 bool
91# else
92 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value &&
93 !Has_data_size<T>::value,
94 bool>::type
95# endif
96 notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
97 return notify(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
98 }
99
105 template <typename T>
106# ifdef _DOXYGEN_
107 bool
108# else
109 typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
110# endif
111 notify(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
112 return notify(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
113 }
114
121 template <typename T>
122# ifdef _DOXYGEN_
123 bool
124# else
125 typename std::enable_if<Has_data_size<T>::value && Has_value_type<T>::value, bool>::type
126# endif
127 notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
128 return notify(
129 reinterpret_cast<const uint8_t*>(v.data()),
130 v.size() * sizeof(typename T::value_type),
131 connHandle
132 );
133 }
134
140 template <typename T>
141# ifdef _DOXYGEN_
142 bool
143# else
144 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
145# endif
146 notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
147 return notify(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
148 }
149
156 template <typename T>
157# ifdef _DOXYGEN_
158 bool
159# else
160 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value &&
161 !Has_data_size<T>::value,
162 bool>::type
163# endif
164 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
165 return indicate(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
166 }
167
173 template <typename T>
174# ifdef _DOXYGEN_
175 bool
176# else
177 typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
178# endif
179 indicate(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
180 return indicate(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
181 }
182
189 template <typename T>
190# ifdef _DOXYGEN_
191 bool
192# else
193 typename std::enable_if<Has_data_size<T>::value && Has_value_type<T>::value, bool>::type
194# endif
195 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
196 return indicate(
197 reinterpret_cast<const uint8_t*>(v.data()),
198 v.size() * sizeof(typename T::value_type),
199 connHandle
200 );
201 }
202
208 template <typename T>
209# ifdef _DOXYGEN_
210 bool
211# else
212 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
213# endif
214 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
215 return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
216 }
217
218# else
219
230 template <typename T>
231 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type notify(
232 const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
233 if constexpr (Has_data_size<T>::value) {
234 if constexpr (Has_value_type<T>::value) {
235 return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size() * sizeof(typename T::value_type), connHandle);
236 } else {
237 return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
238 }
239 } else if constexpr (Has_c_str_length<T>::value) {
240 return notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
241 } else {
242 return notify(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
243 }
244 }
245
256 template <typename T>
257 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type indicate(
258 const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
259 if constexpr (Has_data_size<T>::value) {
260 if constexpr (Has_value_type<T>::value) {
261 return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size() * sizeof(typename T::value_type), connHandle);
262 } else {
263 return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
264 }
265 } else if constexpr (Has_c_str_length<T>::value) {
266 return indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
267 } else {
268 return indicate(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
269 }
270 }
271# endif
272
273 private:
274 friend class NimBLEServer;
275 friend class NimBLEService;
276
277 void setService(NimBLEService* pService);
278 void readEvent(NimBLEConnInfo& connInfo) override;
279 void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
280 bool sendValue(const uint8_t* value,
281 size_t length,
282 bool is_notification = true,
283 uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
284
285 struct SubPeerEntry {
286 enum : uint8_t { AWAITING_SECURE = 1 << 0, SECURE = 1 << 1, SUB_NOTIFY = 1 << 2, SUB_INDICATE = 1 << 3 };
287 void setConnHandle(uint16_t connHandle) { m_connHandle = connHandle; }
288 uint16_t getConnHandle() const { return m_connHandle; }
289 void setAwaitingSecure(bool awaiting) { awaiting ? m_flags |= AWAITING_SECURE : m_flags &= ~AWAITING_SECURE; }
290 void setSecured(bool secure) { secure ? m_flags |= SECURE : m_flags &= ~SECURE; }
291 void setSubNotify(bool notify) { notify ? m_flags |= SUB_NOTIFY : m_flags &= ~SUB_NOTIFY; }
292 void setSubIndicate(bool indicate) { indicate ? m_flags |= SUB_INDICATE : m_flags &= ~SUB_INDICATE; }
293 bool isSubNotify() const { return m_flags & SUB_NOTIFY; }
294 bool isSubIndicate() const { return m_flags & SUB_INDICATE; }
295 bool isSecured() const { return m_flags & SECURE; }
296 bool isAwaitingSecure() const { return m_flags & AWAITING_SECURE; }
297
298 private:
299 uint16_t m_connHandle{BLE_HS_CONN_HANDLE_NONE};
300 uint8_t m_flags{0};
301 } __attribute__((packed));
302
303 using SubPeerArray = std::array<SubPeerEntry, MYNEWT_VAL(BLE_MAX_CONNECTIONS)>;
304 SubPeerArray getSubscribers() const { return m_subPeers; }
305 void processSubRequest(NimBLEConnInfo& connInfo, uint8_t subVal) const;
306 void updatePeerStatus(const NimBLEConnInfo& peerInfo) const;
307
308 NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
309 NimBLEService* m_pService{nullptr};
310 std::vector<NimBLEDescriptor*> m_vDescriptors{};
311 mutable SubPeerArray m_subPeers{};
312}; // NimBLECharacteristic
313
321class NimBLECharacteristicCallbacks {
322 public:
323 virtual ~NimBLECharacteristicCallbacks() {}
324 virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
325 virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
326 virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code); // deprecated
327 virtual void onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, int code);
328 virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
329};
330
331#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
332#endif // NIMBLE_CPP_CHARACTERISTIC_H_
Connection information.
Definition NimBLEConnInfo.h:32
A model of a BLE UUID.
Definition NimBLEUUID.h:41