@stoprocent/noble 1.19.0 → 2.0.0

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 (97) hide show
  1. package/README.md +393 -650
  2. package/examples/advertisement-discovery.js +57 -48
  3. package/examples/connect-address.js +59 -34
  4. package/examples/echo.js +59 -69
  5. package/examples/enter-exit.js +55 -49
  6. package/examples/multiple-bindings.js +53 -0
  7. package/examples/peripheral-explorer-async.js +39 -21
  8. package/examples/peripheral-explorer.ts +52 -0
  9. package/index.d.ts +249 -209
  10. package/index.js +4 -1
  11. package/jest.config.js +4 -0
  12. package/lib/characteristic.js +153 -127
  13. package/lib/{win/src/callbacks.h → common/include/Emit.h} +17 -14
  14. package/lib/common/include/Peripheral.h +31 -0
  15. package/lib/common/include/ThreadSafeCallback.h +95 -0
  16. package/lib/{win/src/callbacks.cc → common/src/Emit.cc} +111 -68
  17. package/lib/descriptor.js +57 -54
  18. package/lib/hci-socket/acl-stream.js +2 -4
  19. package/lib/hci-socket/bindings.js +96 -73
  20. package/lib/hci-socket/gap.js +2 -3
  21. package/lib/hci-socket/gatt.js +2 -5
  22. package/lib/hci-socket/hci.js +19 -7
  23. package/lib/hci-socket/signaling.js +2 -3
  24. package/lib/hci-socket/smp.js +2 -3
  25. package/lib/hci-socket/vs.js +1 -0
  26. package/lib/mac/binding.gyp +5 -7
  27. package/lib/mac/bindings.js +1 -3
  28. package/lib/mac/src/ble_manager.h +1 -8
  29. package/lib/mac/src/ble_manager.mm +87 -44
  30. package/lib/mac/src/napi_objc.h +1 -0
  31. package/lib/mac/src/napi_objc.mm +0 -6
  32. package/lib/mac/src/noble_mac.h +5 -3
  33. package/lib/mac/src/noble_mac.mm +99 -57
  34. package/lib/mac/src/objc_cpp.h +3 -2
  35. package/lib/mac/src/objc_cpp.mm +0 -6
  36. package/lib/noble.js +579 -488
  37. package/lib/peripheral.js +171 -174
  38. package/lib/resolve-bindings.js +37 -30
  39. package/lib/service.js +58 -55
  40. package/lib/win/binding.gyp +4 -11
  41. package/lib/win/bindings.js +1 -3
  42. package/lib/win/src/ble_manager.cc +291 -166
  43. package/lib/win/src/ble_manager.h +11 -13
  44. package/lib/win/src/napi_winrt.cc +1 -7
  45. package/lib/win/src/napi_winrt.h +1 -1
  46. package/lib/win/src/noble_winrt.cc +88 -61
  47. package/lib/win/src/noble_winrt.h +5 -3
  48. package/lib/win/src/notify_map.cc +0 -7
  49. package/lib/win/src/notify_map.h +1 -8
  50. package/lib/win/src/peripheral_winrt.cc +29 -11
  51. package/lib/win/src/peripheral_winrt.h +1 -1
  52. package/lib/win/src/radio_watcher.cc +79 -69
  53. package/lib/win/src/radio_watcher.h +30 -11
  54. package/lib/win/src/winrt_cpp.cc +1 -1
  55. package/lib/win/src/winrt_cpp.h +3 -0
  56. package/package.json +14 -17
  57. package/prebuilds/darwin-x64+arm64/@stoprocent+noble.node +0 -0
  58. package/prebuilds/win32-ia32/@stoprocent+noble.node +0 -0
  59. package/prebuilds/win32-x64/@stoprocent+noble.node +0 -0
  60. package/test/lib/characteristic.test.js +202 -322
  61. package/test/lib/descriptor.test.js +62 -95
  62. package/test/lib/hci-socket/acl-stream.test.js +112 -108
  63. package/test/lib/hci-socket/bindings.test.js +576 -365
  64. package/test/lib/hci-socket/hci.test.js +442 -473
  65. package/test/lib/hci-socket/signaling.test.js +45 -48
  66. package/test/lib/hci-socket/smp.test.js +144 -142
  67. package/test/lib/hci-socket/vs.test.js +193 -18
  68. package/test/lib/peripheral.test.js +492 -322
  69. package/test/lib/resolve-bindings.test.js +207 -82
  70. package/test/lib/service.test.js +79 -88
  71. package/test/noble.test.js +381 -1085
  72. package/.editorconfig +0 -11
  73. package/.nycrc.json +0 -4
  74. package/codecov.yml +0 -5
  75. package/examples/cache-gatt-discovery.js +0 -198
  76. package/examples/cache-gatt-reconnect.js +0 -164
  77. package/examples/ext-advertisement-discovery.js +0 -65
  78. package/examples/peripheral-explorer.js +0 -225
  79. package/examples/pizza/central.js +0 -194
  80. package/examples/pizza/pizza.js +0 -60
  81. package/examples/test/test.custom.js +0 -131
  82. package/examples/uart-bind-params.js +0 -28
  83. package/lib/distributed/bindings.js +0 -326
  84. package/lib/mac/src/callbacks.cc +0 -222
  85. package/lib/mac/src/callbacks.h +0 -84
  86. package/lib/mac/src/peripheral.h +0 -23
  87. package/lib/resolve-bindings-web.js +0 -9
  88. package/lib/webbluetooth/bindings.js +0 -368
  89. package/lib/websocket/bindings.js +0 -321
  90. package/lib/win/src/peripheral.h +0 -23
  91. package/test/lib/distributed/bindings.test.js +0 -918
  92. package/test/lib/webbluetooth/bindings.test.js +0 -190
  93. package/test/lib/websocket/bindings.test.js +0 -456
  94. package/test/mocha.setup.js +0 -0
  95. package/with-bindings.js +0 -5
  96. package/with-custom-binding.js +0 -6
  97. package/ws-slave.js +0 -404
