@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,569 @@
1
+ const events = require('events');
2
+ const util = require('util');
3
+
4
+ const AclStream = require('../hci-socket/acl-stream');
5
+ const Gatt = require('../hci-socket/gatt');
6
+ const Gap = require('../hci-socket/gap');
7
+ const Hci = require('./hci');
8
+ const Signaling = require('../hci-socket/signaling');
9
+
10
+ const NobleBindings = function (options) {
11
+ this._state = null;
12
+
13
+ this._addresses = {};
14
+ this._addresseTypes = {};
15
+ this._connectable = {};
16
+
17
+ this._pendingConnectionUuid = null;
18
+ this._connectionQueue = [];
19
+
20
+ this._handles = {};
21
+ this._gatts = {};
22
+ this._aclStreams = {};
23
+ this._signalings = {};
24
+
25
+ this._hci = new Hci(options);
26
+ this._gap = new Gap(this._hci);
27
+ };
28
+
29
+ util.inherits(NobleBindings, events.EventEmitter);
30
+
31
+ NobleBindings.prototype.setScanParameters = function (interval, window) {
32
+ this._gap.setScanParameters(interval, window);
33
+ };
34
+
35
+ NobleBindings.prototype.startScanning = function (serviceUuids, allowDuplicates) {
36
+ this._scanServiceUuids = serviceUuids || [];
37
+
38
+ this._gap.startScanning(allowDuplicates);
39
+ };
40
+
41
+ NobleBindings.prototype.stopScanning = function () {
42
+ this._gap.stopScanning();
43
+ };
44
+
45
+ NobleBindings.prototype.connect = function (peripheralUuid, parameters) {
46
+ const address = this._addresses[peripheralUuid];
47
+ const addressType = this._addresseTypes[peripheralUuid];
48
+
49
+ if (!this._pendingConnectionUuid) {
50
+ this._pendingConnectionUuid = peripheralUuid;
51
+
52
+ this._hci.createLeConn(address, addressType, parameters);
53
+ } else {
54
+ this._connectionQueue.push({ id: peripheralUuid, params: parameters });
55
+ }
56
+ };
57
+
58
+ NobleBindings.prototype.disconnect = function (peripheralUuid) {
59
+ this._hci.disconnect(this._handles[peripheralUuid]);
60
+ };
61
+
62
+ NobleBindings.prototype.cancelConnect = function (peripheralUuid) {
63
+ // TODO: check if it was not in the queue and only then issue cancel on hci
64
+ this._connectionQueue = this._connectionQueue.filter(c => c.id !== peripheralUuid);
65
+ this._hci.cancelConnect(this._handles[peripheralUuid]);
66
+ };
67
+
68
+ NobleBindings.prototype.reset = function () {
69
+ this._hci.reset();
70
+ };
71
+
72
+ NobleBindings.prototype.updateRssi = function (peripheralUuid) {
73
+ this._hci.readRssi(this._handles[peripheralUuid]);
74
+ };
75
+
76
+ NobleBindings.prototype.init = function () {
77
+ this.onSigIntBinded = this.onSigInt.bind(this);
78
+
79
+ this._gap.on('scanParametersSet', this.onScanParametersSet.bind(this));
80
+ this._gap.on('scanStart', this.onScanStart.bind(this));
81
+ this._gap.on('scanStop', this.onScanStop.bind(this));
82
+ this._gap.on('discover', this.onDiscover.bind(this));
83
+
84
+ this._hci.on('stateChange', this.onStateChange.bind(this));
85
+ this._hci.on('addressChange', this.onAddressChange.bind(this));
86
+ this._hci.on('leConnComplete', this.onLeConnComplete.bind(this));
87
+ this._hci.on('leConnUpdateComplete', this.onLeConnUpdateComplete.bind(this));
88
+ this._hci.on('rssiRead', this.onRssiRead.bind(this));
89
+ this._hci.on('disconnComplete', this.onDisconnComplete.bind(this));
90
+ this._hci.on('encryptChange', this.onEncryptChange.bind(this));
91
+ this._hci.on('aclDataPkt', this.onAclDataPkt.bind(this));
92
+
93
+ this._hci.init();
94
+
95
+ /* Add exit handlers after `init()` has completed. If no adaptor
96
+ is present it can throw an exception - in which case we don't
97
+ want to try and clear up afterwards (issue #502) */
98
+ process.on('SIGINT', this.onSigIntBinded);
99
+ process.on('exit', this.onExit.bind(this));
100
+ };
101
+
102
+ NobleBindings.prototype.onSigInt = function () {
103
+ const sigIntListeners = process.listeners('SIGINT');
104
+
105
+ if (sigIntListeners[sigIntListeners.length - 1] === this.onSigIntBinded) {
106
+ // We need to cleanup queue processing uart messages
107
+ this._hci.cleanup();
108
+ // we are the last listener, so exit
109
+ // this will trigger onExit, and clean up
110
+ process.exit(1);
111
+ }
112
+ };
113
+
114
+ NobleBindings.prototype.onExit = function () {
115
+ this.stopScanning();
116
+
117
+ for (const handle in this._aclStreams) {
118
+ this._hci.disconnect(handle);
119
+ }
120
+ };
121
+
122
+ NobleBindings.prototype.onStateChange = function (state) {
123
+ if (this._state === state) {
124
+ return;
125
+ }
126
+ this._state = state;
127
+
128
+ if (state === 'unauthorized') {
129
+ console.log('noble warning: adapter state unauthorized, please run as root or with sudo');
130
+ console.log(' or see README for information on running without root/sudo:');
131
+ console.log(' https://github.com/sandeepmistry/noble#running-on-linux');
132
+ } else if (state === 'unsupported') {
133
+ console.log('noble warning: adapter does not support Bluetooth Low Energy (BLE, Bluetooth Smart).');
134
+ console.log(' Try to run with environment variable:');
135
+ console.log(' [sudo] NOBLE_HCI_DEVICE_ID=x node ...');
136
+ }
137
+
138
+ this.emit('stateChange', state);
139
+ };
140
+
141
+ NobleBindings.prototype.onAddressChange = function (address) {
142
+ this.emit('addressChange', address);
143
+ };
144
+
145
+ NobleBindings.prototype.onScanParametersSet = function () {
146
+ this.emit('scanParametersSet');
147
+ };
148
+
149
+ NobleBindings.prototype.onScanStart = function (filterDuplicates) {
150
+ this.emit('scanStart', filterDuplicates);
151
+ };
152
+
153
+ NobleBindings.prototype.onScanStop = function () {
154
+ this.emit('scanStop');
155
+ };
156
+
157
+ NobleBindings.prototype.onDiscover = function (status, address, addressType, connectable, advertisement, rssi) {
158
+ if (this._scanServiceUuids === undefined) {
159
+ return;
160
+ }
161
+
162
+ let serviceUuids = advertisement.serviceUuids || [];
163
+ const serviceData = advertisement.serviceData || [];
164
+ let hasScanServiceUuids = (this._scanServiceUuids.length === 0);
165
+
166
+ if (!hasScanServiceUuids) {
167
+ let i;
168
+
169
+ serviceUuids = serviceUuids.slice();
170
+
171
+ for (i in serviceData) {
172
+ serviceUuids.push(serviceData[i].uuid);
173
+ }
174
+
175
+ for (i in serviceUuids) {
176
+ hasScanServiceUuids = (this._scanServiceUuids.indexOf(serviceUuids[i]) !== -1);
177
+
178
+ if (hasScanServiceUuids) {
179
+ break;
180
+ }
181
+ }
182
+ }
183
+
184
+ if (hasScanServiceUuids) {
185
+ const uuid = address.split(':').join('');
186
+ this._addresses[uuid] = address;
187
+ this._addresseTypes[uuid] = addressType;
188
+ this._connectable[uuid] = connectable;
189
+
190
+ this.emit('discover', uuid, address, addressType, connectable, advertisement, rssi);
191
+ }
192
+ };
193
+
194
+ NobleBindings.prototype.onLeConnComplete = function (status, handle, role, addressType, address, interval, latency, supervisionTimeout, masterClockAccuracy) {
195
+ if (role !== 0) {
196
+ // not master, ignore
197
+ return;
198
+ }
199
+ let uuid = null;
200
+
201
+ let error = null;
202
+
203
+ if (status === 0) {
204
+ uuid = address.split(':').join('').toLowerCase();
205
+
206
+ const aclStream = new AclStream(this._hci, handle, this._hci.addressType, this._hci.address, addressType, address);
207
+ const gatt = new Gatt(address, aclStream);
208
+ const signaling = new Signaling(handle, aclStream);
209
+
210
+ this._gatts[uuid] = this._gatts[handle] = gatt;
211
+ this._signalings[uuid] = this._signalings[handle] = signaling;
212
+ this._aclStreams[handle] = aclStream;
213
+ this._handles[uuid] = handle;
214
+ this._handles[handle] = uuid;
215
+
216
+ this._gatts[handle].on('mtu', this.onMtu.bind(this));
217
+ this._gatts[handle].on('servicesDiscover', this.onServicesDiscovered.bind(this));
218
+ this._gatts[handle].on('servicesDiscovered', this.onServicesDiscoveredEX.bind(this));
219
+ this._gatts[handle].on('includedServicesDiscover', this.onIncludedServicesDiscovered.bind(this));
220
+ this._gatts[handle].on('characteristicsDiscover', this.onCharacteristicsDiscovered.bind(this));
221
+ this._gatts[handle].on('characteristicsDiscovered', this.onCharacteristicsDiscoveredEX.bind(this));
222
+ this._gatts[handle].on('read', this.onRead.bind(this));
223
+ this._gatts[handle].on('write', this.onWrite.bind(this));
224
+ this._gatts[handle].on('broadcast', this.onBroadcast.bind(this));
225
+ this._gatts[handle].on('notify', this.onNotify.bind(this));
226
+ this._gatts[handle].on('notification', this.onNotification.bind(this));
227
+ this._gatts[handle].on('descriptorsDiscover', this.onDescriptorsDiscovered.bind(this));
228
+ this._gatts[handle].on('valueRead', this.onValueRead.bind(this));
229
+ this._gatts[handle].on('valueWrite', this.onValueWrite.bind(this));
230
+ this._gatts[handle].on('handleRead', this.onHandleRead.bind(this));
231
+ this._gatts[handle].on('handleWrite', this.onHandleWrite.bind(this));
232
+ this._gatts[handle].on('handleNotify', this.onHandleNotify.bind(this));
233
+
234
+ this._signalings[handle].on('connectionParameterUpdateRequest', this.onConnectionParameterUpdateRequest.bind(this));
235
+
236
+ setTimeout(() => {
237
+ this._gatts[handle].exchangeMtu();
238
+ }, 0);
239
+ } else {
240
+ uuid = this._pendingConnectionUuid;
241
+ let statusMessage = Hci.STATUS_MAPPER[status] || 'HCI Error: Unknown';
242
+ const errorCode = ` (0x${status.toString(16)})`;
243
+ statusMessage = statusMessage + errorCode;
244
+ error = new Error(statusMessage);
245
+ }
246
+
247
+ this.emit('connect', uuid, error);
248
+
249
+ if (this._connectionQueue.length > 0) {
250
+ const queueItem = this._connectionQueue.shift();
251
+ const peripheralUuid = queueItem.id;
252
+
253
+ address = this._addresses[peripheralUuid];
254
+ addressType = this._addresseTypes[peripheralUuid];
255
+
256
+ this._pendingConnectionUuid = peripheralUuid;
257
+
258
+ this._hci.createLeConn(address, addressType, queueItem.params);
259
+ } else {
260
+ this._pendingConnectionUuid = null;
261
+ }
262
+ };
263
+
264
+ NobleBindings.prototype.onLeConnUpdateComplete = function (handle, interval, latency, supervisionTimeout) {
265
+ // no-op
266
+ };
267
+
268
+ NobleBindings.prototype.onDisconnComplete = function (handle, reason) {
269
+ const uuid = this._handles[handle];
270
+
271
+ if (uuid) {
272
+ this._aclStreams[handle].push(null, null);
273
+ this._gatts[handle].removeAllListeners();
274
+ this._signalings[handle].removeAllListeners();
275
+
276
+ delete this._gatts[uuid];
277
+ delete this._gatts[handle];
278
+ delete this._signalings[uuid];
279
+ delete this._signalings[handle];
280
+ delete this._aclStreams[handle];
281
+ delete this._handles[uuid];
282
+ delete this._handles[handle];
283
+
284
+ this.emit('disconnect', uuid); // TODO: handle reason?
285
+ } else {
286
+ console.warn(`noble warning: unknown handle ${handle} disconnected!`);
287
+ }
288
+ };
289
+
290
+ NobleBindings.prototype.onEncryptChange = function (handle, encrypt) {
291
+ const aclStream = this._aclStreams[handle];
292
+
293
+ if (aclStream) {
294
+ aclStream.pushEncrypt(encrypt);
295
+ }
296
+ };
297
+
298
+ NobleBindings.prototype.onMtu = function (address, mtu) {
299
+ const uuid = address.split(':').join('').toLowerCase();
300
+ this.emit('onMtu', uuid, mtu);
301
+ };
302
+
303
+ NobleBindings.prototype.onRssiRead = function (handle, rssi) {
304
+ this.emit('rssiUpdate', this._handles[handle], rssi);
305
+ };
306
+
307
+ NobleBindings.prototype.onAclDataPkt = function (handle, cid, data) {
308
+ const aclStream = this._aclStreams[handle];
309
+
310
+ if (aclStream) {
311
+ aclStream.push(cid, data);
312
+ }
313
+ };
314
+
315
+ NobleBindings.prototype.addService = function (peripheralUuid, service) {
316
+ const handle = this._handles[peripheralUuid];
317
+ const gatt = this._gatts[handle];
318
+
319
+ if (gatt) {
320
+ gatt.addService(service);
321
+ } else {
322
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
323
+ }
324
+ };
325
+
326
+ NobleBindings.prototype.discoverServices = function (peripheralUuid, uuids) {
327
+ const handle = this._handles[peripheralUuid];
328
+ const gatt = this._gatts[handle];
329
+
330
+ if (gatt) {
331
+ gatt.discoverServices(uuids || []);
332
+ } else {
333
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
334
+ }
335
+ };
336
+
337
+ NobleBindings.prototype.onServicesDiscovered = function (address, serviceUuids) {
338
+ const uuid = address.split(':').join('').toLowerCase();
339
+
340
+ this.emit('servicesDiscover', uuid, serviceUuids);
341
+ };
342
+
343
+ NobleBindings.prototype.onServicesDiscoveredEX = function (address, services) {
344
+ const uuid = address.split(':').join('').toLowerCase();
345
+
346
+ this.emit('servicesDiscovered', uuid, services);
347
+ };
348
+
349
+ NobleBindings.prototype.discoverIncludedServices = function (peripheralUuid, serviceUuid, serviceUuids) {
350
+ const handle = this._handles[peripheralUuid];
351
+ const gatt = this._gatts[handle];
352
+
353
+ if (gatt) {
354
+ gatt.discoverIncludedServices(serviceUuid, serviceUuids || []);
355
+ } else {
356
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
357
+ }
358
+ };
359
+
360
+ NobleBindings.prototype.onIncludedServicesDiscovered = function (address, serviceUuid, includedServiceUuids) {
361
+ const uuid = address.split(':').join('').toLowerCase();
362
+
363
+ this.emit('includedServicesDiscover', uuid, serviceUuid, includedServiceUuids);
364
+ };
365
+
366
+ NobleBindings.prototype.addCharacteristics = function (peripheralUuid, serviceUuid, characteristics) {
367
+ const handle = this._handles[peripheralUuid];
368
+ const gatt = this._gatts[handle];
369
+
370
+ if (gatt) {
371
+ gatt.addCharacteristics(serviceUuid, characteristics);
372
+ } else {
373
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
374
+ }
375
+ };
376
+
377
+ NobleBindings.prototype.discoverCharacteristics = function (peripheralUuid, serviceUuid, characteristicUuids) {
378
+ const handle = this._handles[peripheralUuid];
379
+ const gatt = this._gatts[handle];
380
+
381
+ if (gatt) {
382
+ gatt.discoverCharacteristics(serviceUuid, characteristicUuids || []);
383
+ } else {
384
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
385
+ }
386
+ };
387
+
388
+ NobleBindings.prototype.onCharacteristicsDiscovered = function (address, serviceUuid, characteristics) {
389
+ const uuid = address.split(':').join('').toLowerCase();
390
+
391
+ this.emit('characteristicsDiscover', uuid, serviceUuid, characteristics);
392
+ };
393
+
394
+ NobleBindings.prototype.onCharacteristicsDiscoveredEX = function (address, serviceUuid, characteristics) {
395
+ const uuid = address.split(':').join('').toLowerCase();
396
+
397
+ this.emit('characteristicsDiscovered', uuid, serviceUuid, characteristics);
398
+ };
399
+
400
+ NobleBindings.prototype.read = function (peripheralUuid, serviceUuid, characteristicUuid) {
401
+ const handle = this._handles[peripheralUuid];
402
+ const gatt = this._gatts[handle];
403
+
404
+ if (gatt) {
405
+ gatt.read(serviceUuid, characteristicUuid);
406
+ } else {
407
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
408
+ }
409
+ };
410
+
411
+ NobleBindings.prototype.onRead = function (address, serviceUuid, characteristicUuid, data) {
412
+ const uuid = address.split(':').join('').toLowerCase();
413
+
414
+ this.emit('read', uuid, serviceUuid, characteristicUuid, data, false);
415
+ };
416
+
417
+ NobleBindings.prototype.write = function (peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
418
+ const handle = this._handles[peripheralUuid];
419
+ const gatt = this._gatts[handle];
420
+
421
+ if (gatt) {
422
+ gatt.write(serviceUuid, characteristicUuid, data, withoutResponse);
423
+ } else {
424
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
425
+ }
426
+ };
427
+
428
+ NobleBindings.prototype.onWrite = function (address, serviceUuid, characteristicUuid) {
429
+ const uuid = address.split(':').join('').toLowerCase();
430
+
431
+ this.emit('write', uuid, serviceUuid, characteristicUuid);
432
+ };
433
+
434
+ NobleBindings.prototype.broadcast = function (peripheralUuid, serviceUuid, characteristicUuid, broadcast) {
435
+ const handle = this._handles[peripheralUuid];
436
+ const gatt = this._gatts[handle];
437
+
438
+ if (gatt) {
439
+ gatt.broadcast(serviceUuid, characteristicUuid, broadcast);
440
+ } else {
441
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
442
+ }
443
+ };
444
+
445
+ NobleBindings.prototype.onBroadcast = function (address, serviceUuid, characteristicUuid, state) {
446
+ const uuid = address.split(':').join('').toLowerCase();
447
+
448
+ this.emit('broadcast', uuid, serviceUuid, characteristicUuid, state);
449
+ };
450
+
451
+ NobleBindings.prototype.notify = function (peripheralUuid, serviceUuid, characteristicUuid, notify) {
452
+ const handle = this._handles[peripheralUuid];
453
+ const gatt = this._gatts[handle];
454
+
455
+ if (gatt) {
456
+ gatt.notify(serviceUuid, characteristicUuid, notify);
457
+ } else {
458
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
459
+ }
460
+ };
461
+
462
+ NobleBindings.prototype.onNotify = function (address, serviceUuid, characteristicUuid, state) {
463
+ const uuid = address.split(':').join('').toLowerCase();
464
+
465
+ this.emit('notify', uuid, serviceUuid, characteristicUuid, state);
466
+ };
467
+
468
+ NobleBindings.prototype.onNotification = function (address, serviceUuid, characteristicUuid, data) {
469
+ const uuid = address.split(':').join('').toLowerCase();
470
+
471
+ this.emit('read', uuid, serviceUuid, characteristicUuid, data, true);
472
+ };
473
+
474
+ NobleBindings.prototype.discoverDescriptors = function (peripheralUuid, serviceUuid, characteristicUuid) {
475
+ const handle = this._handles[peripheralUuid];
476
+ const gatt = this._gatts[handle];
477
+
478
+ if (gatt) {
479
+ gatt.discoverDescriptors(serviceUuid, characteristicUuid);
480
+ } else {
481
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
482
+ }
483
+ };
484
+
485
+ NobleBindings.prototype.onDescriptorsDiscovered = function (address, serviceUuid, characteristicUuid, descriptorUuids) {
486
+ const uuid = address.split(':').join('').toLowerCase();
487
+
488
+ this.emit('descriptorsDiscover', uuid, serviceUuid, characteristicUuid, descriptorUuids);
489
+ };
490
+
491
+ NobleBindings.prototype.readValue = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
492
+ const handle = this._handles[peripheralUuid];
493
+ const gatt = this._gatts[handle];
494
+
495
+ if (gatt) {
496
+ gatt.readValue(serviceUuid, characteristicUuid, descriptorUuid);
497
+ } else {
498
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
499
+ }
500
+ };
501
+
502
+ NobleBindings.prototype.onValueRead = function (address, serviceUuid, characteristicUuid, descriptorUuid, data) {
503
+ const uuid = address.split(':').join('').toLowerCase();
504
+
505
+ this.emit('valueRead', uuid, serviceUuid, characteristicUuid, descriptorUuid, data);
506
+ };
507
+
508
+ NobleBindings.prototype.writeValue = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
509
+ const handle = this._handles[peripheralUuid];
510
+ const gatt = this._gatts[handle];
511
+
512
+ if (gatt) {
513
+ gatt.writeValue(serviceUuid, characteristicUuid, descriptorUuid, data);
514
+ } else {
515
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
516
+ }
517
+ };
518
+
519
+ NobleBindings.prototype.onValueWrite = function (address, serviceUuid, characteristicUuid, descriptorUuid) {
520
+ const uuid = address.split(':').join('').toLowerCase();
521
+
522
+ this.emit('valueWrite', uuid, serviceUuid, characteristicUuid, descriptorUuid);
523
+ };
524
+
525
+ NobleBindings.prototype.readHandle = function (peripheralUuid, attHandle) {
526
+ const handle = this._handles[peripheralUuid];
527
+ const gatt = this._gatts[handle];
528
+
529
+ if (gatt) {
530
+ gatt.readHandle(attHandle);
531
+ } else {
532
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
533
+ }
534
+ };
535
+
536
+ NobleBindings.prototype.onHandleRead = function (address, handle, data) {
537
+ const uuid = address.split(':').join('').toLowerCase();
538
+
539
+ this.emit('handleRead', uuid, handle, data);
540
+ };
541
+
542
+ NobleBindings.prototype.writeHandle = function (peripheralUuid, attHandle, data, withoutResponse) {
543
+ const handle = this._handles[peripheralUuid];
544
+ const gatt = this._gatts[handle];
545
+
546
+ if (gatt) {
547
+ gatt.writeHandle(attHandle, data, withoutResponse);
548
+ } else {
549
+ console.warn(`noble warning: unknown peripheral ${peripheralUuid}`);
550
+ }
551
+ };
552
+
553
+ NobleBindings.prototype.onHandleWrite = function (address, handle) {
554
+ const uuid = address.split(':').join('').toLowerCase();
555
+
556
+ this.emit('handleWrite', uuid, handle);
557
+ };
558
+
559
+ NobleBindings.prototype.onHandleNotify = function (address, handle, data) {
560
+ const uuid = address.split(':').join('').toLowerCase();
561
+
562
+ this.emit('handleNotify', uuid, handle, data);
563
+ };
564
+
565
+ NobleBindings.prototype.onConnectionParameterUpdateRequest = function (handle, minInterval, maxInterval, latency, supervisionTimeout) {
566
+ this._hci.connUpdateLe(handle, minInterval, maxInterval, latency, supervisionTimeout);
567
+ };
568
+
569
+ module.exports = NobleBindings;
@@ -0,0 +1,70 @@
1
+ const debug = require('debug')('hci-serial-parser');
2
+ const { Transform } = require('stream');
3
+
4
+ const HCI_COMMAND_PKT = 0x01;
5
+ const HCI_ACLDATA_PKT = 0x02;
6
+ const HCI_EVENT_PKT = 0x04;
7
+
8
+ class HciSerialParser extends Transform {
9
+ constructor (options) {
10
+ super();
11
+ this.reset();
12
+ }
13
+
14
+ _transform (chunk, encoding, cb) {
15
+ this.packetData = Buffer.concat([this.packetData, chunk]);
16
+
17
+ debug('HciPacketParser._transform: ', this.packetData.toString('hex'));
18
+
19
+ if (this.packetType === -1) {
20
+ this.packetType = this.packetData.readUInt8(0);
21
+ }
22
+
23
+ if (this.listenerCount('raw') > 0) {
24
+ this.emit('raw', this.packetData);
25
+ }
26
+
27
+ let skipPacket = false;
28
+ while (this.packetData.length >= this.packetSize + this.prePacketSize && !skipPacket) {
29
+ if (this.packetSize === 0 && (this.packetType === HCI_EVENT_PKT || this.packetType === HCI_COMMAND_PKT) && this.packetData.length >= 3) {
30
+ this.packetSize = this.packetData.readUInt8(2);
31
+ this.prePacketSize = 3;
32
+ } else if (this.packetSize === 0 && this.packetType === HCI_ACLDATA_PKT && this.packetData.length >= 5) {
33
+ this.packetSize = this.packetData.readUInt16LE(3);
34
+ this.prePacketSize = 5;
35
+ }
36
+
37
+ if (this.packetData.length < this.packetSize + this.prePacketSize || this.packetSize == 0) {
38
+ skipPacket = true; continue;
39
+ }
40
+
41
+ this.push(this.packetData.subarray(0, this.packetSize + this.prePacketSize));
42
+
43
+ this.packetData = this.packetData.subarray(this.packetSize + this.prePacketSize);
44
+ this.packetSize = 0;
45
+ this.prePacketSize = 0;
46
+
47
+ if (this.packetData.length > 0) {
48
+ this.packetType = this.packetData.readUInt8(0);
49
+ } else {
50
+ this.packetType = -1;
51
+ }
52
+ }
53
+ cb();
54
+ }
55
+
56
+ reset () {
57
+ this.packetSize = 0;
58
+ this.prePacketSize = 0;
59
+ this.packetType = -1;
60
+ this.packetData = Buffer.alloc(0);
61
+ }
62
+
63
+ _flush (cb) {
64
+ this.emit('raw', this.packetData);
65
+ this.reset();
66
+ cb();
67
+ }
68
+ }
69
+
70
+ module.exports = HciSerialParser;