summaryrefslogtreecommitdiff
path: root/sensor/patchedBLE/src/BLERemoteService.cpp
blob: c2b7d344fd93dc6723c6891daf186ca0d255a2e8 (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
337
338
339
340
/*
 * BLERemoteService.cpp
 *
 *  Created on: Jul 8, 2017
 *      Author: kolban
 */
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
 
#include <sstream>
#include "BLERemoteService.h"
#include "BLEUtils.h"
#include "GeneralUtils.h"
#include <esp_err.h>
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define LOG_TAG ""
#else
#include "esp_log.h"
static const char* LOG_TAG = "BLERemoteService";
#endif
 
 
 
BLERemoteService::BLERemoteService(
esp_gatt_id_t srvcId,
BLEClient*    pClient,
uint16_t      startHandle,
uint16_t      endHandle
) {
 
ESP_LOGD(LOG_TAG, ">> BLERemoteService()");
m_srvcId  = srvcId;
m_pClient = pClient;
m_uuid    = BLEUUID(m_srvcId);
m_haveCharacteristics = false;
m_startHandle = startHandle;
m_endHandle = endHandle;
 
ESP_LOGD(LOG_TAG, "<< BLERemoteService()");
}
 
 
BLERemoteService::~BLERemoteService() {
removeCharacteristics();
}
 
/*
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
*/
 
/**
 * @brief Handle GATT Client events
 */
void BLERemoteService::gattClientEventHandler(
esp_gattc_cb_event_t      event,
esp_gatt_if_t             gattc_if,
esp_ble_gattc_cb_param_t* evtParam) {
switch (event) {
// 
// ESP_GATTC_GET_CHAR_EVT 
// 
// get_char: 
// - esp_gatt_status_t    status 
// - uin1t6_t             conn_id 
// - esp_gatt_srvc_id_t   srvc_id 
// - esp_gatt_id_t        char_id 
// - esp_gatt_char_prop_t char_prop 
// 
/*
case ESP_GATTC_GET_CHAR_EVT: {
// Is this event for this service?  If yes, then the local srvc_id and the event srvc_id will be
// the same.
if (compareSrvcId(m_srvcId, evtParam->get_char.srvc_id) == false) {
break;
}
 
// If the status is NOT OK then we have a problem and continue.
if (evtParam->get_char.status != ESP_GATT_OK) {
m_semaphoreGetCharEvt.give();
break;
}
 
// This is an indication that we now have the characteristic details for a characteristic owned
// by this service so remember it.
m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(
BLEUUID(evtParam->get_char.char_id.uuid).toString(),
new BLERemoteCharacteristic(evtParam->get_char.char_id, evtParam->get_char.char_prop, this) ));
 
 
// Now that we have received a characteristic, lets ask for the next one.
esp_err_t errRc = ::esp_ble_gattc_get_characteristic(
m_pClient->getGattcIf(),
m_pClient->getConnId(),
&m_srvcId,
&evtParam->get_char.char_id);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
break;
}
 
//m_semaphoreGetCharEvt.give();
break;
} // ESP_GATTC_GET_CHAR_EVT
*/
default:
break;
} // switch 
 
// Send the event to each of the characteristics owned by this service. 
for (auto &myPair : m_characteristicMapByHandle) {
   myPair.second->gattClientEventHandler(event, gattc_if, evtParam);
}
} // gattClientEventHandler 
 
 
/**
 * @brief Get the remote characteristic object for the characteristic UUID.
 * @param [in] uuid Remote characteristic uuid.
 * @return Reference to the remote characteristic object.
 * @throws BLEUuidNotFoundException
 */
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) {
    return getCharacteristic(BLEUUID(uuid));
} // getCharacteristic 
/**
 * @brief Get the characteristic object for the UUID.
 * @param [in] uuid Characteristic uuid.
 * @return Reference to the characteristic object.
 * @throws BLEUuidNotFoundException
 */
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) {
// Design 
// ------ 
// We wish to retrieve the characteristic given its UUID.  It is possible that we have not yet asked the 
// device what characteristics it has in which case we have nothing to match against.  If we have not 
// asked the device about its characteristics, then we do that now.  Once we get the results we can then 
// examine the characteristics map to see if it has the characteristic we are looking for. 
if (!m_haveCharacteristics) {
retrieveCharacteristics();
}
std::string v = uuid.toString();
for (auto &myPair : m_characteristicMap) {
if (myPair.first == v) {
return myPair.second;
}
}
// throw new BLEUuidNotFoundException();  // <-- we dont want exception here, which will cause app crash, we want to search if any characteristic can be found one after another 
return nullptr;
} // getCharacteristic 
 
 
/**
 * @brief Retrieve all the characteristics for this service.
 * This function will not return until we have all the characteristics.
 * @return N/A
 */
