@stoprocent/noble 1.9.2-16

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 (112) hide show
  1. package/.editorconfig +11 -0
  2. package/.eslintrc.js +25 -0
  3. package/.github/FUNDING.yml +2 -0
  4. package/.github/workflows/fediverse-action.yml +16 -0
  5. package/.github/workflows/nodepackage.yml +77 -0
  6. package/.github/workflows/npm-publish.yml +26 -0
  7. package/.github/workflows/prebuild.yml +65 -0
  8. package/.nycrc.json +4 -0
  9. package/CHANGELOG.md +119 -0
  10. package/LICENSE +20 -0
  11. package/MAINTAINERS.md +1 -0
  12. package/README.md +833 -0
  13. package/assets/noble-logo.png +0 -0
  14. package/assets/noble-logo.svg +13 -0
  15. package/binding.gyp +19 -0
  16. package/codecov.yml +5 -0
  17. package/examples/advertisement-discovery.js +65 -0
  18. package/examples/cache-gatt-discovery.js +198 -0
  19. package/examples/cache-gatt-reconnect.js +164 -0
  20. package/examples/echo.js +104 -0
  21. package/examples/enter-exit.js +78 -0
  22. package/examples/peripheral-explorer-async.js +133 -0
  23. package/examples/peripheral-explorer.js +225 -0
  24. package/examples/pizza/README.md +15 -0
  25. package/examples/pizza/central.js +194 -0
  26. package/examples/pizza/pizza.js +60 -0
  27. package/index.d.ts +203 -0
  28. package/index.js +6 -0
  29. package/lib/characteristic.js +161 -0
  30. package/lib/characteristics.json +449 -0
  31. package/lib/descriptor.js +72 -0
  32. package/lib/descriptors.json +47 -0
  33. package/lib/distributed/bindings.js +326 -0
  34. package/lib/hci-socket/acl-stream.js +60 -0
  35. package/lib/hci-socket/bindings.js +788 -0
  36. package/lib/hci-socket/crypto.js +74 -0
  37. package/lib/hci-socket/gap.js +432 -0
  38. package/lib/hci-socket/gatt.js +809 -0
  39. package/lib/hci-socket/hci-status.json +71 -0
  40. package/lib/hci-socket/hci.js +1264 -0
  41. package/lib/hci-socket/signaling.js +76 -0
  42. package/lib/hci-socket/smp.js +140 -0
  43. package/lib/hci-uart/bindings.js +569 -0
  44. package/lib/hci-uart/hci-serial-parser.js +70 -0
  45. package/lib/hci-uart/hci.js +1336 -0
  46. package/lib/mac/binding.gyp +26 -0
  47. package/lib/mac/bindings.js +11 -0
  48. package/lib/mac/src/ble_manager.h +41 -0
  49. package/lib/mac/src/ble_manager.mm +435 -0
  50. package/lib/mac/src/callbacks.cc +222 -0
  51. package/lib/mac/src/callbacks.h +84 -0
  52. package/lib/mac/src/napi_objc.h +12 -0
  53. package/lib/mac/src/napi_objc.mm +50 -0
  54. package/lib/mac/src/noble_mac.h +34 -0
  55. package/lib/mac/src/noble_mac.mm +264 -0
  56. package/lib/mac/src/objc_cpp.h +26 -0
  57. package/lib/mac/src/objc_cpp.mm +126 -0
  58. package/lib/mac/src/peripheral.h +23 -0
  59. package/lib/manufacture.js +48 -0
  60. package/lib/noble.js +593 -0
  61. package/lib/peripheral.js +219 -0
  62. package/lib/resolve-bindings-web.js +9 -0
  63. package/lib/resolve-bindings.js +44 -0
  64. package/lib/service.js +72 -0
  65. package/lib/services.json +92 -0
  66. package/lib/webbluetooth/bindings.js +368 -0
  67. package/lib/websocket/bindings.js +321 -0
  68. package/lib/win/binding.gyp +23 -0
  69. package/lib/win/bindings.js +11 -0
  70. package/lib/win/src/ble_manager.cc +802 -0
  71. package/lib/win/src/ble_manager.h +77 -0
  72. package/lib/win/src/callbacks.cc +274 -0
  73. package/lib/win/src/callbacks.h +33 -0
  74. package/lib/win/src/napi_winrt.cc +76 -0
  75. package/lib/win/src/napi_winrt.h +12 -0
  76. package/lib/win/src/noble_winrt.cc +308 -0
  77. package/lib/win/src/noble_winrt.h +34 -0
  78. package/lib/win/src/notify_map.cc +62 -0
  79. package/lib/win/src/notify_map.h +50 -0
  80. package/lib/win/src/peripheral.h +23 -0
  81. package/lib/win/src/peripheral_winrt.cc +296 -0
  82. package/lib/win/src/peripheral_winrt.h +82 -0
  83. package/lib/win/src/radio_watcher.cc +125 -0
  84. package/lib/win/src/radio_watcher.h +61 -0
  85. package/lib/win/src/winrt_cpp.cc +82 -0
  86. package/lib/win/src/winrt_cpp.h +11 -0
  87. package/lib/win/src/winrt_guid.cc +12 -0
  88. package/lib/win/src/winrt_guid.h +13 -0
  89. package/misc/nrf52840dk.hex +6921 -0
  90. package/misc/prj.conf +43 -0
  91. package/package.json +96 -0
  92. package/test/lib/characteristic.test.js +791 -0
  93. package/test/lib/descriptor.test.js +249 -0
  94. package/test/lib/distributed/bindings.test.js +918 -0
  95. package/test/lib/hci-socket/acl-stream.test.js +188 -0
  96. package/test/lib/hci-socket/bindings.test.js +1756 -0
  97. package/test/lib/hci-socket/crypto.test.js +55 -0
  98. package/test/lib/hci-socket/gap.test.js +1089 -0
  99. package/test/lib/hci-socket/gatt.test.js +2392 -0
  100. package/test/lib/hci-socket/hci.test.js +1891 -0
  101. package/test/lib/hci-socket/signaling.test.js +94 -0
  102. package/test/lib/hci-socket/smp.test.js +268 -0
  103. package/test/lib/manufacture.test.js +77 -0
  104. package/test/lib/peripheral.test.js +623 -0
  105. package/test/lib/resolve-bindings.test.js +102 -0
  106. package/test/lib/service.test.js +195 -0
  107. package/test/lib/webbluetooth/bindings.test.js +190 -0
  108. package/test/lib/websocket/bindings.test.js +456 -0
  109. package/test/noble.test.js +1565 -0
  110. package/test.js +131 -0
  111. package/with-bindings.js +5 -0
  112. package/ws-slave.js +404 -0
