simplejsble 0.0.29 → 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/NitroSimplejsble.podspec +1 -1
  2. package/VERSION +1 -1
  3. package/dependencies/external/kvn/kvn_bytearray.h +7 -0
  4. package/lib/index.d.ts +3 -0
  5. package/lib/index.d.ts.map +1 -0
  6. package/lib/index.js +2 -0
  7. package/lib/specs/Adapter.nitro.d.ts +10 -0
  8. package/lib/specs/Adapter.nitro.d.ts.map +1 -0
  9. package/lib/specs/Adapter.nitro.js +1 -0
  10. package/package.json +2 -2
  11. package/simpleble/CMakeLists.txt +1 -6
  12. package/simpleble/src/backends/dongl/AdapterDongl.cpp +10 -143
  13. package/simpleble/src/backends/dongl/AdapterDongl.h +0 -1
  14. package/simpleble/src/backends/dongl/PeripheralDongl.cpp +120 -118
  15. package/simpleble/src/backends/dongl/PeripheralDongl.h +9 -2
  16. package/simpleble/src/backends/dongl/protocol/d2h.pb.h +9 -26
  17. package/simpleble/src/backends/dongl/protocol/h2d.pb.h +2 -12
  18. package/simpleble/src/backends/dongl/serial/Protocol.cpp +1 -755
  19. package/simpleble/src/backends/dongl/serial/Protocol.h +0 -75
  20. package/simpleble/test/src/test_bytearray.cpp +7 -0
  21. package/simpleble/src/backends/dongl/protocol/softdevice.pb.c +0 -18
  22. package/simpleble/src/backends/dongl/protocol/softdevice.pb.h +0 -815
  23. package/simpleble/src/backends/dongl/protocol/softdevice_gap.pb.c +0 -339
  24. package/simpleble/src/backends/dongl/protocol/softdevice_gap.pb.h +0 -2086
  25. package/simpleble/src/backends/dongl/protocol/softdevice_gattc.pb.c +0 -114
  26. package/simpleble/src/backends/dongl/protocol/softdevice_gattc.pb.h +0 -772
  27. package/simpleble/src/backends/dongl/protocol/softdevice_gatts.pb.c +0 -117
  28. package/simpleble/src/backends/dongl/protocol/softdevice_gatts.pb.h +0 -766
  29. package/simpleble/src/backends/dongl/protocol/softdevice_types.pb.c +0 -207
  30. package/simpleble/src/backends/dongl/protocol/softdevice_types.pb.h +0 -1686
@@ -7,6 +7,7 @@
7
7
  #include <simpleble/Exceptions.h>
8
8
 
9
9
  #include <cstdint>
10
+ #include <functional>
10
11
  #include <memory>
11
12
  #include <thread>
12
13
 
