-
-
Notifications
You must be signed in to change notification settings - Fork 169
/
Copy pathNimBLECharacteristic.h
253 lines (229 loc) · 11.2 KB
/
NimBLECharacteristic.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Copyright 2020-2025 Ryan Powell <[email protected]> and
* esp-nimble-cpp, NimBLE-Arduino contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NIMBLE_CPP_CHARACTERISTIC_H_
#define NIMBLE_CPP_CHARACTERISTIC_H_
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
class NimBLECharacteristicCallbacks;
class NimBLEService;
class NimBLECharacteristic;
class NimBLEDescriptor;
class NimBLE2904;
# include "NimBLELocalValueAttribute.h"
# include <string>
# include <vector>
/**
* @brief The model of a BLE Characteristic.
*
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE service and
* can be read and written to by a BLE client.
*/
class NimBLECharacteristic : public NimBLELocalValueAttribute {
public:
NimBLECharacteristic(const char* uuid,
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
NimBLECharacteristic(const NimBLEUUID& uuid,
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
NimBLEService* pService = nullptr);
~NimBLECharacteristic();
std::string toString() const;
void addDescriptor(NimBLEDescriptor* pDescriptor);
void removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc = false);
uint16_t getProperties() const;
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
bool indicate(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
bool indicate(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
bool notify(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
bool notify(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
NimBLEDescriptor* createDescriptor(const char* uuid,
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
NimBLEDescriptor* createDescriptor(const NimBLEUUID& uuid,
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
NimBLE2904* create2904();
NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const;
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const;
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;
NimBLEService* getService() const;
NimBLECharacteristicCallbacks* getCallbacks() const;
/*********************** Template Functions ************************/
# if __cplusplus < 201703L
/**
* @brief Template to send a notification with a value from a struct or array.
* @param [in] v The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
* @details <type\> size must be evaluatable by `sizeof()`.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
# endif
notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return notify(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
}
/**
* @brief Template to send a notification with a value from a class that has a c_str() and length() method.
* @param [in] s The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
# endif
notify(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return notify(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
}
/**
* @brief Template to send a notification with a value from a class that has a data() and size() method.
* @param [in] v The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<Has_data_size<T>::value, bool>::type
# endif
notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return notify(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
}
/**
* @brief Template to send an indication with a value from a struct or array.
* @param [in] v The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
* @details <type\> size must be evaluatable by `sizeof()`.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
# endif
indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return indicate(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
}
/**
* @brief Template to send a indication with a value from a class that has a c_str() and length() method.
* @param [in] s The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
# endif
indicate(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return indicate(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
}
/**
* @brief Template to send a indication with a value from a class that has a data() and size() method.
* @param [in] v The value to send.
* @param [in] connHandle Optional, a connection handle to send the notification to.
*/
template <typename T>
# ifdef _DOXYGEN_
bool
# else
typename std::enable_if<Has_data_size<T>::value, bool>::type
# endif
indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
}
# else
/**
* @brief Template to send a notification for classes which may have
* data()/size() or c_str()/length() methods. Falls back to sending
* the data by casting the first element of the array to a uint8_t
* pointer and getting the length of the array using sizeof.
* @tparam T The a reference to a class containing the data to send.
* @param[in] value The <type\>value to set.
* @param[in] connHandle The connection handle to send the notification to.
* @note This function is only available if the type T is not a pointer.
*/
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, bool>::type notify(const T& value,
uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
if constexpr (Has_data_size<T>::value) {
return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
} else if constexpr (Has_c_str_length<T>::value) {
return notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
} else {
return notify(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
}
}
/**
* @brief Template to send an indication for classes which may have
* data()/size() or c_str()/length() methods. Falls back to sending
* the data by casting the first element of the array to a uint8_t
* pointer and getting the length of the array using sizeof.
* @tparam T The a reference to a class containing the data to send.
* @param[in] value The <type\>value to set.
* @param[in] connHandle The connection handle to send the indication to.
* @note This function is only available if the type T is not a pointer.
*/
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, bool>::type indicate(
const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
if constexpr (Has_data_size<T>::value) {
return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
} else if constexpr (Has_c_str_length<T>::value) {
return indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
} else {
return indicate(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
}
}
# endif
private:
friend class NimBLEServer;
friend class NimBLEService;
void setService(NimBLEService* pService);
void readEvent(NimBLEConnInfo& connInfo) override;
void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
bool sendValue(const uint8_t* value,
size_t length,
bool is_notification = true,
uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
NimBLEService* m_pService{nullptr};
std::vector<NimBLEDescriptor*> m_vDescriptors{};
}; // NimBLECharacteristic
/**
* @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
*
* When a server application creates a %BLE characteristic, we may wish to be informed when there is either
* a read or write request to the characteristic's value. An application can register a
* sub-classed instance of this class and will be notified when such an event happens.
*/
class NimBLECharacteristicCallbacks {
public:
virtual ~NimBLECharacteristicCallbacks() {}
virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code);
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
};
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
#endif /*NIMBLE_CPP_CHARACTERISTIC_H_*/