@@ -1,21 +1,22 @@
1
- //
2
- // ble_manager.cc
3
- // noble-winrt-native
4
- //
5
- // Created by Georg Vienna on 03.09.18.
6
- //
7
-
8
1
  #include "ble_manager.h"
9
2
  #include "winrt_cpp.h"
10
3
 
11
4
  #include <winrt/Windows.Foundation.Collections.h>
12
5
  #include <winrt/Windows.Storage.Streams.h>
6
+ #include <winrt/Windows.Security.Cryptography.h>
7
+ #include <winrt/Windows.Devices.Bluetooth.h>
8
+
9
+
13
10
  using winrt::Windows::Devices::Bluetooth::BluetoothCacheMode;
14
11
  using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
15
12
  using winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
13
+ using winrt::Windows::Devices::Bluetooth::BluetoothUuidHelper;
16
14
  using winrt::Windows::Storage::Streams::DataReader;
17
15
  using winrt::Windows::Storage::Streams::DataWriter;
18
16
  using winrt::Windows::Storage::Streams::IBuffer;
17
+ using winrt::Windows::Storage::Streams::ByteOrder;
18
+ using winrt::Windows::Security::Cryptography::CryptographicBuffer;
19
+ using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementBytePattern;
19
20
 
20
21
  template <typename T> auto inFilter(std::vector<T> filter, T object)
