esp-nimble-cpp 2.5.0
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, uint16_t index = 0) const;
73 NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid, uint16_t index = 0) 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(reinterpret_cast<const uint8_t*>(v.data()), v.size() * sizeof(typename T::value_type), connHandle);
129 }
130
136 template <typename T>
137# ifdef _DOXYGEN_
138 bool
139# else
140 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
141# endif
142 notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
143 return notify(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
144 }
145
152 template <typename T>
153# ifdef _DOXYGEN_
154 bool
155# else
156 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value &&
157 !Has_data_size<T>::value,
158 bool>::type
159# endif
160 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
161 return indicate(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
162 }
163
169 template <typename T>
170# ifdef _DOXYGEN_
171 bool
172# else
173 typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
174# endif
175 indicate(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
176 return indicate(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
177 }
178
185 template <typename T>
186# ifdef _DOXYGEN_
187 bool
188# else
189 typename std::enable_if<Has_data_size<T>::value && Has_value_type<T>::value, bool>::type
190# endif
191 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
192 return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size() * sizeof(typename T::value_type), connHandle);
193 }
194
200 template <typename T>
201# ifdef _DOXYGEN_
202 bool
203# else
204 typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
205# endif
206 indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
207 return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
208 }
209
210# else
211
222 template <typename T>
223 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type notify(
224 const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
225 if constexpr (Has_data_size<T>::value) {
226 if constexpr (Has_value_type<T>::value) {
227 return notify(reinterpret_cast<const uint8_t*>(value.data()),
228 value.size() * sizeof(typename T::value_type),
229 connHandle);
230 } else {
231 return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
232 }
233 } else if constexpr (Has_c_str_length<T>::value) {
234 return notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
235 } else {
236 return notify(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
237 }
238 }
239
250 template <typename T>
251 typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type indicate(
252 const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
253 if constexpr (Has_data_size<T>::value) {
254 if constexpr (Has_value_type<T>::value) {
255 return indicate(reinterpret_cast<const uint8_t*>(value.data()),
256 value.size() * sizeof(typename T::value_type),
257 connHandle);
258 } else {
259 return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
260 }
261 } else if constexpr (Has_c_str_length<T>::value) {
262 return indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
263 } else {
264 return indicate(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
265 }
266 }
267# endif
268
269 private:
270 friend class NimBLEServer;
271 friend class NimBLEService;
272
273 void setService(NimBLEService* pService);
274 void readEvent(NimBLEConnInfo& connInfo) override;
275 void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
276 bool sendValue(const uint8_t* value,
277 size_t length,
278 bool is_notification = true,
279 uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
280
281 struct SubPeerEntry {
282 enum : uint8_t { AWAITING_SECURE = 1 << 0, SECURE = 1 << 1, SUB_NOTIFY = 1 << 2, SUB_INDICATE = 1 << 3 };
283 void setConnHandle(uint16_t connHandle) { m_connHandle = connHandle; }
284 uint16_t getConnHandle() const { return m_connHandle; }
285 void setAwaitingSecure(bool awaiting) { awaiting ? m_flags |= AWAITING_SECURE : m_flags &= ~AWAITING_SECURE; }
286 void setSecured(bool secure) { secure ? m_flags |= SECURE : m_flags &= ~SECURE; }
287 void setSubNotify(bool notify) { notify ? m_flags |= SUB_NOTIFY : m_flags &= ~SUB_NOTIFY; }
288 void setSubIndicate(bool indicate) { indicate ? m_flags |= SUB_INDICATE : m_flags &= ~SUB_INDICATE; }
289 bool isSubNotify() const { return m_flags & SUB_NOTIFY; }
290 bool isSubIndicate() const { return m_flags & SUB_INDICATE; }
291 bool isSecured() const { return m_flags & SECURE; }
292 bool isAwaitingSecure() const { return m_flags & AWAITING_SECURE; }
293
294 private:
295 uint16_t m_connHandle{BLE_HS_CONN_HANDLE_NONE};
296 uint8_t m_flags{0};
297 } __attribute__((packed));
298
299 using SubPeerArray = std::array<SubPeerEntry, MYNEWT_VAL(BLE_MAX_CONNECTIONS)>;
300 SubPeerArray getSubscribers() const { return m_subPeers; }
301 void processSubRequest(NimBLEConnInfo& connInfo, uint8_t subVal) const;
302 void updatePeerStatus(const NimBLEConnInfo& peerInfo) const;
303
304 NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
305 NimBLEService* m_pService{nullptr};
306 std::vector<NimBLEDescriptor*> m_vDescriptors{};
307 mutable SubPeerArray m_subPeers{};
308}; // NimBLECharacteristic
309
317class NimBLECharacteristicCallbacks {
318 public:
319 virtual ~NimBLECharacteristicCallbacks() {}
320 virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
321 virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
322 virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code); // deprecated
323 virtual void onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, int code);
324 virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
325};
326
327#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
328#endif // NIMBLE_CPP_CHARACTERISTIC_H_
Connection information.
Definition NimBLEConnInfo.h:33
A model of a BLE UUID.
Definition NimBLEUUID.h:41