summaryrefslogtreecommitdiff
path: root/src/BLERemoteCharacteristic.cpp
blob: 5227bf6ce48cdb2b01086ec63bb49e01463c8e77 (plain)
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
 * BLERemoteCharacteristic.cpp
 *
 *  Created on: Jul 8, 2017
 *      Author: kolban
 */
 
#include "BLERemoteCharacteristic.h"
 
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
 
#include <esp_gattc_api.h>
#include <esp_log.h>
#include <esp_err.h>
 
#include <sstream>
#include "BLEUtils.h"
#include "GeneralUtils.h"
 
 
static const char* LOG_TAG = "BLERemoteCharacteristic";
 
BLERemoteCharacteristic::BLERemoteCharacteristic(
esp_gatt_id_t        charId,
esp_gatt_char_prop_t charProp,
BLERemoteService*    pRemoteService) {
m_charId         = charId;
m_charProp       = charProp;
m_pRemoteService = pRemoteService;
m_notifyCallback = nullptr;
} // BLERemoteCharacteristic 
 
 
static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) {
if (id1.id.inst_id != id2.id.inst_id{
return false;
}
if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) {
return false;
}
return true;
} // compareSrvcId 
 
 
static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) {
if (id1.inst_id != id2.inst_id{
return false;
}
if (!BLEUUID(id1.uuid).equals(BLEUUID(id2.uuid))) {
return false;
}
return true;
} // compareCharId 
 
 
/**
 * @brief Handle GATT Client events.
 * When an event arrives for a GATT client we give this characteristic the opportunity to
 * take a look at it to see if there is interest in it.
 * @param [in] event The type of event.
 * @param [in] gattc_if The interface on which the event was received.
 * @param [in] evtParam Payload data for the event.
 * @returns N/A
 */
void BLERemoteCharacteristic::gattClientEventHandler(
esp_gattc_cb_event_t      event,
esp_gatt_if_t             gattc_if,
esp_ble_gattc_cb_param_t* evtParam) {
switch(event) {
// 
// ESP_GATTC_READ_CHAR_EVT 
// This event indicates that the server has responded to the read request. 
// 
// read: 
// esp_gatt_status_t  status 
// uint16_t           conn_id 
// esp_gatt_srvc_id_t srvc_id 
// esp_gatt_id_t      char_id 
// esp_gatt_id_t      descr_id 
// uint8_t*           value 
// uint16_t           value_type 
// uint16_t           value_len 
case ESP_GATTC_READ_CHAR_EVT: {
if (compareSrvcId(evtParam->read.srvc_id, *m_pRemoteService->getSrvcId()) == false{
break;
}
 
if (evtParam->read.conn_id != m_pRemoteService->getClient()->getConnId()) {
break;
}
 
if (compareGattId(evtParam->read.char_id, m_charId) == false{
break;
}
 
if (evtParam->read.status == ESP_GATT_OK) {
m_value = std::string((char*)evtParam->read.value, evtParam->read.value_len);
} else {
m_value = "";
}
 
m_semaphoreReadCharEvt.give();
break;
} // ESP_GATTC_READ_CHAR_EVT 
 
 
// 
// ESP_GATTC_REG_FOR_NOTIFY_EVT 
// 
// reg_for_notify: 
// - esp_gatt_status_t status 
// - esp_gatt_srvc_id_t srvc_id 
// - esp_gatt_id_t char_id 
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
if (compareSrvcId(evtParam->reg_for_notify.srvc_id, *m_pRemoteService->getSrvcId()) == false{
break;
}
if (compareGattId(evtParam->reg_for_notify.char_id, m_charId) == false{
break;
}
m_semaphoreRegForNotifyEvt.give();
break;
} // ESP_GATTC_REG_FOR_NOTIFY_EVT 
 
 
// 
// ESP_GATTC_WRITE_CHAR_EVT 
// 
// write: 
// esp_gatt_status_t  status 
// uint16_t           conn_id 
// esp_gatt_srvc_id_t srvc_id 
// esp_gatt_id_t      char_id 
// esp_gatt_id_t      descr_id 
case ESP_GATTC_WRITE_CHAR_EVT: {
if (compareSrvcId(evtParam->write.srvc_id, *m_pRemoteService->getSrvcId()) == false{
break;
}
if (evtParam->write.conn_id != m_pRemoteService->getClient()->getConnId()) {
break;
}
if (compareGattId(evtParam->write.char_id, m_charId) == false{
break;
}
m_semaphoreWriteCharEvt.give();
break;
} // ESP_GATTC_WRITE_CHAR_EVT 
 
 
default{
break;
}
}
}// gattClientEventHandler 
 
 
BLEUUID BLERemoteCharacteristic::getUUID() {
return BLEUUID(m_charId.uuid);
}
 
/**
 * @brief Read an unsigned 16 bit value
 * @return The unsigned 16 bit value.
 */
uint16_t BLERemoteCharacteristic::readUInt16(void) {
std::string value = readValue();
if (value.length() >= 2{
return *(uint16_t*)(value.data());
}
return 0;
} // readUInt16 
 
 
/**
 * @brief Read an unsigned 32 bit value.
 * @return the unsigned 32 bit value.
 */
uint32_t BLERemoteCharacteristic::readUInt32(void) {
std::string value = readValue();
if (value.length() >= 4{
return *(uint32_t*)(value.data());
}
return 0;
} // readUInt32 
 
 
/**
 * @brief Read a byte value
 * @return The value as a byte
 */
uint8_t BLERemoteCharacteristic::readUInt8(void) {
std::string value = readValue();
if (value.length() >= 1{
return (uint8_t)value[0];
}
return 0;
} // readUInt8 
 
 
/**
 * @brief Read the value of the remote characteristic.
 * @return The value of the remote characteristic.
 */
std::string BLERemoteCharacteristic::readValue() {
ESP_LOGD(LOG_TAG, ">> readValue()");
 
m_semaphoreReadCharEvt.take("readValue");
 
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. 
esp_err_t errRc = ::esp_ble_gattc_read_char(
m_pRemoteService->getClient()->getGattcIf(),
m_pRemoteService->getClient()->getConnId(),
m_pRemoteService->getSrvcId(),
&m_charId,
ESP_GATT_AUTH_REQ_NONE);
 
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return "";
}
 
// Block waiting for the event that indicates that the read has completed.  When it has, the std::string found 
// in m_value will contain our data. 
m_semaphoreReadCharEvt.wait("readValue");
 
ESP_LOGD(LOG_TAG, "<< readValue()");
return m_value;
} // readValue 
 
 
/**
 * @brief Register for notifications.
 * @param [in] notifyCallback A callback to be invoked for a notification.
 * @return N/A.
 */
void BLERemoteCharacteristic::registerForNotify(
void (*notifyCallback)(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify){
ESP_LOGD(LOG_TAG, ">> registerForNotify()");
 
m_notifyCallback = notifyCallback; // Save the notification callback. 
 
m_semaphoreRegForNotifyEvt.take("registerForNotify");
 
esp_err_t errRc = ::esp_ble_gattc_register_for_notify(
m_pRemoteService->getClient()->getGattcIf(),
*m_pRemoteService->getClient()->getPeerAddress().getNative(),
m_pRemoteService->getSrvcId(),
&m_charId);
 
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
 
m_semaphoreRegForNotifyEvt.wait("registerForNotify");
 
ESP_LOGD(LOG_TAG, "<< registerForNotify()");
} // registerForNotify 
 
 
/**
 * @brief Convert a BLERemoteCharacteristic to a string representation;
 * @return a String representation.
 */
std::string BLERemoteCharacteristic::toString() {
std::ostringstream ss;
ss << "Characteristic: uuid: " << BLEUUID(m_charId.uuid).toString() <<
", props: " << BLEUtils::characteristicPropertiesToString(m_charProp) <<
", inst_id: " << (int)m_charId.inst_id;
return ss.str();
} // toString 
 
 
/**
 * @brief Write the new value for the characteristic.
 * @param [in] newValue The new value to write.
 * @param [in] response Do we expect a response?
 * @return N/A.
 */
void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) {
ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", newValue.length());
 
m_semaphoreWriteCharEvt.take("writeValue");
 
esp_err_t errRc = ::esp_ble_gattc_write_char(
m_pRemoteService->getClient()->getGattcIf(),
m_pRemoteService->getClient()->getConnId(),
m_pRemoteService->getSrvcId(),
&m_charId,
newValue.length(),
(uint8_t*)newValue.data(),
response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE
);
 
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
 
m_semaphoreWriteCharEvt.wait("writeValue");
 
ESP_LOGD(LOG_TAG, "<< writeValue");
} // writeValue 
 
 
/**
 * @brief Write the new value for the characteristic.
 *
 * This is a convenience function.  Many BLE characteristics are a single byte of data.
 * @param [in] newValue The new byte value to write.
 * @param [in] response Whether we require a response from the write.
 * @return N/A.
 */
void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) {
writeValue(std::string(reinterpret_cast<char*>(&newValue), 1), response);
} // writeValue 
 
 
/**
 * @brief Write the new value for the characteristic from a data buffer.
 * @param [in] data A pointer to a data buffer.
 * @param [in] length The length of the data in the data buffer.
 * @param [in] response Whether we require a response from the write.
 */
void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) {
writeValue(std::string((char *)data, length), response);
} // writeValue 
 
 
#endif /* CONFIG_BT_ENABLED */