void BLERemoteService::retrieveCharacteristics() {
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
 
removeCharacteristics(); // Forget any previous characteristics. 
 
uint16_t offset = 0;
esp_gattc_char_elem_t result;
while (true{
uint16_t count = 10;  // this value is used as in parameter that allows to search max 10 chars with the same uuid 
esp_gatt_status_t status = ::esp_ble_gattc_get_all_char(
getClient()->getGattcIf(),
getClient()->getConnId(),
m_startHandle,
m_endHandle,
&result,
&count,
offset
);
 
if (status == ESP_GATT_INVALID_OFFSET) {   // We have reached the end of the entries. 
break;
}
 
if (status != ESP_GATT_OK) {   // If we got an error, end. 
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_all_char: %s", BLEUtils::gattStatusToString(status).c_str());
break;
}
 
if (count == 0{   // If we failed to get any new records, end. 
break;
}
 
ESP_LOGD(LOG_TAG, "Found a characteristic: Handle: %d, UUID: %s", result.char_handle, BLEUUID(result.uuid).toString().c_str());
 
// We now have a new characteristic ... let us add that to our set of known characteristics 
BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic(
result.char_handle,
BLEUUID(result.uuid),
result.properties,
this
);
 
m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic));
m_characteristicMapByHandle.insert(std::pair<uint16_t, BLERemoteCharacteristic*>(result.char_handle, pNewRemoteCharacteristic));
offset++;   // Increment our count of number of descriptors found. 
} // Loop forever (until we break inside the loop). 
 
m_haveCharacteristics = true// Remember that we have received the characteristics. 
ESP_LOGD(LOG_TAG, "<< getCharacteristics()");
} // getCharacteristics 
 
 
/**
 * @brief Retrieve a map of all the characteristics of this service.
 * @return A map of all the characteristics of this service.
 */
std::map<std::string, BLERemoteCharacteristic*>* BLERemoteService::getCharacteristics() {
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
// If is possible that we have not read the characteristics associated with the service so do that 
// now.  The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking 
// call and does not return until all the characteristics are available. 
if (!m_haveCharacteristics) {
retrieveCharacteristics();
}
ESP_LOGD(LOG_TAG, "<< getCharacteristics() for service: %s", getUUID().toString().c_str());
return &m_characteristicMap;
} // getCharacteristics 
 
/**
 * @brief This function is designed to get characteristics map when we have multiple characteristics with the same UUID
 */
void BLERemoteService::getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap) {
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
pCharacteristicMap = &m_characteristicMapByHandle;
}  // Get the characteristics map. 
 
/**
 * @brief Get the client associated with this service.
 * @return A reference to the client associated with this service.
 */
BLEClient* BLERemoteService::getClient() {
return m_pClient;
} // getClient 
 
 
uint16_t BLERemoteService::getEndHandle() {
return m_endHandle;
} // getEndHandle 
 
 
esp_gatt_id_t* BLERemoteService::getSrvcId() {
return &m_srvcId;
} // getSrvcId 
 
 
uint16_t BLERemoteService::getStartHandle() {
return m_startHandle;
} // getStartHandle 
 
 
uint16_t BLERemoteService::getHandle() {
ESP_LOGD(LOG_TAG, ">> getHandle: service: %s", getUUID().toString().c_str());
ESP_LOGD(LOG_TAG, "<< getHandle: %d 0x%.2x", getStartHandle(), getStartHandle());
return getStartHandle();
} // getHandle 
 
 
BLEUUID BLERemoteService::getUUID() {
return m_uuid;
}
 
/**
 * @brief Read the value of a characteristic associated with this service.
 */
std::string BLERemoteService::getValue(BLEUUID characteristicUuid) {
ESP_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
std::string ret =  getCharacteristic(characteristicUuid)->readValue();
ESP_LOGD(LOG_TAG, "<< readValue");
return ret;
} // readValue 
 
 
 
/**
 * @brief Delete the characteristics in the characteristics map.
 * We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic
 * object references.  Since we allocated these in this class, we are also responsible for deleteing
 * them.  This method does just that.
 * @return N/A.
 */
void BLERemoteService::removeCharacteristics() {
for (auto &myPair : m_characteristicMap) {
   delete myPair.second;
   //m_characteristicMap.erase(myPair.first);  // Should be no need to delete as it will be deleted by the clear 
}
m_characteristicMap.clear();   // Clear the map 
for (auto &myPair : m_characteristicMapByHandle) {
   delete myPair.second;
}
m_characteristicMapByHandle.clear();   // Clear the map 
} // removeCharacteristics 
 
 
/**
 * @brief Set the value of a characteristic.
 * @param [in] characteristicUuid The characteristic to set.
 * @param [in] value The value to set.
 * @throws BLEUuidNotFound
 */
void BLERemoteService::setValue(BLEUUID characteristicUuid, std::string value) {
ESP_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
getCharacteristic(characteristicUuid)->writeValue(value);
ESP_LOGD(LOG_TAG, "<< setValue");
} // setValue 
 
 
/**
 * @brief Create a string representation of this remote service.
 * @return A string representation of this remote service.
 */
std::string BLERemoteService::toString() {
std::ostringstream ss;
ss << "Service: uuid: " + m_uuid.toString();
ss << ", start_handle: " << std::dec << m_startHandle << " 0x" << std::hex << m_startHandle <<
", end_handle: " << std::dec << m_endHandle << " 0x" << std::hex << m_endHandle;
for (auto &myPair : m_characteristicMap) {
ss << "\n" << myPair.second->toString();
   // myPair.second is the value 
}
return ss.str();
} // toString 
 
 
#endif /* CONFIG_BT_ENABLED */