@@ -0,0 +1,802 @@
1
+ //
2
+ // ble_manager.cc
3
+ // noble-winrt-native
4
+ //
5
+ // Created by Georg Vienna on 03.09.18.
6
+ //
7
+
8
+ #include "ble_manager.h"
9
+ #include "winrt_cpp.h"
10
+
11
+ #include <winrt/Windows.Foundation.Collections.h>
12
+ #include <winrt/Windows.Storage.Streams.h>
13
+ using winrt::Windows::Devices::Bluetooth::BluetoothCacheMode;
14
+ using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
15
+ using winrt::Windows::Storage::Streams::DataReader;
16
+ using winrt::Windows::Storage::Streams::DataWriter;
17
+
18
+ template <typename T> auto inFilter(std::vector<T> filter, T object)
19
+ {
20
+ return filter.empty() || std::find(filter.begin(), filter.end(), object) != filter.end();
21
+ }
22
+
23
+ template <typename O, typename M, class... Types> auto bind2(O* object, M method, Types&... args)
24
+ {
25
+ return std::bind(method, object, std::placeholders::_1, std::placeholders::_2, args...);
26
+ }
27
+
28
+ #define LOGE(message, ...) printf(__FUNCTION__ ": " message "\n", __VA_ARGS__)
29
+
30
+ #define CHECK_DEVICE() \
31
+ if (mDeviceMap.find(uuid) == mDeviceMap.end()) \
32
+ { \
33
+ LOGE("device with id %s not found", uuid.c_str()); \
34
+ return false; \
35
+ }
36
+
37
+ #define IFDEVICE(_device, _uuid) \
38
+ PeripheralWinrt& peripheral = mDeviceMap[_uuid]; \
39
+ if (!peripheral.device.has_value()) \
40
+ { \
41
+ LOGE("device not connected"); \
42
+ return false; \
43
+ } \
44
+ BluetoothLEDevice& _device = *peripheral.device;
45
+
46
+ #define CHECK_RESULT(_result) \
47
+ if (!_result) \
48
+ { \
49
+ LOGE("result is null"); \
50
+ return; \
51
+ } \
52
+ auto _commStatus = _result.Status(); \
53
+ if (_commStatus != GattCommunicationStatus::Success) \
54
+ { \
55
+ LOGE("communication status: %d", _commStatus); \
56
+ return; \
57
+ }
58
+
59
+ #define FOR(object, vector) \
60
+ auto _vector = vector; \
61
+ if (!_vector) \
62
+ { \
63
+ LOGE(#vector " is null"); \
64
+ return; \
65
+ } \
66
+ else \
67
+ for (auto&& object : _vector)
68
+
69
+ BLEManager::BLEManager(const Napi::Value& receiver, const Napi::Function& callback)
70
+ {
71
+ mRadioState = AdapterState::Initial;
72
+ mEmit.Wrap(receiver, callback);
73
+ auto onRadio = std::bind(&BLEManager::OnRadio, this, std::placeholders::_1);
74
+ mWatcher.Start(onRadio);
75
+ mAdvertismentWatcher.ScanningMode(BluetoothLEScanningMode::Active);
76
+ auto onReceived = bind2(this, &BLEManager::OnScanResult);
77
+ mReceivedRevoker = mAdvertismentWatcher.Received(winrt::auto_revoke, onReceived);
78
+ auto onStopped = bind2(this, &BLEManager::OnScanStopped);
79
+ mStoppedRevoker = mAdvertismentWatcher.Stopped(winrt::auto_revoke, onStopped);
80
+ }
81
+
82
+ const char* adapterStateToString(AdapterState state)
83
+ {
84
+ switch (state)
85
+ {
86
+ case AdapterState::Unsupported:
87
+ return "unsupported";
88
+ case AdapterState::On:
89
+ return "poweredOn";
90
+ break;
91
+ case AdapterState::Off:
92
+ return "poweredOff";
93
+ break;
94
+ case AdapterState::Disabled:
95
+ return "poweredOff";
96
+ break;
97
+ default:
98
+ return "unknown";
99
+ }
100
+ }
101
+
102
+ void BLEManager::OnRadio(Radio& radio)
103
+ {
104
+ auto state = AdapterState::Unsupported;
105
+ if (radio)
106
+ {
107
+ state = (AdapterState)radio.State();
108
+ }
109
+ if (state != mRadioState)
110
+ {
111
+ mRadioState = state;
112
+ mEmit.RadioState(adapterStateToString(state));
113
+ }
114
+ }
115
+
116
+ void BLEManager::Scan(const std::vector<winrt::guid>& serviceUUIDs, bool allowDuplicates)
117
+ {
118
+ mAdvertismentMap.clear();
119
+ mAllowDuplicates = allowDuplicates;
120
+ BluetoothLEAdvertisementFilter filter = BluetoothLEAdvertisementFilter();
121
+ BluetoothLEAdvertisement advertisment = BluetoothLEAdvertisement();
122
+ auto services = advertisment.ServiceUuids();
123
+ for (auto uuid : serviceUUIDs)
124
+ {
125
+ services.Append(uuid);
126
+ }
127
+ filter.Advertisement(advertisment);
128
+ mAdvertismentWatcher.AdvertisementFilter(filter);
129
+ mAdvertismentWatcher.Start();
130
+ mEmit.ScanState(true);
131
+ }
132
+
133
+ void BLEManager::OnScanResult(BluetoothLEAdvertisementWatcher watcher,
134
+ const BluetoothLEAdvertisementReceivedEventArgs& args)
135
+ {
136
+ uint64_t bluetoothAddress = args.BluetoothAddress();
137
+ std::string uuid = formatBluetoothUuid(bluetoothAddress);
138
+ int16_t rssi = args.RawSignalStrengthInDBm();
139
+ auto advertismentType = args.AdvertisementType();
140
+
141
+ if (mDeviceMap.find(uuid) == mDeviceMap.end())
142
+ {
143
+ mAdvertismentMap.insert(uuid);
144
+ auto peripheral =
145
+ PeripheralWinrt(bluetoothAddress, advertismentType, rssi, args.Advertisement());
146
+ mEmit.Scan(uuid, rssi, peripheral);
147
+ mDeviceMap.emplace(std::make_pair(uuid, std::move(peripheral)));
148
+ }
149
+ else
150
+ {
151
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
152
+ peripheral.Update(rssi, args.Advertisement(), advertismentType);
153
+ if (mAllowDuplicates || mAdvertismentMap.find(uuid) == mAdvertismentMap.end())
154
+ {
155
+ mAdvertismentMap.insert(uuid);
156
+ mEmit.Scan(uuid, rssi, peripheral);
157
+ }
158
+ }
159
+ }
160
+
161
+ void BLEManager::StopScan()
162
+ {
163
+ mAdvertismentWatcher.Stop();
164
+ }
165
+
166
+ void BLEManager::OnScanStopped(BluetoothLEAdvertisementWatcher watcher,
167
+ const BluetoothLEAdvertisementWatcherStoppedEventArgs& args)
168
+ {
169
+ mEmit.ScanState(false);
170
+ }
171
+
172
+ bool BLEManager::Connect(const std::string& uuid)
173
+ {
174
+ if (mDeviceMap.find(uuid) == mDeviceMap.end())
175
+ {
176
+ mEmit.Connected(uuid, "device not found");
177
+ return false;
178
+ }
179
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
180
+ if (!peripheral.device.has_value())
181
+ {
182
+ auto completed = bind2(this, &BLEManager::OnConnected, uuid);
183
+ BluetoothLEDevice::FromBluetoothAddressAsync(peripheral.bluetoothAddress)
184
+ .Completed(completed);
185
+ }
186
+ else
187
+ {
188
+ mEmit.Connected(uuid);
189
+ }
190
+ return true;
191
+ }
192
+
193
+ void BLEManager::OnConnected(IAsyncOperation<BluetoothLEDevice> asyncOp, AsyncStatus& status,
194
+ const std::string uuid)
195
+ {
196
+ if (status == AsyncStatus::Completed)
197
+ {
198
+ BluetoothLEDevice device = asyncOp.GetResults();
199
+ // device can be null if the connection failed
200
+ if (device)
201
+ {
202
+ auto onChanged = bind2(this, &BLEManager::OnConnectionStatusChanged);
203
+ auto token = device.ConnectionStatusChanged(onChanged);
204
+ auto uuid = formatBluetoothUuid(device.BluetoothAddress());
205
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
206
+ peripheral.device = device;
207
+ peripheral.connectionToken = token;
208
+ mEmit.Connected(uuid);
209
+ }
210
+ else
211
+ {
212
+ mEmit.Connected(uuid, "could not connect to device: result is null");
213
+ }
214
+ }
215
+ else
216
+ {
217
+ mEmit.Connected(uuid, "could not connect to device");
218
+ }
219
+ }
220
+
221
+ bool BLEManager::Disconnect(const std::string& uuid)
222
+ {
223
+ CHECK_DEVICE();
224
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
225
+ peripheral.Disconnect();
226
+ mNotifyMap.Remove(uuid);
227
+ mEmit.Disconnected(uuid);
228
+ return true;
229
+ }
230
+
231
+ void BLEManager::OnConnectionStatusChanged(BluetoothLEDevice device,
232
+ winrt::Windows::Foundation::IInspectable inspectable)
233
+ {
234
+ if (device.ConnectionStatus() == BluetoothConnectionStatus::Disconnected)
235
+ {
236
+ auto uuid = formatBluetoothUuid(device.BluetoothAddress());
237
+ if (mDeviceMap.find(uuid) == mDeviceMap.end())
238
+ {
239
+ LOGE("device with id %s not found", uuid.c_str());
240
+ return;
241
+ }
242
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
243
+ peripheral.Disconnect();
244
+ mNotifyMap.Remove(uuid);
245
+ mEmit.Disconnected(uuid);
246
+ }
247
+ }
248
+
249
+ bool BLEManager::UpdateRSSI(const std::string& uuid)
250
+ {
251
+ CHECK_DEVICE();
252
+
253
+ PeripheralWinrt& peripheral = mDeviceMap[uuid];
254
+ // no way to get the rssi while we are connected, return the last value of advertisement
255
+ mEmit.RSSI(uuid, peripheral.rssi);
256
+ return true;
257
+ }
258
+
259
+ bool BLEManager::DiscoverServices(const std::string& uuid,
260
+ const std::vector<winrt::guid>& serviceUUIDs)
261
+ {
262
+ CHECK_DEVICE();
263
+ IFDEVICE(device, uuid)
264
+ {
265
+ auto completed = bind2(this, &BLEManager::OnServicesDiscovered, uuid, serviceUUIDs);
266
+ device.GetGattServicesAsync(BluetoothCacheMode::Uncached).Completed(completed);
267
+ return true;
268
+ }
269
+ }
270
+
271
+ void BLEManager::OnServicesDiscovered(IAsyncOperation<GattDeviceServicesResult> asyncOp,
272
+ AsyncStatus status, const std::string uuid,
273
+ const std::vector<winrt::guid> serviceUUIDs)
274
+ {
275
+ if (status == AsyncStatus::Completed)
276
+ {
277
+ GattDeviceServicesResult result = asyncOp.GetResults();
278
+ CHECK_RESULT(result);
279
+ std::vector<std::string> serviceUuids;
280
+ FOR(service, result.Services())
281
+ {
282
+ auto id = service.Uuid();
283
+ if (inFilter(serviceUUIDs, id))
284
+ {
285
+ serviceUuids.push_back(toStr(id));
286
+ }
287
+ }
288
+ mEmit.ServicesDiscovered(uuid, serviceUuids);
289
+ }
290
+ else
291
+ {
292
+ LOGE("status: %d", status);
293
+ }
294
+ }
295
+
296
+ bool BLEManager::DiscoverIncludedServices(const std::string& uuid, const winrt::guid& serviceUuid,
297
+ const std::vector<winrt::guid>& serviceUUIDs)
298
+ {
299
+ CHECK_DEVICE();
300
+ IFDEVICE(device, uuid)
301
+ {
302
+ peripheral.GetService(serviceUuid, [=](std::optional<GattDeviceService> service) {
303
+ if (service)
304
+ {
305
+ std::string serviceId = toStr(serviceUuid);
306
+ service->GetIncludedServicesAsync(BluetoothCacheMode::Uncached)
307
+ .Completed(bind2(this, &BLEManager::OnIncludedServicesDiscovered, uuid,
308
+ serviceId, serviceUUIDs));
309
+ }
310
+ else
311
+ {
312
+ LOGE("GetService error");
313
+ }
314
+ });
315
+ return true;
316
+ }
317
+ }
318
+
319
+ void BLEManager::OnIncludedServicesDiscovered(IAsyncOperation<GattDeviceServicesResult> asyncOp,
320
+ AsyncStatus status, const std::string uuid,
321
+ const std::string serviceId,
322
+ const std::vector<winrt::guid> serviceUUIDs)
323
+ {
324
+ if (status == AsyncStatus::Completed)
325
+ {
326
+ auto result = asyncOp.GetResults();
327
+ CHECK_RESULT(result);
328
+ std::vector<std::string> servicesUuids;
329
+ FOR(service, result.Services())
330
+ {
331
+ auto id = service.Uuid();
332
+ if (inFilter(serviceUUIDs, id))
333
+ {
334
+ servicesUuids.push_back(toStr(id));
335
+ }
336
+ }
337
+ mEmit.IncludedServicesDiscovered(uuid, serviceId, servicesUuids);
338
+ }
339
+ else
340
+ {
341
+ LOGE("status: %d", status);
342
+ }
343
+ }
344
+
345
+ bool BLEManager::DiscoverCharacteristics(const std::string& uuid, const winrt::guid& serviceUuid,
346
+ const std::vector<winrt::guid>& characteristicUUIDs)
347
+ {
348
+ CHECK_DEVICE();
349
+ IFDEVICE(device, uuid)
350
+ {
351
+ peripheral.GetService(serviceUuid, [=](std::optional<GattDeviceService> service) {
352
+ if (service)
353
+ {
354
+ std::string serviceId = toStr(serviceUuid);
355
+ service->GetCharacteristicsAsync(BluetoothCacheMode::Uncached)
356
+ .Completed(bind2(this, &BLEManager::OnCharacteristicsDiscovered, uuid,
357
+ serviceId, characteristicUUIDs));
358
+ }
359
+ else
360
+ {
361
+ LOGE("GetService error");
362
+ }
363
+ });
364
+ return true;
365
+ }
366
+ }
367
+
368
+ void BLEManager::OnCharacteristicsDiscovered(IAsyncOperation<GattCharacteristicsResult> asyncOp,
369
+ AsyncStatus status, const std::string uuid,
370
+ const std::string serviceId,
371
+ const std::vector<winrt::guid> characteristicUUIDs)
372
+ {
373
+ if (status == AsyncStatus::Completed)
374
+ {
375
+ auto result = asyncOp.GetResults();
376
+ CHECK_RESULT(result);
377
+ std::vector<std::pair<std::string, std::vector<std::string>>> characteristicsUuids;
378
+ FOR(characteristic, result.Characteristics())
379
+ {
380
+ auto id = characteristic.Uuid();
381
+ if (inFilter(characteristicUUIDs, id))
382
+ {
383
+ auto props = characteristic.CharacteristicProperties();
384
+ characteristicsUuids.push_back({ toStr(id), toPropertyArray(props) });
385
+ }
386
+ }
387
+ mEmit.CharacteristicsDiscovered(uuid, serviceId, characteristicsUuids);
388
+ }
389
+ else
390
+ {
391
+ LOGE("status: %d", status);
392
+ }
393
+ }
394
+
395
+ bool BLEManager::Read(const std::string& uuid, const winrt::guid& serviceUuid,
396
+ const winrt::guid& characteristicUuid)
397
+ {
398
+ CHECK_DEVICE();
399
+ IFDEVICE(device, uuid)
400
+ {
401
+ peripheral.GetCharacteristic(
402
+ serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
403
+ if (characteristic)
404
+ {
405
+ std::string serviceId = toStr(serviceUuid);
406
+ std::string characteristicId = toStr(characteristicUuid);
407
+ characteristic->ReadValueAsync(BluetoothCacheMode::Uncached)
408
+ .Completed(
409
+ bind2(this, &BLEManager::OnRead, uuid, serviceId, characteristicId));
410
+ }
411
+ else
412
+ {
413
+ LOGE("GetCharacteristic error");
414
+ }
415
+ });
416
+ return true;
417
+ }
418
+ }
419
+
420
+ void BLEManager::OnRead(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
421
+ const std::string uuid, const std::string serviceId,
422
+ const std::string characteristicId)
423
+ {
424
+ if (status == AsyncStatus::Completed)
425
+ {
426
+ GattReadResult result = asyncOp.GetResults();
427
+ CHECK_RESULT(result);
428
+ auto value = result.Value();
429
+ if (value)
430
+ {
431
+ auto reader = DataReader::FromBuffer(value);
432
+ Data data(reader.UnconsumedBufferLength());
433
+ reader.ReadBytes(data);
434
+ mEmit.Read(uuid, serviceId, characteristicId, data, false);
435
+ }
436
+ else
437
+ {
438
+ LOGE("value is null");
439
+ }
440
+ }
441
+ else
442
+ {
443
+ LOGE("status: %d", status);
444
+ }
445
+ }
446
+
447
+ bool BLEManager::Write(const std::string& uuid, const winrt::guid& serviceUuid,
448
+ const winrt::guid& characteristicUuid, const Data& data,
449
+ bool withoutResponse)
450
+ {
451
+ CHECK_DEVICE();
452
+ IFDEVICE(device, uuid)
453
+ {
454
+ peripheral.GetCharacteristic(
455
+ serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
456
+ if (characteristic)
457
+ {
458
+ std::string serviceId = toStr(serviceUuid);
459
+ std::string characteristicId = toStr(characteristicUuid);
460
+ auto writer = DataWriter();
461
+ writer.WriteBytes(data);
462
+ auto value = writer.DetachBuffer();
463
+ GattWriteOption option = withoutResponse ? GattWriteOption::WriteWithoutResponse
464
+ : GattWriteOption::WriteWithResponse;
465
+ characteristic->WriteValueWithResultAsync(value, option)
466
+ .Completed(
467
+ bind2(this, &BLEManager::OnWrite, uuid, serviceId, characteristicId));
468
+ }
469
+ else
470
+ {
471
+ LOGE("GetCharacteristic error");
472
+ }
473
+ });
474
+ return true;
475
+ }
476
+ }
477
+
478
+ void BLEManager::OnWrite(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
479
+ const std::string uuid, const std::string serviceId,
480
+ const std::string characteristicId)
481
+ {
482
+ if (status == AsyncStatus::Completed)
483
+ {
484
+ mEmit.Write(uuid, serviceId, characteristicId);
485
+ }
486
+ else
487
+ {
488
+ LOGE("status: %d", status);
489
+ }
490
+ }
491
+
492
+ GattClientCharacteristicConfigurationDescriptorValue
493
+ GetDescriptorValue(GattCharacteristicProperties properties)
494
+ {
495
+ if ((properties & GattCharacteristicProperties::Indicate) ==
496
+ GattCharacteristicProperties::Indicate)
497
+ {
498
+ return GattClientCharacteristicConfigurationDescriptorValue::Indicate;
499
+ }
500
+ else
501
+ {
502
+ return GattClientCharacteristicConfigurationDescriptorValue::Notify;
503
+ }
504
+ }
505
+
506
+ bool BLEManager::Notify(const std::string& uuid, const winrt::guid& serviceUuid,
507
+ const winrt::guid& characteristicUuid, bool on)
508
+ {
509
+ CHECK_DEVICE();
510
+ IFDEVICE(device, uuid)
511
+ {
512
+ auto onCharacteristic = [=](std::optional<GattCharacteristic> characteristic) {
513
+ if (characteristic)
514
+ {
515
+ std::string serviceId = toStr(serviceUuid);
516
+ std::string characteristicId = toStr(characteristicUuid);
517
+ bool subscribed = mNotifyMap.IsSubscribed(uuid, *characteristic);
518
+
519
+ if (on)
520
+ {
521
+ if (subscribed)
522
+ {
523
+ // already listening
524
+ mEmit.Notify(uuid, serviceId, characteristicId, true);
525
+ return;
526
+ }
527
+ auto descriptorValue =
528
+ GetDescriptorValue(characteristic->CharacteristicProperties());
529
+
530
+ auto completed = bind2(this, &BLEManager::OnNotify, *characteristic, uuid,
531
+ serviceId, characteristicId, on);
532
+ characteristic
533
+ ->WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
534
+ descriptorValue)
535
+ .Completed(completed);
536
+ }
537
+ else
538
+ {
539
+ if (!subscribed)
540
+ {
541
+ // already not listening
542
+ mEmit.Notify(uuid, serviceId, characteristicId, false);
543
+ return;
544
+ }
545
+
546
+ mNotifyMap.Unsubscribe(uuid, *characteristic);
547
+ auto descriptorValue =
548
+ GattClientCharacteristicConfigurationDescriptorValue::None;
549
+ auto completed = bind2(this, &BLEManager::OnNotify, *characteristic, uuid,
550
+ serviceId, characteristicId, on);
551
+ characteristic
552
+ ->WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
553
+ descriptorValue)
554
+ .Completed(completed);
555
+ }
556
+ }
557
+ else
558
+ {
559
+ LOGE("GetCharacteristic error");
560
+ }
561
+ };
562
+ peripheral.GetCharacteristic(serviceUuid, characteristicUuid, onCharacteristic);
563
+ return true;
564
+ }
565
+ }
566
+
567
+ void BLEManager::OnNotify(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
568
+ const GattCharacteristic characteristic, const std::string uuid,
569
+ const std::string serviceId, const std::string characteristicId,
570
+ const bool state)
571
+ {
572
+ if (status == AsyncStatus::Completed)
573
+ {
574
+ if (state == true)
575
+ {
576
+ auto onChanged = bind2(this, &BLEManager::OnValueChanged, uuid);
577
+ auto token = characteristic.ValueChanged(onChanged);
578
+ mNotifyMap.Add(uuid, characteristic, token);
579
+ }
580
+ mEmit.Notify(uuid, serviceId, characteristicId, state);
581
+ }
582
+ else
583
+ {
584
+ LOGE("status: %d", status);
585
+ }
586
+ }
587
+
588
+ void BLEManager::OnValueChanged(GattCharacteristic characteristic,
589
+ const GattValueChangedEventArgs& args, std::string deviceUuid)
590
+ {
591
+ auto reader = DataReader::FromBuffer(args.CharacteristicValue());
592
+ Data data(reader.UnconsumedBufferLength());
593
+ reader.ReadBytes(data);
594
+ auto characteristicUuid = toStr(characteristic.Uuid());
595
+ auto serviceUuid = toStr(characteristic.Service().Uuid());
596
+ mEmit.Read(deviceUuid, serviceUuid, characteristicUuid, data, true);
597
+ }
598
+
599
+ bool BLEManager::DiscoverDescriptors(const std::string& uuid, const winrt::guid& serviceUuid,
600
+ const winrt::guid& characteristicUuid)
601
+ {
602
+ CHECK_DEVICE();
603
+ IFDEVICE(device, uuid)
604
+ {
605
+ peripheral.GetCharacteristic(
606
+ serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
607
+ if (characteristic)
608
+ {
609
+ std::string serviceId = toStr(serviceUuid);
610
+ std::string characteristicId = toStr(characteristicUuid);
611
+ auto completed = bind2(this, &BLEManager::OnDescriptorsDiscovered, uuid,
612
+ serviceId, characteristicId);
613
+ characteristic->GetDescriptorsAsync(BluetoothCacheMode::Uncached)
614
+ .Completed(completed);
615
+ }
616
+ else
617
+ {
618
+ LOGE("GetCharacteristic error");
619
+ }
620
+ });
621
+ return true;
622
+ }
623
+ }
624
+
625
+ void BLEManager::OnDescriptorsDiscovered(IAsyncOperation<GattDescriptorsResult> asyncOp,
626
+ AsyncStatus status, const std::string uuid,
627
+ const std::string serviceId,
628
+ const std::string characteristicId)
629
+ {
630
+ if (status == AsyncStatus::Completed)
631
+ {
632
+ auto result = asyncOp.GetResults();
633
+ CHECK_RESULT(result);
634
+ std::vector<std::string> descriptorUuids;
635
+ FOR(descriptor, result.Descriptors())
636
+ {
637
+ descriptorUuids.push_back(toStr(descriptor.Uuid()));
638
+ }
639
+ mEmit.DescriptorsDiscovered(uuid, serviceId, characteristicId, descriptorUuids);
640
+ }
641
+ else
642
+ {
643
+ LOGE("status: %d", status);
644
+ }
645
+ }
646
+
647
+ bool BLEManager::ReadValue(const std::string& uuid, const winrt::guid& serviceUuid,
648
+ const winrt::guid& characteristicUuid, const winrt::guid& descriptorUuid)
649
+ {
650
+ CHECK_DEVICE();
651
+ IFDEVICE(device, uuid)
652
+ {
653
+ peripheral.GetDescriptor(
654
+ serviceUuid, characteristicUuid, descriptorUuid,
655
+ [=](std::optional<GattDescriptor> descriptor) {
656
+ if (descriptor)
657
+ {
658
+ std::string serviceId = toStr(serviceUuid);
659
+ std::string characteristicId = toStr(characteristicUuid);
660
+ std::string descriptorId = toStr(descriptorUuid);
661
+ auto completed = bind2(this, &BLEManager::OnReadValue, uuid, serviceId,
662
+ characteristicId, descriptorId);
663
+ descriptor->ReadValueAsync(BluetoothCacheMode::Uncached).Completed(completed);
664
+ }
665
+ else
666
+ {
667
+ LOGE("descriptor not found");
668
+ }
669
+ });
670
+ return true;
671
+ }
672
+ }
673
+
674
+ void BLEManager::OnReadValue(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
675
+ const std::string uuid, const std::string serviceId,
676
+ const std::string characteristicId, const std::string descriptorId)
677
+ {
678
+ if (status == AsyncStatus::Completed)
679
+ {
680
+ GattReadResult result = asyncOp.GetResults();
681
+ CHECK_RESULT(result);
682
+ auto value = result.Value();
683
+ if (value)
684
+ {
685
+ auto reader = DataReader::FromBuffer(value);
686
+ Data data(reader.UnconsumedBufferLength());
687
+ reader.ReadBytes(data);
688
+ mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, data);
689
+ }
690
+ else
691
+ {
692
+ LOGE("value is null");
693
+ }
694
+ }
695
+ else
696
+ {
697
+ LOGE("status: %d", status);
698
+ }
699
+ }
700
+
701
+ bool BLEManager::WriteValue(const std::string& uuid, const winrt::guid& serviceUuid,
702
+ const winrt::guid& characteristicUuid,
703
+ const winrt::guid& descriptorUuid, const Data& data)
704
+ {
705
+ CHECK_DEVICE();
706
+ IFDEVICE(device, uuid)
707
+ {
708
+ auto onDescriptor = [=](std::optional<GattDescriptor> descriptor) {
709
+ if (descriptor)
710
+ {
711
+ std::string serviceId = toStr(serviceUuid);
712
+ std::string characteristicId = toStr(characteristicUuid);
713
+ std::string descriptorId = toStr(descriptorUuid);
714
+ auto writer = DataWriter();
715
+ writer.WriteBytes(data);
716
+ auto value = writer.DetachBuffer();
717
+ auto asyncOp = descriptor->WriteValueWithResultAsync(value);
718
+ asyncOp.Completed(bind2(this, &BLEManager::OnWriteValue, uuid, serviceId,
719
+ characteristicId, descriptorId));
720
+ }
721
+ else
722
+ {
723
+ LOGE("descriptor not found");
724
+ }
725
+ };
726
+ peripheral.GetDescriptor(serviceUuid, characteristicUuid, descriptorUuid, onDescriptor);
727
+ return true;
728
+ }
729
+ }
730
+
731
+ void BLEManager::OnWriteValue(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
732
+ const std::string uuid, const std::string serviceId,
733
+ const std::string characteristicId, const std::string descriptorId)
734
+ {
735
+ if (status == AsyncStatus::Completed)
736
+ {
737
+ mEmit.WriteValue(uuid, serviceId, characteristicId, descriptorId);
738
+ }
739
+ else
740
+ {
741
+ LOGE("status: %d", status);
742
+ }
743
+ }
744
+
745
+ bool BLEManager::ReadHandle(const std::string& uuid, int handle)
746
+ {
747
+ CHECK_DEVICE();
748
+ IFDEVICE(device, uuid)
749
+ {
750
+ LOGE("not available");
751
+ return true;
752
+ }
753
+ }
754
+
755
+ void BLEManager::OnReadHandle(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
756
+ const std::string uuid, const int handle)
757
+ {
758
+ if (status == AsyncStatus::Completed)
759
+ {
760
+ GattReadResult result = asyncOp.GetResults();
761
+ CHECK_RESULT(result);
762
+ auto value = result.Value();
763
+ if (value)
764
+ {
765
+ auto reader = DataReader::FromBuffer(value);
766
+ Data data(reader.UnconsumedBufferLength());
767
+ reader.ReadBytes(data);
768
+ mEmit.ReadHandle(uuid, handle, data);
769
+ }
770
+ else
771
+ {
772
+ LOGE("value is null");
773
+ }
774
+ }
775
+ else
776
+ {
777
+ LOGE("status: %d", status);
778
+ }
779
+ }
780
+
781
+ bool BLEManager::WriteHandle(const std::string& uuid, int handle, Data data)
782
+ {
783
+ CHECK_DEVICE();
784
+ IFDEVICE(device, uuid)
785
+ {
786
+ LOGE("not available");
787
+ return true;
788
+ }
789
+ }
790
+
791
+ void BLEManager::OnWriteHandle(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
792
+ const std::string uuid, const int handle)
793
+ {
794
+ if (status == AsyncStatus::Completed)
795
+ {
796
+ mEmit.WriteHandle(uuid, handle);
797
+ }
798
+ else
799
+ {
800
+ LOGE("status %d", status);
801
+ }
802
+ }