21
22
  {
@@ -45,18 +46,57 @@ template <typename O, typename M, class... Types> auto bind2(O* object, M method
45
46
  } \
46
47
  BluetoothLEDevice& _device = *peripheral.device;
47
48
 
48
- #define CHECK_RESULT(_result) \
49
- if (!_result) \
50
- { \
51
- LOGE("result is null"); \
52
- return; \
53
- } \
54
- auto _commStatus = _result.Status(); \
55
- if (_commStatus != GattCommunicationStatus::Success) \
56
- { \
57
- LOGE("communication status: %d", _commStatus); \
58
- return; \
59
- }
49
+ std::string gattStatusToString(GattCommunicationStatus status) {
50
+ switch (status) {
51
+ case GattCommunicationStatus::Success:
52
+ return "Success";
53
+ case GattCommunicationStatus::Unreachable:
54
+ return "Device is unreachable";
55
+ case GattCommunicationStatus::ProtocolError:
56
+ return "Protocol error";
57
+ case GattCommunicationStatus::AccessDenied:
58
+ return "Access denied";
59
+ default:
60
+ return "Unknown error (" + std::to_string(static_cast<int>(status)) + ")";
61
+ }
62
+ }
63
+
64
+ std::string asyncStatusToString(AsyncStatus status) {
65
+ switch (status) {
66
+ case AsyncStatus::Completed:
67
+ return "Completed";
68
+ case AsyncStatus::Started:
69
+ return "Operation still in progress";
70
+ case AsyncStatus::Canceled:
71
+ return "Operation was canceled";
72
+ case AsyncStatus::Error:
73
+ return "Operation failed with error";
74
+ default:
75
+ return "Unknown status (" + std::to_string(static_cast<int>(status)) + ")";
76
+ }
77
+ }
78
+
79
+ #define CHECK_STATUS_AND_RESULT(_status, _result, _error_emit_func) \
80
+ do \
81
+ { \
82
+ if ((_status) != AsyncStatus::Completed) \
83
+ { \
84
+ _error_emit_func(asyncStatusToString(_status)); \
85
+ return; \
86
+ } \
87
+ if (!(_result)) \
88
+ { \
89
+ _error_emit_func("Operation result is null"); \
90
+ return; \
91
+ } \
92
+ auto _commStatus = (_result).Status(); \
93
+ if ((_commStatus) != GattCommunicationStatus::Success) \
94
+ { \
95
+ _error_emit_func(gattStatusToString(_commStatus)); \
96
+ return; \
97
+ } \
98
+ } while (0)
99
+
60
100
 
61
101
  #define FOR(object, vector) \
62
102
  auto _vector = vector; \
@@ -68,11 +108,31 @@ template <typename O, typename M, class... Types> auto bind2(O* object, M method
68
108
  else \
69
109
  for (auto&& object : _vector)
70
110
 
111
+ struct ServiceDataTypeInfo {
112
+ uint8_t dataType;
113
+ std::function<winrt::guid(DataReader&)> uuidConverter;
114
+ };
115
+
116
+ const std::vector<ServiceDataTypeInfo> serviceDataTypes = {
117
+ {
118
+ BluetoothLEAdvertisementDataTypes::ServiceData16BitUuids(),
119
+ [](DataReader& reader) { return BluetoothUuidHelper::FromShortId(reader.ReadUInt16()); }
120
+ },
121
+ {
122
+ BluetoothLEAdvertisementDataTypes::ServiceData32BitUuids(),
123
+ [](DataReader& reader) { return BluetoothUuidHelper::FromShortId(reader.ReadUInt32()); }
124
+ },
125
+ {
126
+ BluetoothLEAdvertisementDataTypes::ServiceData128BitUuids(),
127
+ [](DataReader& reader) { return reader.ReadGuid(); }
128
+ }
129
+ };
130
+
71
131
  BLEManager::BLEManager(const Napi::Value& receiver, const Napi::Function& callback)
72
132
  {
73
133
  mRadioState = AdapterState::Initial;
74
134
  mEmit.Wrap(receiver, callback);
75
- auto onRadio = std::bind(&BLEManager::OnRadio, this, std::placeholders::_1);
135
+ auto onRadio = std::bind(&BLEManager::OnRadio, this, std::placeholders::_1, std::placeholders::_2);
76
136
  mWatcher.Start(onRadio);
77
137
  mAdvertismentWatcher.ScanningMode(BluetoothLEScanningMode::Active);
78
138
  auto onReceived = bind2(this, &BLEManager::OnScanResult);
@@ -81,27 +141,7 @@ BLEManager::BLEManager(const Napi::Value& receiver, const Napi::Function& callba
81
141
  mStoppedRevoker = mAdvertismentWatcher.Stopped(winrt::auto_revoke, onStopped);
82
142
  }
83
143
 
84
- const char* adapterStateToString(AdapterState state)
85
- {
86
- switch (state)
87
- {
88
- case AdapterState::Unsupported:
89
- return "unsupported";
90
- case AdapterState::On:
91
- return "poweredOn";
92
- break;
93
- case AdapterState::Off:
94
- return "poweredOff";
95
- break;
96
- case AdapterState::Disabled:
97
- return "poweredOff";
98
- break;
99
- default:
100
- return "unknown";
101
- }
102
- }
103
-
104
- void BLEManager::OnRadio(Radio& radio)
144
+ void BLEManager::OnRadio(Radio& radio, const AdapterCapabilities& capabilities)
105
145
  {
106
146
  auto state = AdapterState::Unsupported;
107
147
  if (radio)
@@ -113,21 +153,29 @@ void BLEManager::OnRadio(Radio& radio)
113
153
  mRadioState = state;
114
154
  mEmit.RadioState(adapterStateToString(state));
115
155
  }
156
+ if (capabilities.bluetoothAddress > 0)
157
+ {
158
+ mEmit.Address(formatBluetoothAddress(capabilities.bluetoothAddress));
159
+ }
116
160
  }
117
161
 
118
162
  void BLEManager::Scan(const std::vector<winrt::guid>& serviceUUIDs, bool allowDuplicates)
119
163
  {
120
164
  mAdvertismentMap.clear();
121
165
  mAllowDuplicates = allowDuplicates;
166
+ mScanServiceUUIDs = serviceUUIDs;
167
+
122
168
  BluetoothLEAdvertisementFilter filter = BluetoothLEAdvertisementFilter();
123
169
  BluetoothLEAdvertisement advertisment = BluetoothLEAdvertisement();
124
170
  auto services = advertisment.ServiceUuids();
125
- for (auto uuid : serviceUUIDs)
126
- {
127
- services.Append(uuid);
128
- }
129
- filter.Advertisement(advertisment);
171
+ // This was replaced by the filtering after the scan result
172
+ // for (auto uuid : serviceUUIDs)
173
+ // {
174
+ // services.Append(uuid);
175
+ // }
176
+ // filter.Advertisement(advertisment);
130
177
  mAdvertismentWatcher.AdvertisementFilter(filter);
178
+
131
179
  mAdvertismentWatcher.Start();
132
180
  mEmit.ScanState(true);
133
181
  }
@@ -139,7 +187,40 @@ void BLEManager::OnScanResult(BluetoothLEAdvertisementWatcher watcher,
139
187
  std::string uuid = formatBluetoothUuid(bluetoothAddress);
140
188
  int16_t rssi = args.RawSignalStrengthInDBm();
141
189
  auto advertismentType = args.AdvertisementType();
190
+ auto advertisment = args.Advertisement();
191
+
192
+ if (!mScanServiceUUIDs.empty()) {
193
+ auto found = false;
194
+ std::vector<winrt::guid> serviceUUIDs;
195
+
196
+ for (const auto& typeInfo : serviceDataTypes) {
197
+ auto sections = advertisment.GetSectionsByType(typeInfo.dataType);
198
+ for (auto section : sections) {
199
+ auto reader = DataReader::FromBuffer(section.Data());
200
+ reader.ByteOrder(ByteOrder::LittleEndian);
201
+ auto uuid = typeInfo.uuidConverter(reader);
202
+ if (inFilter(mScanServiceUUIDs, uuid)) {
203
+ found = true;
204
+ break;
205
+ }
206
+ }
207
+ if (found) break;
208
+ }
209
+
210
+ auto serviceUuids = advertisment.ServiceUuids();
211
+ for (auto uuid : serviceUuids) {
212
+ if (inFilter(mScanServiceUUIDs, uuid)) {
213
+ found = true;
214
+ break;
215
+ }
216
+ }
142
217
 
218
+ if (!found) {
219
+ return;
220
+ }
221
+ }
222
+
223
+
143
224
  if (mDeviceMap.find(uuid) == mDeviceMap.end())
144
225
  {
145
226
  mAdvertismentMap.insert(uuid);
@@ -163,6 +244,12 @@ void BLEManager::OnScanResult(BluetoothLEAdvertisementWatcher watcher,
163
244
  void BLEManager::StopScan()
164
245
  {
165
246
  mAdvertismentWatcher.Stop();
247
+
248
+ auto status = mAdvertismentWatcher.Status();
249
+ if (status == BluetoothLEAdvertisementWatcherStatus::Stopped ||
250
+ status == BluetoothLEAdvertisementWatcherStatus::Aborted) {
251
+ mEmit.ScanState(false);
252
+ }
166
253
  }
167
254
 
168
255
  void BLEManager::OnScanStopped(BluetoothLEAdvertisementWatcher watcher,
@@ -175,9 +262,38 @@ bool BLEManager::Connect(const std::string& uuid)
175
262
  {
176
263
  if (mDeviceMap.find(uuid) == mDeviceMap.end())
177
264
  {
178
- mEmit.Connected(uuid, "device not found");
179
- return false;
265
+ // Convert UUID string to MAC address format
266
+ // Remove any colons if present and convert to uppercase
267
+ std::string cleanUuid = uuid;
268
+ cleanUuid.erase(std::remove(cleanUuid.begin(), cleanUuid.end(), ':'), cleanUuid.end());
269
+
270
+ // Basic validation
271
+ if (cleanUuid.length() != 12) {
272
+ mEmit.Connected(uuid, "invalid device address format");
273
+ return false;
274
+ }
275
+
276
+ try {
277
+ // Convert string to uint64_t bluetooth address
278
+ uint64_t bluetoothAddress = std::stoull(cleanUuid, nullptr, 16);
279
+
280
+ // Create a new peripheral entry as if it was scanned
281
+ auto peripheral = PeripheralWinrt(bluetoothAddress,
282
+ BluetoothLEAdvertisementType::ConnectableUndirected,
283
+ 127, // default RSSI for direct connect
284
+ BluetoothLEAdvertisement()); // empty advertisement
285
+
286
+ // Emit scan event just like during normal scanning
287
+ mEmit.Scan(uuid, 127, peripheral);
288
+
289
+ // Add to device map
290
+ mDeviceMap.emplace(std::make_pair(uuid, std::move(peripheral)));
291
+ } catch (const std::exception& e) {
292
+ mEmit.Connected(uuid, "invalid device address format");
293
+ return false;
294
+ }
180
295
  }
296
+
181
297
  PeripheralWinrt& peripheral = mDeviceMap[uuid];
182
298
  if (!peripheral.device.has_value())
183
299
  {
@@ -230,6 +346,15 @@ bool BLEManager::Disconnect(const std::string& uuid)
230
346
  return true;
231
347
  }
232
348
 
349
+ bool BLEManager::CancelConnect(const std::string& uuid)
350
+ {
351
+ CHECK_DEVICE();
352
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
353
+ peripheral.Disconnect();
354
+ mNotifyMap.Remove(uuid);
355
+ return true;
356
+ }
357
+
233
358
  void BLEManager::OnConnectionStatusChanged(BluetoothLEDevice device,
234
359
  winrt::Windows::Foundation::IInspectable inspectable)
235
360
  {
@@ -274,25 +399,25 @@ void BLEManager::OnServicesDiscovered(IAsyncOperation<GattDeviceServicesResult>
274
399
  AsyncStatus status, const std::string uuid,
275
400
  const std::vector<winrt::guid> serviceUUIDs)
276
401
  {
277
- if (status == AsyncStatus::Completed)
402
+ auto result = asyncOp.GetResults();
403
+ std::vector<std::string> serviceUuids;
404
+
405
+ auto emit = [this, uuid, &serviceUuids](const std::string& err) {
406
+ auto error = err + " while discovering services";
407
+ mEmit.ServicesDiscovered(uuid, serviceUuids, error);
408
+ };
409
+
410
+ CHECK_STATUS_AND_RESULT(status, result, emit);
411
+
412
+ FOR(service, result.Services())
278
413
  {
279
- GattDeviceServicesResult result = asyncOp.GetResults();
280
- CHECK_RESULT(result);
281
- std::vector<std::string> serviceUuids;
282
- FOR(service, result.Services())
414
+ auto id = service.Uuid();
415
+ if (inFilter(serviceUUIDs, id))
283
416
  {
284
- auto id = service.Uuid();
285
- if (inFilter(serviceUUIDs, id))
286
- {
287
- serviceUuids.push_back(toStr(id));
288
- }
417
+ serviceUuids.push_back(toStr(id));
289
418
  }
290
- mEmit.ServicesDiscovered(uuid, serviceUuids);
291
- }
292
- else
293
- {
294
- LOGE("status: %d", status);
295
419
  }
420
+ mEmit.ServicesDiscovered(uuid, serviceUuids);
296
421
  }
297
422
 
298
423
  bool BLEManager::DiscoverIncludedServices(const std::string& uuid, const winrt::guid& serviceUuid,
@@ -323,25 +448,25 @@ void BLEManager::OnIncludedServicesDiscovered(IAsyncOperation<GattDeviceServices
323
448
  const std::string serviceId,
324
449
  const std::vector<winrt::guid> serviceUUIDs)
325
450
  {
326
- if (status == AsyncStatus::Completed)
451
+ auto result = asyncOp.GetResults();
452
+ std::vector<std::string> servicesUuids;
453
+
454
+ auto emit = [this, uuid, serviceId, &servicesUuids](const std::string& err) {
455
+ auto error = err + " while discovering included services for service " + serviceId;
456
+ mEmit.IncludedServicesDiscovered(uuid, serviceId, servicesUuids, error);
457
+ };
458
+
459
+ CHECK_STATUS_AND_RESULT(status, result, emit);
460
+
461
+ FOR(service, result.Services())
327
462
  {
328
- auto result = asyncOp.GetResults();
329
- CHECK_RESULT(result);
330
- std::vector<std::string> servicesUuids;
331
- FOR(service, result.Services())
463
+ auto id = service.Uuid();
464
+ if (inFilter(serviceUUIDs, id))
332
465
  {
333
- auto id = service.Uuid();
334
- if (inFilter(serviceUUIDs, id))
335
- {
336
- servicesUuids.push_back(toStr(id));
337
- }
466
+ servicesUuids.push_back(toStr(id));
338
467
  }
339
- mEmit.IncludedServicesDiscovered(uuid, serviceId, servicesUuids);
340
- }
341
- else
342
- {
343
- LOGE("status: %d", status);
344
468
  }
469
+ mEmit.IncludedServicesDiscovered(uuid, serviceId, servicesUuids);
345
470
  }
346
471
 
347
472
  bool BLEManager::DiscoverCharacteristics(const std::string& uuid, const winrt::guid& serviceUuid,
@@ -372,27 +497,26 @@ void BLEManager::OnCharacteristicsDiscovered(IAsyncOperation<GattCharacteristics
372
497
  const std::string serviceId,
373
498
  const std::vector<winrt::guid> characteristicUUIDs)
374
499
  {
375
- if (status == AsyncStatus::Completed)
376
- {
377
- auto result = asyncOp.GetResults();
378
- CHECK_RESULT(result);
379
- std::vector<std::pair<std::string, std::vector<std::string>>> characteristicsUuids;
500
+ auto result = asyncOp.GetResults();
501
+ std::vector<std::pair<std::string, std::vector<std::string>>> characteristicsUuids;
380
502
 
381
- FOR(characteristic, result.Characteristics())
503
+ auto emit = [this, uuid, serviceId, &characteristicsUuids](const std::string& err) {
504
+ auto error = err + " while discovering characteristics for service " + serviceId;
505
+ mEmit.CharacteristicsDiscovered(uuid, serviceId, characteristicsUuids, error);
506
+ };
507
+
508
+ CHECK_STATUS_AND_RESULT(status, result, emit);
509
+
510
+ FOR(characteristic, result.Characteristics())
511
+ {
512
+ auto id = characteristic.Uuid();
513
+ if (inFilter(characteristicUUIDs, id))
382
514
  {
383
- auto id = characteristic.Uuid();
384
- if (inFilter(characteristicUUIDs, id))
385
- {
386
- auto props = characteristic.CharacteristicProperties();
387
- characteristicsUuids.push_back({ toStr(id), toPropertyArray(props) });
388
- }
515
+ auto props = characteristic.CharacteristicProperties();
516
+ characteristicsUuids.push_back({ toStr(id), toPropertyArray(props) });
389
517
  }
390
- mEmit.CharacteristicsDiscovered(uuid, serviceId, characteristicsUuids);
391
- }
392
- else
393
- {
394
- LOGE("status: %d", status);
395
518
  }
519
+ mEmit.CharacteristicsDiscovered(uuid, serviceId, characteristicsUuids);
396
520
  }
397
521
 
398
522
  bool BLEManager::Read(const std::string& uuid, const winrt::guid& serviceUuid,
@@ -424,26 +548,25 @@ void BLEManager::OnRead(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus sta
424
548
  const std::string uuid, const std::string serviceId,
425
549
  const std::string characteristicId)
426
550
  {
427
- if (status == AsyncStatus::Completed)
551
+ auto result = asyncOp.GetResults();
552
+
553
+ auto emit = [this, uuid, serviceId, characteristicId](const std::string& err) {
554
+ auto error = err + " while reading characteristic " + characteristicId;
555
+ mEmit.Read(uuid, serviceId, characteristicId, Data(), false, error);
556
+ };
557
+
558
+ CHECK_STATUS_AND_RESULT(status, result, emit);
559
+
560
+ auto value = result.Value();
561
+ if (value)
428
562
  {
429
- GattReadResult result = asyncOp.GetResults();
430
- CHECK_RESULT(result);
431
- auto value = result.Value();
432
- if (value)
433
- {
434
- auto reader = DataReader::FromBuffer(value);
435
- Data data(reader.UnconsumedBufferLength());
436
- reader.ReadBytes(data);
437
- mEmit.Read(uuid, serviceId, characteristicId, data, false);
438
- }
439
- else
440
- {
441
- LOGE("value is null");
442
- }
563
+ auto reader = DataReader::FromBuffer(value);
564
+ Data data(reader.UnconsumedBufferLength());
565
+ reader.ReadBytes(data);
566
+ mEmit.Read(uuid, serviceId, characteristicId, data, false);
443
567
  }
444
- else
445
- {
446
- LOGE("status: %d", status);
568
+ else {
569
+ mEmit.Read(uuid, serviceId, characteristicId, Data(), false, "value is null");
447
570
  }
448
571
  }
449
572
 
@@ -488,7 +611,8 @@ void BLEManager::OnWrite(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus s
488
611
  }
489
612
  else
490
613
  {
491
- LOGE("status: %d", status);
614
+ std::string error = "status: " + std::to_string((int)status);
615
+ mEmit.Write(uuid, serviceId, characteristicId, error);
492
616
  }
493
617
  }
494
618
 
@@ -584,7 +708,8 @@ void BLEManager::OnNotify(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus
584
708
  }
585
709
  else
586
710
  {
587
- LOGE("status: %d", status);
711
+ std::string error = "status: " + std::to_string((int)status);
712
+ mEmit.Notify(uuid, serviceId, characteristicId, state, error);
588
713
  }
589
714
  }
590
715
 
@@ -630,21 +755,21 @@ void BLEManager::OnDescriptorsDiscovered(IAsyncOperation<GattDescriptorsResult>
630
755
  const std::string serviceId,
631
756
  const std::string characteristicId)
632
757
  {
633
- if (status == AsyncStatus::Completed)
634
- {
635
- auto result = asyncOp.GetResults();
636
- CHECK_RESULT(result);
637
- std::vector<std::string> descriptorUuids;
638
- FOR(descriptor, result.Descriptors())
639
- {
640
- descriptorUuids.push_back(toStr(descriptor.Uuid()));
641
- }
642
- mEmit.DescriptorsDiscovered(uuid, serviceId, characteristicId, descriptorUuids);
643
- }
644
- else
758
+ auto result = asyncOp.GetResults();
759
+ std::vector<std::string> descriptorUuids;
760
+
761
+ auto emit = [this, uuid, serviceId, characteristicId, &descriptorUuids](const std::string& err) {
762
+ auto error = err + " while discovering descriptors for characteristic " + characteristicId;
763
+ mEmit.DescriptorsDiscovered(uuid, serviceId, characteristicId, descriptorUuids, error);
764
+ };
765
+
766
+ CHECK_STATUS_AND_RESULT(status, result, emit);
767
+
768
+ FOR(descriptor, result.Descriptors())
645
769
  {
646
- LOGE("status: %d", status);
770
+ descriptorUuids.push_back(toStr(descriptor.Uuid()));
647
771
  }
772
+ mEmit.DescriptorsDiscovered(uuid, serviceId, characteristicId, descriptorUuids);
648
773
  }
649
774
 
650
775
  bool BLEManager::ReadValue(const std::string& uuid, const winrt::guid& serviceUuid,
@@ -678,26 +803,25 @@ void BLEManager::OnReadValue(IAsyncOperation<GattReadResult> asyncOp, AsyncStatu
678
803
  const std::string uuid, const std::string serviceId,
679
804
  const std::string characteristicId, const std::string descriptorId)
680
805
  {
681
- if (status == AsyncStatus::Completed)
806
+ auto result = asyncOp.GetResults();
807
+
808
+ auto emit = [this, uuid, serviceId, characteristicId, descriptorId](const std::string& err) {
809
+ auto error = err + " while reading value of descriptor " + descriptorId;
810
+ mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, Data(), error);
811
+ };
812
+
813
+ CHECK_STATUS_AND_RESULT(status, result, emit);
814
+
815
+ auto value = result.Value();
816
+ if (value)
682
817
  {
683
- GattReadResult result = asyncOp.GetResults();
684
- CHECK_RESULT(result);
685
- auto value = result.Value();
686
- if (value)
687
- {
688
- auto reader = DataReader::FromBuffer(value);
689
- Data data(reader.UnconsumedBufferLength());
690
- reader.ReadBytes(data);
691
- mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, data);
692
- }
693
- else
694
- {
695
- LOGE("value is null");
696
- }
818
+ auto reader = DataReader::FromBuffer(value);
819
+ Data data(reader.UnconsumedBufferLength());
820
+ reader.ReadBytes(data);
821
+ mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, data);
697
822
  }
698
- else
699
- {
700
- LOGE("status: %d", status);
823
+ else {
824
+ mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, Data(), "value is null");
701
825
  }
702
826
  }
703
827
 
@@ -741,7 +865,8 @@ void BLEManager::OnWriteValue(IAsyncOperation<GattWriteResult> asyncOp, AsyncSta
741
865
  }
742
866
  else
743
867
  {
744
- LOGE("status: %d", status);
868
+ std::string error = "status: " + std::to_string((int)status);
869
+ mEmit.WriteValue(uuid, serviceId, characteristicId, descriptorId, error);
745
870
  }
746
871
  }
747
872
 
@@ -758,26 +883,25 @@ bool BLEManager::ReadHandle(const std::string& uuid, int handle)
758
883
  void BLEManager::OnReadHandle(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
759
884
  const std::string uuid, const int handle)
760
885
  {
761
- if (status == AsyncStatus::Completed)
886
+ auto result = asyncOp.GetResults();
887
+
888
+ auto emit = [this, uuid, handle](const std::string& err) {
889
+ auto error = err + " while reading handle " + std::to_string(handle);
890
+ mEmit.ReadHandle(uuid, handle, Data(), error);
891
+ };
892
+
893
+ CHECK_STATUS_AND_RESULT(status, result, emit);
894
+
895
+ auto value = result.Value();
896
+ if (value)
762
897
  {
763
- GattReadResult result = asyncOp.GetResults();
764
- CHECK_RESULT(result);
765
- auto value = result.Value();
766
- if (value)
767
- {
768
- auto reader = DataReader::FromBuffer(value);
769
- Data data(reader.UnconsumedBufferLength());
770
- reader.ReadBytes(data);
771
- mEmit.ReadHandle(uuid, handle, data);
772
- }
773
- else
774
- {
775
- LOGE("value is null");
776
- }
898
+ auto reader = DataReader::FromBuffer(value);
899
+ Data data(reader.UnconsumedBufferLength());
900
+ reader.ReadBytes(data);
901
+ mEmit.ReadHandle(uuid, handle, data);
777
902
  }
778
- else
779
- {
780
- LOGE("status: %d", status);
903
+ else {
904
+ mEmit.ReadHandle(uuid, handle, Data(), "value is null");
781
905
  }
782
906
  }
783
907
 
@@ -800,6 +924,7 @@ void BLEManager::OnWriteHandle(IAsyncOperation<GattWriteResult> asyncOp, AsyncSt
800
924
  }
801
925
  else
802
926
  {
803
- LOGE("status %d", status);
927
+ std::string error = "status: " + std::to_string((int)status);
928
+ mEmit.WriteHandle(uuid, handle, error);
804
929
  }
805
930
  }