@@ -104,10 +105,8 @@ void PeripheralDongl::unpair() {}
104
105
  SharedPtrVector<ServiceBase> PeripheralDongl::available_services() {
105
106
  SharedPtrVector<ServiceBase> service_list;
106
107
  for (auto& service : _services) {
107
- fmt::print("PeripheralDongl::available_services: Service UUID: {}\n", service.uuid);
108
108
  SharedPtrVector<CharacteristicBase> characteristic_list;
109
109
  for (auto& characteristic : service.characteristics) {
110
- fmt::print("PeripheralDongl::available_services: Characteristic UUID: {}\n", characteristic.uuid);
111
110
  SharedPtrVector<DescriptorBase> descriptor_list;
112
111
  for (auto& descriptor : characteristic.descriptors) {
113
112
  descriptor_list.push_back(std::make_shared<DescriptorBase>(descriptor.uuid));
@@ -133,122 +132,125 @@ SharedPtrVector<ServiceBase> PeripheralDongl::advertised_services() {
133
132
 
134
133
  std::map<uint16_t, ByteArray> PeripheralDongl::manufacturer_data() { return _manufacturer_data; }
135
134
 
136
- ByteArray PeripheralDongl::read(BluetoothUUID const& service, BluetoothUUID const& characteristic) {
137
- auto& char_def = _characteristic_definition(service, characteristic);
135
+ ByteArray PeripheralDongl::read(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid) {
136
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
138
137
 
139
- if (!char_def.can_read) {
140
- throw Exception::OperationFailed(fmt::format("Characteristic {} is not readable", characteristic));
138
+ if (!characteristic.can_read) {
139
+ throw Exception::OperationFailed(fmt::format("Characteristic {} is not readable", characteristic_uuid));
141
140
  }
142
141
 
143
- simpleble_ReadRsp rsp = _serial_protocol->simpleble_read(_conn_handle, char_def.handle_value);
142
+ simpleble_ReadRsp rsp = _serial_protocol->simpleble_read(_conn_handle, characteristic.handle_value);
144
143
  if (rsp.ret_code != 0) {
145
144
  throw Exception::OperationFailed(
146
- fmt::format("Failed to read characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
145
+ fmt::format("Failed to read characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
147
146
  }
148
147
 
149
148
  return ByteArray(rsp.data.bytes, rsp.data.size);
150
149
  }
151
150
 
152
- void PeripheralDongl::write_request(BluetoothUUID const& service, BluetoothUUID const& characteristic,
151
+ void PeripheralDongl::write_request(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
153
152
  ByteArray const& data) {
154
- auto& char_def = _characteristic_definition(service, characteristic);
153
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
155
154
 
156
- if (!char_def.can_write_request) {
157
- throw Exception::OperationFailed(fmt::format("Characteristic {} is not writable", characteristic));
155
+ if (!characteristic.can_write_request) {
156
+ throw Exception::OperationFailed(fmt::format("Characteristic {} is not writable", characteristic_uuid));
158
157
  }
159
158
 
160
- simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, char_def.handle_value,
159
+ simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, characteristic.handle_value,
161
160
  simpleble_WriteOperation_WRITE_REQ, data);
162
161
  if (rsp.ret_code != 0) {
163
162
  throw Exception::OperationFailed(
164
- fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
163
+ fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
165
164
  }
166
165
  }
167
166
 
168
- void PeripheralDongl::write_command(BluetoothUUID const& service, BluetoothUUID const& characteristic,
167
+ void PeripheralDongl::write_command(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
169
168
  ByteArray const& data) {
170
- auto& char_def = _characteristic_definition(service, characteristic);
169
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
171
170
 
172
- if (!char_def.can_write_command) {
173
- throw Exception::OperationFailed(fmt::format("Characteristic {} is not writable", characteristic));
171
+ if (!characteristic.can_write_command) {
172
+ throw Exception::OperationFailed(fmt::format("Characteristic {} is not writable", characteristic_uuid));
174
173
  }
175
174
 
176
- simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, char_def.handle_value,
175
+ simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, characteristic.handle_value,
177
176
  simpleble_WriteOperation_WRITE_CMD, data);
178
177
  if (rsp.ret_code != 0) {
179
178
  throw Exception::OperationFailed(
180
- fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
179
+ fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
181
180
  }
182
181
  }
183
182
 
184
- void PeripheralDongl::notify(BluetoothUUID const& service, BluetoothUUID const& characteristic,
183
+ void PeripheralDongl::notify(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
185
184
  std::function<void(ByteArray payload)> callback) {
186
- auto& char_def = _characteristic_definition(service, characteristic);
185
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
187
186
 
188
- if (!char_def.can_notify) {
189
- throw Exception::OperationFailed(fmt::format("Characteristic {} is not notifyable", characteristic));
187
+ if (!characteristic.can_notify) {
188
+ throw Exception::OperationFailed(fmt::format("Characteristic {} is not notifyable", characteristic_uuid));
190
189
  }
191
190
 
192
- // Find the CCCD for the characteristic
193
- for (auto& descriptor : char_def.descriptors) {
194
- if (descriptor.uuid == "00002902-0000-1000-8000-00805f9b34fb") {
195
- ByteArray data = {0x01, 0x00};
196
- simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, descriptor.handle,
197
- simpleble_WriteOperation_WRITE_REQ, data);
198
- if (rsp.ret_code != 0) {
199
- throw Exception::OperationFailed(
200
- fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
201
- }
202
- }
191
+ if (characteristic.handle_cccd == 0) {
192
+ throw Exception::OperationFailed(fmt::format("Characteristic {} does not have a CCCD", characteristic_uuid));
193
+ }
194
+
195
+ _callbacks_on_value_changed[characteristic.handle_value] = std::move(callback);
196
+
197
+ ByteArray data = {0x01, 0x00};
198
+ simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, characteristic.handle_cccd,
199
+ simpleble_WriteOperation_WRITE_REQ, data);
200
+ if (rsp.ret_code != 0) {
201
+ throw Exception::OperationFailed(
202
+ fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
203
203
  }
204
204
  }
205
205
 
206
- void PeripheralDongl::indicate(BluetoothUUID const& service, BluetoothUUID const& characteristic,
206
+ void PeripheralDongl::indicate(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
207
207
  std::function<void(ByteArray payload)> callback) {
208
- auto& char_def = _characteristic_definition(service, characteristic);
208
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
209
209
 
210
- if (!char_def.can_indicate) {
211
- throw Exception::OperationFailed(fmt::format("Characteristic {} is not indicateable", characteristic));
210
+ if (!characteristic.can_indicate) {
211
+ throw Exception::OperationFailed(fmt::format("Characteristic {} is not indicateable", characteristic_uuid));
212
212
  }
213
213
 
214
- // Find the CCCD for the characteristic
215
- for (auto& descriptor : char_def.descriptors) {
216
- if (descriptor.uuid == "00002902-0000-1000-8000-00805f9b34fb") {
217
- ByteArray data = {0x02, 0x00};
218
- simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, descriptor.handle,
219
- simpleble_WriteOperation_WRITE_REQ, data);
220
- if (rsp.ret_code != 0) {
221
- throw Exception::OperationFailed(
222
- fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
223
- }
224
- }
214
+ if (characteristic.handle_cccd == 0) {
215
+ throw Exception::OperationFailed(fmt::format("Characteristic {} does not have a CCCD", characteristic_uuid));
216
+ }
217
+
218
+ _callbacks_on_value_changed[characteristic.handle_value] = callback;
219
+
220
+ ByteArray data = {0x02, 0x00};
221
+ simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, characteristic.handle_cccd,
222
+ simpleble_WriteOperation_WRITE_REQ, data);
223
+ if (rsp.ret_code != 0) {
224
+ throw Exception::OperationFailed(
225
+ fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
225
226
  }
226
227
  }
227
228
 
228
- void PeripheralDongl::unsubscribe(BluetoothUUID const& service, BluetoothUUID const& characteristic) {
229
- auto& char_def = _characteristic_definition(service, characteristic);
229
+ void PeripheralDongl::unsubscribe(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid) {
230
+ auto& characteristic = _find_characteristic_from_uuid(service_uuid, characteristic_uuid);
230
231
 
231
- // Find the CCCD for the characteristic
232
- for (auto& descriptor : char_def.descriptors) {
233
- if (descriptor.uuid == "00002902-0000-1000-8000-00805f9b34fb") {
234
- ByteArray data = {0x00, 0x00};
235
- simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, descriptor.handle,
236
- simpleble_WriteOperation_WRITE_REQ, data);
237
- if (rsp.ret_code != 0) {
238
- throw Exception::OperationFailed(
239
- fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic, rsp.ret_code));
240
- }
241
- }
232
+ if (characteristic.handle_cccd == 0) {
233
+ throw Exception::OperationFailed(fmt::format("Characteristic {} does not have a CCCD", characteristic_uuid));
234
+ }
235
+
236
+ _callbacks_on_value_changed.erase(characteristic.handle_value);
237
+
238
+ ByteArray data = {0x00, 0x00};
239
+ simpleble_WriteRsp rsp = _serial_protocol->simpleble_write(_conn_handle, characteristic.handle_cccd,
240
+ simpleble_WriteOperation_WRITE_REQ, data);
241
+ if (rsp.ret_code != 0) {
242
+ throw Exception::OperationFailed(
243
+ fmt::format("Failed to write characteristic {} - ret_code: {}", characteristic_uuid, rsp.ret_code));
242
244
  }
243
245
  }
244
246
 
245
- ByteArray PeripheralDongl::read(BluetoothUUID const& service, BluetoothUUID const& characteristic,
246
- BluetoothUUID const& descriptor) {
247
+ ByteArray PeripheralDongl::read(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
248
+ BluetoothUUID const& descriptor_uuid) {
247
249
  return {};
248
250
  }
249
251
 
250
- void PeripheralDongl::write(BluetoothUUID const& service, BluetoothUUID const& characteristic,
251
- BluetoothUUID const& descriptor, ByteArray const& data) {}
252
+ void PeripheralDongl::write(BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid,
253
+ BluetoothUUID const& descriptor_uuid, ByteArray const& data) {}
252
254
 
253
255
  void PeripheralDongl::set_callback_on_connected(std::function<void()> on_connected) {
254
256
  if (on_connected) {
@@ -284,7 +286,7 @@ bool PeripheralDongl::_attempt_connect() {
284
286
  if (_conn_handle != BLE_CONN_HANDLE_INVALID) {
285
287
  auto response = _serial_protocol->simpleble_disconnect(_conn_handle);
286
288
  if (response.ret_code != 0) {
287
- fmt::println("Failed to disconnect during connect attempt: {}", response.ret_code);
289
+ SIMPLEBLE_LOG_ERROR(fmt::format("Failed to disconnect during connect attempt: {}", response.ret_code));
288
290
  }
289
291
 
290
292
  // Wait for the disconnection to be confirmed.
@@ -292,7 +294,6 @@ bool PeripheralDongl::_attempt_connect() {
292
294
  disconnection_cv_.wait_for(lock, 500ms, [this]() { return !is_connected(); });
293
295
  }
294
296
 
295
- fmt::println("Disconnection confirmed");
296
297
  _conn_handle = BLE_CONN_HANDLE_INVALID;
297
298
 
298
299
  auto response = _serial_protocol->simpleble_connect(static_cast<simpleble_BluetoothAddressType>(_address_type),
@@ -311,39 +312,34 @@ bool PeripheralDongl::_attempt_connect() {
311
312
  std::unique_lock<std::mutex> lock(connection_mutex_);
312
313
  connection_cv_.wait_for(lock, 5000ms, [this]() { return _conn_handle != BLE_CONN_HANDLE_INVALID; });
313
314
  if (_conn_handle == BLE_CONN_HANDLE_INVALID) {
314
- // SIMPLEBLE_LOG_ERROR("Timeout while waiting for connection confirmation");
315
- fmt::println("Timeout while waiting for connection confirmation");
315
+ SIMPLEBLE_LOG_ERROR("Timeout while waiting for connection confirmation");
316
316
  return false;
317
317
  }
318
318
  }
319
319
 
320
- fmt::println("Connection confirmed");
321
-
322
320
  // Wait for the attributes to be discovered.
323
321
  {
324
322
  std::unique_lock<std::mutex> lock(attributes_discovered_mutex_);
325
323
  attributes_discovered_cv_.wait_for(
326
324
  lock, 15000ms, [this]() { return !_services.empty() || _conn_handle == BLE_CONN_HANDLE_INVALID; });
327
325
  if (_services.empty()) {
328
- fmt::println("Timeout while waiting for attributes to be discovered");
326
+ SIMPLEBLE_LOG_ERROR("Timeout while waiting for attributes to be discovered");
329
327
  return false;
330
328
  }
331
329
 
332
330
  if (_conn_handle == BLE_CONN_HANDLE_INVALID) {
333
- fmt::println("Connection lost during attribute discovery");
331
+ SIMPLEBLE_LOG_ERROR("Connection lost during attribute discovery");
334
332
  return false;
335
333
  }
336
334
  }
337
335
 
338
- fmt::println("Attributes discovered. {} services found", _services.size());
339
-
340
336
  // Retrieve any missing 128-bit UUIDs.
341
337
  for (auto& service : _services) {
342
338
  // Fetch the service UUID if missing.
343
339
  if (service.uuid.empty()) {
344
340
  simpleble_ReadRsp rsp = _serial_protocol->simpleble_read(_conn_handle, service.start_handle);
345
341
  if (rsp.ret_code != 0) {
346
- fmt::println("Failed to read UUID for service {} - ret_code: {}", service.start_handle, rsp.ret_code);
342
+ SIMPLEBLE_LOG_ERROR(fmt::format("Failed to read UUID for service {} - ret_code: {}", service.start_handle, rsp.ret_code));
347
343
  continue;
348
344
  }
349
345
 
@@ -356,7 +352,7 @@ bool PeripheralDongl::_attempt_connect() {
356
352
  }
357
353
  service.uuid = _uuid_from_uuid128(uuid_128);
358
354
  } else {
359
- fmt::println("Unexpected UUID size: {}", rsp.data.size);
355
+ SIMPLEBLE_LOG_ERROR(fmt::format("Unexpected UUID size: {}", rsp.data.size));
360
356
  continue;
361
357
  }
362
358
  }
@@ -366,8 +362,8 @@ bool PeripheralDongl::_attempt_connect() {
366
362
  if (characteristic.uuid.empty()) {
367
363
  simpleble_ReadRsp rsp = _serial_protocol->simpleble_read(_conn_handle, characteristic.handle_decl);
368
364
  if (rsp.ret_code != 0) {
369
- fmt::println("Failed to read UUID for characteristic {} - ret_code: {}", characteristic.handle_decl,
370
- rsp.ret_code);
365
+ SIMPLEBLE_LOG_ERROR(fmt::format("Failed to read UUID for characteristic {} - ret_code: {}", characteristic.handle_decl,
366
+ rsp.ret_code));
371
367
  continue;
372
368
  }
373
369
 
@@ -383,20 +379,15 @@ bool PeripheralDongl::_attempt_connect() {
383
379
  }
384
380
  }
385
381
  }
386
-
387
- fmt::println("Service discovery complete");
388
-
389
382
  return true;
390
383
  }
391
384
 
392
385
  void PeripheralDongl::notify_connected(uint16_t conn_handle) {
393
- fmt::print("PeripheralDongl::notify_connected: {}\n", conn_handle);
394
386
  _conn_handle = conn_handle;
395
387
  connection_cv_.notify_all();
396
388
  }
397
389
 
398
390
  void PeripheralDongl::notify_disconnected() {
399
- fmt::print("PeripheralDongl::notify_disconnected: {}\n", _conn_handle);
400
391
  _conn_handle = BLE_CONN_HANDLE_INVALID;
401
392
  disconnection_cv_.notify_all();
402
393
  attributes_discovered_cv_.notify_all();
@@ -406,10 +397,6 @@ void PeripheralDongl::notify_disconnected() {
406
397
  }
407
398
 
408
399
  void PeripheralDongl::notify_service_discovered(simpleble_ServiceDiscoveredEvt const& evt) {
409
- fmt::print(
410
- "PeripheralDongl::notify_service_discovered: conn_handle={}, uuid16={:04x}, start_handle={}, end_handle={}\n",
411
- evt.conn_handle, evt.uuid16.uuid, evt.start_handle, evt.end_handle);
412
-
413
400
  BluetoothUUID uuid;
414
401
  if (evt.has_uuid16) {
415
402
  uuid = _uuid_from_uuid16(evt.uuid16.uuid);
@@ -423,13 +410,7 @@ void PeripheralDongl::notify_service_discovered(simpleble_ServiceDiscoveredEvt c
423
410
  }
424
411
 
425
412
  void PeripheralDongl::notify_characteristic_discovered(simpleble_CharacteristicDiscoveredEvt const& evt) {
426
- fmt::print(
427
- "PeripheralDongl::notify_characteristic_discovered: conn_handle={}, uuid16={:04x}, handle_decl={}, "
428
- "handle_value={}, can_read={}, can_write_wo_resp={}, can_write_cmd={}, can_notify={}, can_indicate={}\n",
429
- evt.conn_handle, evt.uuid16.uuid, evt.handle_decl, evt.handle_value, evt.props.read, evt.props.write_wo_resp,
430
- evt.props.write, evt.props.notify, evt.props.indicate);
431
-
432
- auto& service = _service_definition(evt.handle_decl);
413
+ auto& service = _find_service_from_handle(evt.handle_decl);
433
414
 
434
415
  BluetoothUUID uuid;
435
416
  if (evt.has_uuid16) {
@@ -440,6 +421,7 @@ void PeripheralDongl::notify_characteristic_discovered(simpleble_CharacteristicD
440
421
  uuid,
441
422
  evt.handle_decl,
442
423
  evt.handle_value,
424
+ 0,
443
425
  evt.props.read,
444
426
  evt.props.write,
445
427
  evt.props.write_wo_resp,
@@ -449,7 +431,7 @@ void PeripheralDongl::notify_characteristic_discovered(simpleble_CharacteristicD
449
431
  }
450
432
 
451
433
  void PeripheralDongl::notify_descriptor_discovered(simpleble_DescriptorDiscoveredEvt const& evt) {
452
- auto& service = _service_definition(evt.handle);
434
+ auto& service = _find_service_from_handle(evt.handle);
453
435
 
454
436
  for (auto& characteristic : service.characteristics) {
455
437
  // If the descriptor matches the characteristic declaration handle or value handle, we can ignore it.
@@ -459,27 +441,32 @@ void PeripheralDongl::notify_descriptor_discovered(simpleble_DescriptorDiscovere
459
441
  }
460
442
 
461
443
  // At this point we know we have a real descriptor that we shouldn't ignore.
462
- fmt::print("PeripheralDongl::notify_descriptor_discovered: conn_handle={}, uuid16={:04x}, handle={}\n",
463
- evt.conn_handle, evt.uuid16.uuid, evt.handle);
464
-
465
- // For the given service handle, loop the characteristics backwards and select the first characteristic where the
466
- // handle_value is less than the descriptor handle.
467
- for (auto it = service.characteristics.rbegin(); it != service.characteristics.rend(); ++it) {
468
- if (it->handle_value < evt.handle) {
469
- it->descriptors.emplace_back(DescriptorDefinition{
470
- _uuid_from_uuid16(evt.uuid16.uuid),
471
- evt.handle,
472
- });
473
- break;
474
- }
444
+
445
+ auto& characteristic = _find_characteristic_from_handle(evt.handle);
446
+ characteristic.descriptors.emplace_back(DescriptorDefinition{
447
+ _uuid_from_uuid16(evt.uuid16.uuid),
448
+ evt.handle,
449
+ });
450
+
451
+ // If the descriptor is a client characteristic configuration descriptor (CCCD),
452
+ // save that handle number for the characteristic.
453
+ if (evt.uuid16.uuid == 0x2902) {
454
+ characteristic.handle_cccd = evt.handle;
475
455
  }
476
456
  }
477
457
 
478
458
  void PeripheralDongl::notify_attribute_discovery_complete() {
479
- fmt::print("PeripheralDongl::notify_attribute_discovery_complete: {}\n", _conn_handle);
480
459
  attributes_discovered_cv_.notify_all();
481
460
  }
482
461
 
462
+ void PeripheralDongl::notify_value_changed(simpleble_ValueChangedEvt const& evt) {
463
+ ByteArray data(evt.data.bytes, evt.data.bytes + evt.data.size);
464
+ std::function<void(ByteArray)> callback = _callbacks_on_value_changed[evt.handle];
465
+ if (callback) {
466
+ callback(data);
467
+ }
468
+ }
469
+
483
470
  BluetoothUUID PeripheralDongl::_uuid_from_uuid16(uint16_t uuid16) {
484
471
  return BluetoothUUID(fmt::format("0000{:04X}-0000-1000-8000-00805F9B34FB", uuid16));
485
472
  }
@@ -531,22 +518,37 @@ BluetoothUUID PeripheralDongl::_uuid_from_proto(simpleble_UUID const& uuid) {
531
518
  }
532
519
  }
533
520
 
534
- fmt::print("Unknown UUID type: {}\n", uuid.which_uuid);
535
521
  // Should not be reached
536
- return BluetoothUUID();
522
+ throw std::runtime_error(fmt::format("Unknown UUID type: {}", uuid.which_uuid));
537
523
  }
538
524
 
539
- PeripheralDongl::ServiceDefinition& PeripheralDongl::_service_definition(uint16_t handle) {
525
+ PeripheralDongl::ServiceDefinition& PeripheralDongl::_find_service_from_handle(uint16_t handle) {
540
526
  for (auto& service : _services) {
541
527
  if (service.start_handle <= handle && service.end_handle >= handle) {
542
528
  return service;
543
529
  }
544
530
  }
545
531
 
546
- throw std::runtime_error("Service not found");
532
+ throw std::runtime_error(fmt::format("Service not found for handle {}", handle));
533
+ }
534
+
535
+ PeripheralDongl::CharacteristicDefinition& PeripheralDongl::_find_characteristic_from_handle(uint16_t handle) {
536
+ for (auto& service : _services) {
537
+ if (service.start_handle <= handle && service.end_handle >= handle) {
538
+ // For the given service handle, loop the characteristics backwards and select the first characteristic
539
+ // where the handle_value is less than the descriptor handle.
540
+ for (auto it = service.characteristics.rbegin(); it != service.characteristics.rend(); ++it) {
541
+ if (it->handle_value < handle) {
542
+ return *it;
543
+ }
544
+ }
545
+ }
546
+ }
547
+
548
+ throw std::runtime_error(fmt::format("Characteristic not found for handle {}", handle));
547
549
  }
548
550
 
549
- PeripheralDongl::CharacteristicDefinition& PeripheralDongl::_characteristic_definition(
551
+ PeripheralDongl::CharacteristicDefinition& PeripheralDongl::_find_characteristic_from_uuid(
550
552
  BluetoothUUID const& service_uuid, BluetoothUUID const& characteristic_uuid) {
551
553
  for (auto& service : _services) {
552
554
  if (service.uuid == service_uuid) {
@@ -558,5 +560,5 @@ PeripheralDongl::CharacteristicDefinition& PeripheralDongl::_characteristic_defi
558
560
  }
559
561
  }
560
562
 
561
- throw std::runtime_error("Characteristic not found");
563
+ throw std::runtime_error(fmt::format("Characteristic {} not found", characteristic_uuid));
562
564
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include <TaskRunner.hpp>
9
9
  #include <kvn_safe_callback.hpp>
10
+ #include <kvn_safe_map.hpp>
10
11
 
11
12
  #include <atomic>
12
13
  #include <map>
@@ -61,6 +62,7 @@ class PeripheralDongl : public PeripheralBase {
61
62
  virtual void set_callback_on_disconnected(std::function<void()> on_disconnected) override;
62
63
 
63
64
  // Internal methods not exposed to the user.
65
+ // TODO: Make these private and the adapter a friend.
64
66
  uint16_t conn_handle() const;
65
67
  void update_advertising_data(advertising_data_t advertising_data);
66
68
  void notify_connected(uint16_t conn_handle);
@@ -69,6 +71,7 @@ class PeripheralDongl : public PeripheralBase {
69
71
  void notify_characteristic_discovered(simpleble_CharacteristicDiscoveredEvt const& characteristic_discovered_evt);
70
72
  void notify_descriptor_discovered(simpleble_DescriptorDiscoveredEvt const& descriptor_discovered_evt);
71
73
  void notify_attribute_discovery_complete();
74
+ void notify_value_changed(simpleble_ValueChangedEvt const& value_changed_evt);
72
75
 
73
76
  const uint16_t BLE_CONN_HANDLE_INVALID = 0xFFFF;
74
77
  const uint16_t BLE_CONN_HANDLE_PENDING = 0xFFFE;
@@ -83,6 +86,7 @@ class PeripheralDongl : public PeripheralBase {
83
86
  BluetoothUUID uuid;
84
87
  uint16_t handle_decl;
85
88
  uint16_t handle_value;
89
+ uint16_t handle_cccd = 0;
86
90
  bool can_read;
87
91
  bool can_write_request;
88
92
  bool can_write_command;
@@ -105,8 +109,10 @@ class PeripheralDongl : public PeripheralBase {
105
109
  BluetoothUUID _uuid_from_uuid128(const uint8_t uuid[16]);
106
110
  BluetoothUUID _uuid_from_proto(simpleble_UUID const& uuid);
107
111
 
108
- ServiceDefinition& _service_definition(uint16_t handle);
109
- CharacteristicDefinition& _characteristic_definition(BluetoothUUID const& service, BluetoothUUID const& characteristic);
112
+ ServiceDefinition& _find_service_from_handle(uint16_t handle);
113
+ CharacteristicDefinition& _find_characteristic_from_handle(uint16_t handle);
114
+ CharacteristicDefinition& _find_characteristic_from_uuid(BluetoothUUID const& service,
115
+ BluetoothUUID const& characteristic);
110
116
 
111
117
  uint16_t _conn_handle = BLE_CONN_HANDLE_INVALID;
112
118
  std::string _identifier;
@@ -131,6 +137,7 @@ class PeripheralDongl : public PeripheralBase {
131
137
 
132
138
  kvn::safe_callback<void()> _callback_on_connected;
133
139
  kvn::safe_callback<void()> _callback_on_disconnected;
140
+ kvn::safe_map<uint16_t, std::function<void(ByteArray payload)>> _callbacks_on_value_changed;
134
141
  };
135
142
 
136
143
  } // namespace SimpleBLE
@@ -6,7 +6,6 @@
6
6
  #include "nanopb/pb.h"
7
7
  #include "protocol/basic.pb.h"
8
8
  #include "protocol/simpleble.pb.h"
9
- #include "protocol/softdevice.pb.h"
10
9
 
11
10
  #if PB_PROTO_HEADER_VERSION != 40
12
11
  #error Regenerate this file with the current version of nanopb generator.
@@ -19,14 +18,12 @@ typedef struct _dongl_Response {
19
18
  union {
20
19
  basic_Response basic;
21
20
  simpleble_Response simpleble;
22
- sd_Response softdevice;
23
21
  } rsp;
24
22
  } dongl_Response;
25
23
 
26
24
  typedef struct _dongl_Event {
27
25
  pb_size_t which_evt;
28
26
  union {
29
- sd_Event softdevice;
30
27
  simpleble_Event simpleble;
31
28
  } evt;
32
29
  } dongl_Event;
@@ -46,38 +43,32 @@ extern "C" {
46
43
 
47
44
  /* Initializer values for message structs */
48
45
  #define dongl_Response_init_default {0, {basic_Response_init_default}}
49
- #define dongl_Event_init_default {0, {sd_Event_init_default}}
46
+ #define dongl_Event_init_default {0, {simpleble_Event_init_default}}
50
47
  #define dongl_D2H_init_default {0, {dongl_Response_init_default}}
51
48
  #define dongl_Response_init_zero {0, {basic_Response_init_zero}}
52
- #define dongl_Event_init_zero {0, {sd_Event_init_zero}}
49
+ #define dongl_Event_init_zero {0, {simpleble_Event_init_zero}}
53
50
  #define dongl_D2H_init_zero {0, {dongl_Response_init_zero}}
54
51
 
55
52
  /* Field tags (for use in manual encoding/decoding) */
56
53
  #define dongl_Response_basic_tag 1
57
54
  #define dongl_Response_simpleble_tag 2
58
- #define dongl_Response_softdevice_tag 3
59
- #define dongl_Event_softdevice_tag 2
60
- #define dongl_Event_simpleble_tag 3
55
+ #define dongl_Event_simpleble_tag 2
61
56
  #define dongl_D2H_rsp_tag 1
62
57
  #define dongl_D2H_evt_tag 2
63
58
 
64
59
  /* Struct field encoding specification for nanopb */
65
60
  #define dongl_Response_FIELDLIST(X, a) \
66
61
  X(a, STATIC, ONEOF, MESSAGE, (rsp,basic,rsp.basic), 1) \
67
- X(a, STATIC, ONEOF, MESSAGE, (rsp,simpleble,rsp.simpleble), 2) \
68
- X(a, STATIC, ONEOF, MESSAGE, (rsp,softdevice,rsp.softdevice), 3)
62
+ X(a, STATIC, ONEOF, MESSAGE, (rsp,simpleble,rsp.simpleble), 2)
69
63
  #define dongl_Response_CALLBACK NULL
70
64
  #define dongl_Response_DEFAULT NULL
71
65
  #define dongl_Response_rsp_basic_MSGTYPE basic_Response
72
66
  #define dongl_Response_rsp_simpleble_MSGTYPE simpleble_Response
73
- #define dongl_Response_rsp_softdevice_MSGTYPE sd_Response
74
67
 
75
68
  #define dongl_Event_FIELDLIST(X, a) \
76
- X(a, STATIC, ONEOF, MESSAGE, (evt,softdevice,evt.softdevice), 2) \
77
- X(a, STATIC, ONEOF, MESSAGE, (evt,simpleble,evt.simpleble), 3)
69
+ X(a, STATIC, ONEOF, MESSAGE, (evt,simpleble,evt.simpleble), 2)
78
70
  #define dongl_Event_CALLBACK NULL
79
71
  #define dongl_Event_DEFAULT NULL
80
- #define dongl_Event_evt_softdevice_MSGTYPE sd_Event
81
72
  #define dongl_Event_evt_simpleble_MSGTYPE simpleble_Event
82
73
 
83
74
  #define dongl_D2H_FIELDLIST(X, a) \
@@ -98,18 +89,10 @@ extern const pb_msgdesc_t dongl_D2H_msg;
98
89
  #define dongl_D2H_fields &dongl_D2H_msg
99
90
 
100
91
  /* Maximum encoded size of messages (where known) */
101
- #if defined(sd_Event_size)
102
- union dongl_Event_evt_size_union {char f2[(6 + sd_Event_size)]; char f0[531];};
103
- #endif
104
- #if defined(sd_Event_size)
105
- union dongl_D2H_type_size_union {char f2[(6 + sizeof(union dongl_Event_evt_size_union))]; char f0[549];};
106
- #endif
107
- #define DONGL_D2H_PB_H_MAX_SIZE dongl_Response_size
108
- #define dongl_Response_size 546
109
- #if defined(sd_Event_size)
110
- #define dongl_D2H_size (0 + sizeof(union dongl_D2H_type_size_union))
111
- #define dongl_Event_size (0 + sizeof(union dongl_Event_evt_size_union))
112
- #endif
92
+ #define DONGL_D2H_PB_H_MAX_SIZE dongl_D2H_size
93
+ #define dongl_D2H_size 534
94
+ #define dongl_Event_size 531
95
+ #define dongl_Response_size 531
113
96
 
114
97
  #ifdef __cplusplus
115
98
  } /* extern "C" */
@@ -6,7 +6,6 @@
6
6
  #include "nanopb/pb.h"
7
7
  #include "protocol/basic.pb.h"
8
8
  #include "protocol/simpleble.pb.h"
9
- #include "protocol/softdevice.pb.h"
10
9
 
11
10
  #if PB_PROTO_HEADER_VERSION != 40
12
11
  #error Regenerate this file with the current version of nanopb generator.
@@ -19,7 +18,6 @@ typedef struct _dongl_Command {
19
18
  union {
20
19
  basic_Command basic;
21
20
  simpleble_Command simpleble;
22
- sd_Command softdevice;
23
21
  } cmd;
24
22
  } dongl_Command;
25
23
 
@@ -35,18 +33,15 @@ extern "C" {
35
33
  /* Field tags (for use in manual encoding/decoding) */
36
34
  #define dongl_Command_basic_tag 1
37
35
  #define dongl_Command_simpleble_tag 2
38
- #define dongl_Command_softdevice_tag 3
39
36
 
40
37
  /* Struct field encoding specification for nanopb */
41
38
  #define dongl_Command_FIELDLIST(X, a) \
42
39
  X(a, STATIC, ONEOF, MESSAGE, (cmd,basic,cmd.basic), 1) \
43
- X(a, STATIC, ONEOF, MESSAGE, (cmd,simpleble,cmd.simpleble), 2) \
44
- X(a, STATIC, ONEOF, MESSAGE, (cmd,softdevice,cmd.softdevice), 3)
40
+ X(a, STATIC, ONEOF, MESSAGE, (cmd,simpleble,cmd.simpleble), 2)
45
41
  #define dongl_Command_CALLBACK NULL
46
42
  #define dongl_Command_DEFAULT NULL
47
43
  #define dongl_Command_cmd_basic_MSGTYPE basic_Command
48
44
  #define dongl_Command_cmd_simpleble_MSGTYPE simpleble_Command
49
- #define dongl_Command_cmd_softdevice_MSGTYPE sd_Command
50
45
 
51
46
  extern const pb_msgdesc_t dongl_Command_msg;
52
47
 
@@ -54,13 +49,8 @@ extern const pb_msgdesc_t dongl_Command_msg;
54
49
  #define dongl_Command_fields &dongl_Command_msg
55
50
 
56
51
  /* Maximum encoded size of messages (where known) */
57
- #if defined(sd_Command_size)
58
- union dongl_Command_cmd_size_union {char f3[(6 + sd_Command_size)]; char f0[531];};
59
- #endif
60
- #if defined(sd_Command_size)
61
52
  #define DONGL_H2D_PB_H_MAX_SIZE dongl_Command_size
62
- #define dongl_Command_size (0 + sizeof(union dongl_Command_cmd_size_union))
63
- #endif
53
+ #define dongl_Command_size 531
64
54
 
65
55
  #ifdef __cplusplus
66
56
  } /* extern "C" */