@stoprocent/bleno 0.8.5 → 0.9.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 (39) hide show
  1. package/README.md +197 -30
  2. package/examples/echo/async.js +47 -0
  3. package/examples/echo/characteristic.js +15 -17
  4. package/examples/echo/main.js +19 -1
  5. package/examples/uart/main.js +3 -2
  6. package/examples/with-bindings/main.js +35 -0
  7. package/index.d.ts +166 -121
  8. package/index.js +5 -1
  9. package/lib/bleno.js +108 -17
  10. package/lib/characteristic.js +27 -10
  11. package/lib/hci-socket/acl-stream.js +3 -3
  12. package/lib/hci-socket/bindings.js +36 -29
  13. package/lib/hci-socket/gatt.js +177 -105
  14. package/lib/hci-socket/hci.js +5 -3
  15. package/lib/hci-socket/mgmt.js +1 -1
  16. package/lib/hci-socket/smp.js +5 -4
  17. package/lib/mac/src/ble_peripheral_manager.h +3 -7
  18. package/lib/mac/src/ble_peripheral_manager.mm +117 -162
  19. package/lib/mac/src/bleno_mac.h +0 -1
  20. package/lib/mac/src/bleno_mac.mm +21 -33
  21. package/lib/mac/src/callbacks.h +12 -48
  22. package/lib/mac/src/callbacks.mm +34 -45
  23. package/lib/mac/src/napi_objc.mm +9 -30
  24. package/lib/mac/src/objc_cpp.h +2 -2
  25. package/lib/mac/src/objc_cpp.mm +3 -37
  26. package/lib/resolve-bindings.js +27 -6
  27. package/package.json +7 -9
  28. package/prebuilds/darwin-x64+arm64/@stoprocent+bleno.node +0 -0
  29. package/prebuilds/win32-ia32/@stoprocent+bleno.node +0 -0
  30. package/prebuilds/win32-x64/@stoprocent+bleno.node +0 -0
  31. package/test/characteristic.test.js +158 -11
  32. package/examples/battery-service/README.md +0 -14
  33. package/examples/blink1/README.md +0 -44
  34. package/examples/pizza/README.md +0 -16
  35. package/lib/mac/src/noble_mac.h +0 -34
  36. package/lib/mac/src/noble_mac.mm +0 -267
  37. package/lib/mac/src/peripheral.h +0 -23
  38. package/with-bindings.js +0 -5
  39. package/with-custom-binding.js +0 -6
@@ -68,18 +68,36 @@ class Gatt extends EventEmitter {
68
68
  super();
69
69
 
70
70
  this.maxMtu = 256;
71
- this._mtu = 23;
72
- this._preparedWriteRequest = null;
71
+
72
+ this._name = process.env.BLENO_DEVICE_NAME || os.hostname();
73
+ this._connections = new Map();
74
+ this._preparedWriteRequests = new Map();
75
+ this._aclStreamCallbacks = new Map();
76
+ this._lastIndicatedAttributes = new Map();
77
+ this._handles = [];
73
78
 
74
79
  this.setServices([]);
80
+ }
75
81
 
76
- this.onAclStreamDataBinded = this.onAclStreamData.bind(this);
77
- this.onAclStreamEndBinded = this.onAclStreamEnd.bind(this);
82
+ updateName (name) {
83
+ this._name = name;
84
+ let valueHandle = undefined;
85
+ for (let i = 0; i < this._handles.length; i++) {
86
+ //
87
+ if (typeof this._handles[i] !== 'object') continue;
88
+ // Update the value of the characteristic
89
+ if (this._handles[i].type === 'characteristic' && this._handles[i].uuid === '2a00') {
90
+ this._handles[i].attribute.value = Buffer.from(name);
91
+ valueHandle = this._handles[i].valueHandle;
92
+ }
93
+ // Update the value of the characteristic value
94
+ if (this._handles[i].type === 'characteristicValue' && this._handles[i].handle === valueHandle) {
95
+ this._handles[i].value = Buffer.from(name);
96
+ }
97
+ }
78
98
  }
79
99
 
80
100
  setServices (services) {
81
- const deviceName = process.env.BLENO_DEVICE_NAME || os.hostname();
82
-
83
101
  // base services and characteristics
84
102
  const allServices = [
85
103
  {
@@ -89,7 +107,7 @@ class Gatt extends EventEmitter {
89
107
  uuid: '2a00',
90
108
  properties: ['read'],
91
109
  secure: [],
92
- value: Buffer.from(deviceName),
110
+ value: Buffer.from(this._name),
93
111
  descriptors: []
94
112
  },
95
113
  {
@@ -213,7 +231,7 @@ class Gatt extends EventEmitter {
213
231
  attribute: characteristic,
214
232
  properties: (0x02 | 0x04 | 0x08), // read/write
215
233
  secure: (secure & 0x10) ? (0x02 | 0x04 | 0x08) : 0,
216
- value: Buffer.from([0x00, 0x00])
234
+ values: new Map()
217
235
  };
218
236
  }
219
237
 
@@ -255,43 +273,68 @@ class Gatt extends EventEmitter {
255
273
  debug('handles = ' + JSON.stringify(debugHandles, null, 2));
256
274
  }
257
275
 
258
- setAclStream (aclStream) {
259
- this._mtu = 23;
260
- this._preparedWriteRequest = null;
261
-
262
- this._aclStream = aclStream;
276
+ registerAclStream (aclStream, connection) {
277
+ this._connections.set(connection, {
278
+ aclStream,
279
+ mtu: 23,
280
+ });
281
+
282
+ this._aclStreamCallbacks.set(connection, {
283
+ onData: function (connection, cid, data) {
284
+ this.onAclStreamData(connection, cid, data);
285
+ },
286
+ onEnd: function (connection) {
287
+ this.onAclStreamEnd(connection);
288
+ }
289
+ });
263
290
 
264
- this._aclStream.on('data', this.onAclStreamDataBinded);
265
- this._aclStream.on('end', this.onAclStreamEndBinded);
291
+ aclStream.on('data', this._aclStreamCallbacks.get(connection).onData.bind(this));
292
+ aclStream.on('end', this._aclStreamCallbacks.get(connection).onEnd.bind(this));
266
293
  }
267
294
 
268
- onAclStreamData (cid, data) {
295
+ onAclStreamData (connection, cid, data) {
269
296
  if (cid !== ATT_CID) {
270
297
  return;
271
298
  }
272
299
 
273
- this.handleRequest(data);
300
+ this.handleRequest(data, connection);
274
301
  }
275
302
 
276
- onAclStreamEnd () {
277
- this._aclStream.removeListener('data', this.onAclStreamDataBinded);
278
- this._aclStream.removeListener('end', this.onAclStreamEndBinded);
303
+ onAclStreamEnd (connection) {
304
+ if (this._connections.has(connection) === false) {
305
+ return;
306
+ }
279
307
 
280
- for (let i = 0; i < this._handles.length; i++) {
281
- if (this._handles[i] && this._handles[i].type === 'descriptor' &&
282
- this._handles[i].uuid === '2902' && this._handles[i].value.readUInt16LE(0) !== 0) {
283
- this._handles[i].value = Buffer.from([0x00, 0x00]);
308
+ const { aclStream } = this._connections.get(connection);
309
+
310
+ aclStream.removeListener('data', this._aclStreamCallbacks.get(connection).onData);
311
+ aclStream.removeListener('end', this._aclStreamCallbacks.get(connection).onEnd);
284
312
 
313
+ // Clean up subscriptions for this connection
314
+ for (let i = 0; i < this._handles.length; i++) {
315
+ if (this._handles[i] &&
316
+ this._handles[i].type === 'descriptor' &&
317
+ this._handles[i].uuid === '2902' &&
318
+ this._handles[i].values &&
319
+ this._handles[i].values.has(connection)) {
320
+
321
+ this._handles[i].values.delete(connection);
322
+
285
323
  if (this._handles[i].attribute && this._handles[i].attribute.emit) {
286
- this._handles[i].attribute.emit('unsubscribe');
324
+ this._handles[i].attribute.emit('unsubscribe', connection);
287
325
  }
288
326
  }
289
327
  }
328
+
329
+ this._connections.delete(connection);
330
+ this._preparedWriteRequests.delete(connection);
290
331
  }
291
332
 
292
- send (data) {
333
+ send (data, connection) {
293
334
  debug('send: ' + data.toString('hex'));
294
- this._aclStream.write(ATT_CID, data);
335
+ if (this._connections.has(connection)) {
336
+ this._connections.get(connection).aclStream.write(ATT_CID, data);
337
+ }
295
338
  }
296
339
 
297
340
  errorResponse (opcode, handle, status) {
@@ -305,53 +348,53 @@ class Gatt extends EventEmitter {
305
348
  return buf;
306
349
  }
307
350
 
308
- handleRequest (request) {
309
- debug('handing request: ' + request.toString('hex'));
351
+ handleRequest (request, connection) {
352
+ debug('handling request: ' + request.toString('hex'));
310
353
 
311
354
  const requestType = request[0];
312
355
  let response = null;
313
356
 
314
357
  switch (requestType) {
315
358
  case ATT_OP_MTU_REQ:
316
- response = this.handleMtuRequest(request);
359
+ response = this.handleMtuRequest(request, connection);
317
360
  break;
318
361
 
319
362
  case ATT_OP_FIND_INFO_REQ:
320
- response = this.handleFindInfoRequest(request);
363
+ response = this.handleFindInfoRequest(request, connection);
321
364
  break;
322
365
 
323
366
  case ATT_OP_FIND_BY_TYPE_REQ:
324
- response = this.handleFindByTypeRequest(request);
367
+ response = this.handleFindByTypeRequest(request, connection);
325
368
  break;
326
369
 
327
370
  case ATT_OP_READ_BY_TYPE_REQ:
328
- response = this.handleReadByTypeRequest(request);
371
+ response = this.handleReadByTypeRequest(request, connection);
329
372
  break;
330
373
 
331
374
  case ATT_OP_READ_REQ:
332
375
  case ATT_OP_READ_BLOB_REQ:
333
- response = this.handleReadOrReadBlobRequest(request);
376
+ response = this.handleReadOrReadBlobRequest(request, connection);
334
377
  break;
335
378
 
336
379
  case ATT_OP_READ_BY_GROUP_REQ:
337
- response = this.handleReadByGroupRequest(request);
380
+ response = this.handleReadByGroupRequest(request, connection);
338
381
  break;
339
382
 
340
383
  case ATT_OP_WRITE_REQ:
341
384
  case ATT_OP_WRITE_CMD:
342
- response = this.handleWriteRequestOrCommand(request);
385
+ response = this.handleWriteRequestOrCommand(request, connection);
343
386
  break;
344
387
 
345
388
  case ATT_OP_PREP_WRITE_REQ:
346
- response = this.handlePrepareWriteRequest(request);
389
+ response = this.handlePrepareWriteRequest(request, connection);
347
390
  break;
348
391
 
349
392
  case ATT_OP_EXEC_WRITE_REQ:
350
- response = this.handleExecuteWriteRequest(request);
393
+ response = this.handleExecuteWriteRequest(request, connection);
351
394
  break;
352
395
 
353
396
  case ATT_OP_HANDLE_CNF:
354
- this.handleConfirmation(request);
397
+ this.handleConfirmation(request, connection);
355
398
  break;
356
399
 
357
400
  default:
@@ -361,12 +404,11 @@ class Gatt extends EventEmitter {
361
404
 
362
405
  if (response) {
363
406
  debug('response: ' + response.toString('hex'));
364
-
365
- this.send(response);
407
+ this.send(response, connection);
366
408
  }
367
409
  }
368
410
 
369
- handleMtuRequest (request) {
411
+ handleMtuRequest (request, connection) {
370
412
  let mtu = request.readUInt16LE(1);
371
413
 
372
414
  if (mtu < 23) {
@@ -375,9 +417,11 @@ class Gatt extends EventEmitter {
375
417
  mtu = this.maxMtu;
376
418
  }
377
419
 
378
- this._mtu = mtu;
420
+ if (this._connections.has(connection)) {
421
+ this._connections.get(connection).mtu = mtu;
422
+ }
379
423
 
380
- this.emit('mtuChange', this._mtu);
424
+ this.emit('mtuChange', mtu);
381
425
 
382
426
  const response = Buffer.alloc(3);
383
427
 
@@ -387,7 +431,9 @@ class Gatt extends EventEmitter {
387
431
  return response;
388
432
  }
389
433
 
390
- handleFindInfoRequest (request) {
434
+ handleFindInfoRequest (request, connection) {
435
+ const { mtu } = this._connections.get(connection);
436
+
391
437
  const startHandle = request.readUInt16LE(1);
392
438
  const endHandle = request.readUInt16LE(3);
393
439
 
@@ -435,7 +481,7 @@ class Gatt extends EventEmitter {
435
481
  }
436
482
 
437
483
  const lengthPerInfo = (uuidSize === 2) ? 4 : 18;
438
- const maxInfo = Math.floor((this._mtu - 2) / lengthPerInfo);
484
+ const maxInfo = Math.floor((mtu - 2) / lengthPerInfo);
439
485
  numInfo = Math.min(numInfo, maxInfo);
440
486
 
441
487
  const response = Buffer.alloc(2 + numInfo * lengthPerInfo);
@@ -459,7 +505,9 @@ class Gatt extends EventEmitter {
459
505
  return this.errorResponse(ATT_OP_FIND_INFO_REQ, startHandle, ATT_ECODE_ATTR_NOT_FOUND);
460
506
  }
461
507
 
462
- handleFindByTypeRequest (request) {
508
+ handleFindByTypeRequest (request, connection) {
509
+ const { mtu } = this._connections.get(connection);
510
+
463
511
  const startHandle = request.readUInt16LE(1);
464
512
  const endHandle = request.readUInt16LE(3);
465
513
  const uuid = request.slice(5, 7).toString('hex').match(/.{1,2}/g).reverse().join('');
@@ -486,7 +534,7 @@ class Gatt extends EventEmitter {
486
534
  if (handles.length) {
487
535
  const lengthPerHandle = 4;
488
536
  let numHandles = handles.length;
489
- const maxHandles = Math.floor((this._mtu - 1) / lengthPerHandle);
537
+ const maxHandles = Math.floor((mtu - 1) / lengthPerHandle);
490
538
 
491
539
  numHandles = Math.min(numHandles, maxHandles);
492
540
 
@@ -506,7 +554,9 @@ class Gatt extends EventEmitter {
506
554
  return this.errorResponse(ATT_OP_FIND_BY_TYPE_REQ, startHandle, ATT_ECODE_ATTR_NOT_FOUND);
507
555
  }
508
556
 
509
- handleReadByGroupRequest (request) {
557
+ handleReadByGroupRequest (request, connection) {
558
+ const { mtu } = this._connections.get(connection);
559
+
510
560
  const startHandle = request.readUInt16LE(1);
511
561
  const endHandle = request.readUInt16LE(3);
512
562
  const uuid = request.slice(5).toString('hex').match(/.{1,2}/g).reverse().join('');
@@ -541,7 +591,7 @@ class Gatt extends EventEmitter {
541
591
  }
542
592
 
543
593
  const lengthPerService = (uuidSize === 2) ? 6 : 20;
544
- const maxServices = Math.floor((this._mtu - 2) / lengthPerService);
594
+ const maxServices = Math.floor((mtu - 2) / lengthPerService);
545
595
  numServices = Math.min(numServices, maxServices);
546
596
 
547
597
  const response = Buffer.alloc(2 + numServices * lengthPerService);
@@ -569,7 +619,9 @@ class Gatt extends EventEmitter {
569
619
  return this.errorResponse(ATT_OP_READ_BY_GROUP_REQ, startHandle, ATT_ECODE_UNSUPP_GRP_TYPE);
570
620
  }
571
621
 
572
- handleReadByTypeRequest (request) {
622
+ handleReadByTypeRequest (request, connection) {
623
+ const { mtu } = this._connections.get(connection);
624
+
573
625
  let response = null;
574
626
  const requestType = request[0];
575
627
 
@@ -606,7 +658,7 @@ class Gatt extends EventEmitter {
606
658
  }
607
659
 
608
660
  const lengthPerCharacteristic = (uuidSize === 2) ? 7 : 21;
609
- const maxCharacteristics = Math.floor((this._mtu - 2) / lengthPerCharacteristic);
661
+ const maxCharacteristics = Math.floor((mtu - 2) / lengthPerCharacteristic);
610
662
  numCharacteristics = Math.min(numCharacteristics, maxCharacteristics);
611
663
 
612
664
  response = Buffer.alloc(2 + numCharacteristics * lengthPerCharacteristic);
@@ -653,15 +705,15 @@ class Gatt extends EventEmitter {
653
705
  }
654
706
  }
655
707
 
656
- if (secure && !this._aclStream.encrypted) {
708
+ if (secure && !this._connections.get(connection).aclStream.encrypted) {
657
709
  response = this.errorResponse(ATT_OP_READ_BY_TYPE_REQ, startHandle, ATT_ECODE_AUTHENTICATION);
658
710
  } else if (valueHandle) {
659
- const callback = (function (valueHandle) {
711
+ const callback = (function (requestType, valueHandle, connection) {
660
712
  return function (result, data) {
661
713
  let callbackResponse;
662
714
 
663
715
  if (ATT_ECODE_SUCCESS === result) {
664
- const dataLength = Math.min(data.length, this._mtu - 4);
716
+ const dataLength = Math.min(data.length, mtu - 4);
665
717
  callbackResponse = Buffer.alloc(4 + dataLength);
666
718
 
667
719
  callbackResponse[0] = ATT_OP_READ_BY_TYPE_RESP;
@@ -676,16 +728,22 @@ class Gatt extends EventEmitter {
676
728
 
677
729
  debug('read by type response: ' + callbackResponse.toString('hex'));
678
730
 
679
- this.send(callbackResponse);
731
+ this.send(callbackResponse, connection);
680
732
  }.bind(this);
681
- }.bind(this))(valueHandle);
733
+ }.bind(this))(requestType, valueHandle, connection);
682
734
 
683
- const data = this._handles[valueHandle].value;
735
+ let data = undefined;
736
+ if (this._handles[valueHandle].values && this._handles[valueHandle].values.has(connection)) {
737
+ data = this._handles[valueHandle].values.get(connection);
738
+ }
739
+ else {
740
+ data = this._handles[valueHandle].value;
741
+ }
684
742
 
685
743
  if (data) {
686
744
  callback(ATT_ECODE_SUCCESS, data);
687
745
  } else if (handleAttribute) {
688
- handleAttribute.emit('readRequest', 0, callback);
746
+ handleAttribute.emit('readRequest', connection, 0, callback);
689
747
  } else {
690
748
  callback(ATT_ECODE_UNLIKELY);
691
749
  }
@@ -697,7 +755,7 @@ class Gatt extends EventEmitter {
697
755
  return response;
698
756
  }
699
757
 
700
- handleReadOrReadBlobRequest (request) {
758
+ handleReadOrReadBlobRequest (request, connection) {
701
759
  let response = null;
702
760
 
703
761
  const requestType = request[0];
@@ -711,12 +769,13 @@ class Gatt extends EventEmitter {
711
769
  let data = null;
712
770
  const handleType = handle.type;
713
771
 
714
- const callback = (function (requestType, valueHandle) {
772
+ const callback = (function (requestType, valueHandle, connection) {
715
773
  return function (result, data) {
716
774
  let callbackResponse;
775
+ const { mtu } = this._connections.get(connection);
717
776
 
718
777
  if (ATT_ECODE_SUCCESS === result) {
719
- const dataLength = Math.min(data.length, this._mtu - 1);
778
+ const dataLength = Math.min(data.length, mtu - 1);
720
779
  callbackResponse = Buffer.alloc(1 + dataLength);
721
780
 
722
781
  callbackResponse[0] = (requestType === ATT_OP_READ_BLOB_REQ) ? ATT_OP_READ_BLOB_RESP : ATT_OP_READ_RESP;
@@ -729,9 +788,9 @@ class Gatt extends EventEmitter {
729
788
 
730
789
  debug('read response: ' + callbackResponse.toString('hex'));
731
790
 
732
- this.send(callbackResponse);
791
+ this.send(callbackResponse, connection);
733
792
  }.bind(this);
734
- }.bind(this))(requestType, valueHandle);
793
+ }.bind(this))(requestType, valueHandle, connection);
735
794
 
736
795
  if (handleType === 'service' || handleType === 'includedService') {
737
796
  result = ATT_ECODE_SUCCESS;
@@ -758,7 +817,7 @@ class Gatt extends EventEmitter {
758
817
  }
759
818
 
760
819
  if (handleProperties & 0x02) {
761
- if (handleSecure & 0x02 && !this._aclStream.encrypted) {
820
+ if (handleSecure & 0x02 && !this._connections.get(connection).aclStream.encrypted) {
762
821
  result = ATT_ECODE_AUTHENTICATION;
763
822
  } else {
764
823
  data = handle.value;
@@ -766,7 +825,7 @@ class Gatt extends EventEmitter {
766
825
  if (data) {
767
826
  result = ATT_ECODE_SUCCESS;
768
827
  } else {
769
- handleAttribute.emit('readRequest', offset, callback);
828
+ handleAttribute.emit('readRequest', connection, offset, callback);
770
829
  }
771
830
  }
772
831
  } else {
@@ -797,7 +856,7 @@ class Gatt extends EventEmitter {
797
856
  return response;
798
857
  }
799
858
 
800
- handleWriteRequestOrCommand (request) {
859
+ handleWriteRequestOrCommand (request, connection) {
801
860
  let response = null;
802
861
 
803
862
  const requestType = request[0];
@@ -817,7 +876,7 @@ class Gatt extends EventEmitter {
817
876
  const handleSecure = handle.secure;
818
877
 
819
878
  if (handleProperties && (withoutResponse ? (handleProperties & 0x04) : (handleProperties & 0x08))) {
820
- const callback = (function (requestType, valueHandle, withoutResponse) {
879
+ const callback = (function (requestType, valueHandle, withoutResponse, connection) {
821
880
  return function (result) {
822
881
  if (!withoutResponse) {
823
882
  let callbackResponse;
@@ -830,12 +889,12 @@ class Gatt extends EventEmitter {
830
889
 
831
890
  debug('write response: ' + callbackResponse.toString('hex'));
832
891
 
833
- this.send(callbackResponse);
892
+ this.send(callbackResponse, connection);
834
893
  }
835
894
  }.bind(this);
836
- }.bind(this))(requestType, valueHandle, withoutResponse);
895
+ }.bind(this))(requestType, valueHandle, withoutResponse, connection);
837
896
 
838
- if (handleSecure & (withoutResponse ? 0x04 : 0x08) && !this._aclStream.encrypted) {
897
+ if (handleSecure & (withoutResponse ? 0x04 : 0x08) && !this._connections.get(connection).aclStream.encrypted) {
839
898
  response = this.errorResponse(requestType, valueHandle, ATT_ECODE_AUTHENTICATION);
840
899
  } else if (handle.type === 'descriptor' || handle.uuid === '2902') {
841
900
  let result;
@@ -846,12 +905,18 @@ class Gatt extends EventEmitter {
846
905
  const value = data.readUInt16LE(0);
847
906
  const handleAttribute = handle.attribute;
848
907
 
849
- handle.value = data;
908
+ if (handle.values) {
909
+ handle.values.set(connection, data);
910
+ }
911
+ else {
912
+ handle.value = data;
913
+ }
850
914
 
851
915
  if (value & 0x0003) {
852
- const updateValueCallback = (function (valueHandle, attribute) {
916
+ const updateValueCallback = (function (valueHandle, attribute, connection) {
853
917
  return function (data) {
854
- const dataLength = Math.min(data.length, this._mtu - 3);
918
+ const { mtu } = this._connections.get(connection);
919
+ const dataLength = Math.min(data.length, mtu - 3);
855
920
  const useNotify = attribute.properties.indexOf('notify') !== -1;
856
921
  const useIndicate = attribute.properties.indexOf('indicate') !== -1;
857
922
 
@@ -866,9 +931,9 @@ class Gatt extends EventEmitter {
866
931
  }
867
932
 
868
933
  debug('notify message: ' + notifyMessage.toString('hex'));
869
- this.send(notifyMessage);
934
+ this.send(notifyMessage, connection);
870
935
 
871
- attribute.emit('notify');
936
+ attribute.emit('notify', connection);
872
937
  } else if (useIndicate) {
873
938
  const indicateMessage = Buffer.alloc(3 + dataLength);
874
939
 
@@ -879,20 +944,21 @@ class Gatt extends EventEmitter {
879
944
  indicateMessage[3 + i] = data[i];
880
945
  }
881
946
 
882
- this._lastIndicatedAttribute = attribute;
947
+ this._lastIndicatedAttributes.set(connection, attribute);
883
948
 
884
949
  debug('indicate message: ' + indicateMessage.toString('hex'));
885
- this.send(indicateMessage);
950
+ this.send(indicateMessage, connection);
886
951
  }
887
952
  }.bind(this);
888
- }.bind(this))(valueHandle - 1, handleAttribute);
953
+ }.bind(this))(valueHandle - 1, handleAttribute, connection);
889
954
 
890
955
  if (handleAttribute.emit) {
891
- handleAttribute.emit('subscribe', this._mtu - 3, updateValueCallback);
956
+ const { mtu } = this._connections.get(connection);
957
+ handleAttribute.emit('subscribe', connection, mtu - 3, updateValueCallback);
892
958
  }
893
959
  } else {
894
960
  if (handleAttribute.emit) {
895
- handleAttribute.emit('unsubscribe');
961
+ handleAttribute.emit('unsubscribe', connection);
896
962
  }
897
963
  }
898
964
 
@@ -901,7 +967,7 @@ class Gatt extends EventEmitter {
901
967
 
902
968
  callback(result);
903
969
  } else {
904
- handle.attribute.emit('writeRequest', data, offset, withoutResponse, callback);
970
+ handle.attribute.emit('writeRequest', connection, data, offset, withoutResponse, callback);
905
971
  }
906
972
  } else {
907
973
  response = this.errorResponse(requestType, valueHandle, ATT_ECODE_WRITE_NOT_PERM);
@@ -913,7 +979,7 @@ class Gatt extends EventEmitter {
913
979
  return response;
914
980
  }
915
981
 
916
- handlePrepareWriteRequest (request) {
982
+ handlePrepareWriteRequest (request, connection) {
917
983
  let response;
918
984
 
919
985
  const requestType = request[0];
@@ -931,14 +997,15 @@ class Gatt extends EventEmitter {
931
997
  const handleSecure = handle.secure;
932
998
 
933
999
  if (handleProperties && (handleProperties & 0x08)) {
934
- if ((handleSecure & 0x08) && !this._aclStream.encrypted) {
1000
+ if ((handleSecure & 0x08) && !this._connections.get(connection).aclStream.encrypted) {
935
1001
  response = this.errorResponse(requestType, valueHandle, ATT_ECODE_AUTHENTICATION);
936
- } else if (this._preparedWriteRequest) {
937
- if (this._preparedWriteRequest.handle !== handle) {
1002
+ } else if (this._preparedWriteRequests.has(connection)) {
1003
+ const preparedWriteRequest = this._preparedWriteRequests.get(connection);
1004
+ if (preparedWriteRequest.handle !== handle) {
938
1005
  response = this.errorResponse(requestType, valueHandle, ATT_ECODE_UNLIKELY);
939
- } else if (offset === (this._preparedWriteRequest.offset + this._preparedWriteRequest.data.length)) {
940
- this._preparedWriteRequest.data = Buffer.concat([
941
- this._preparedWriteRequest.data,
1006
+ } else if (offset === (preparedWriteRequest.offset + preparedWriteRequest.data.length)) {
1007
+ preparedWriteRequest.data = Buffer.concat([
1008
+ preparedWriteRequest.data,
942
1009
  data
943
1010
  ]);
944
1011
 
@@ -949,12 +1016,12 @@ class Gatt extends EventEmitter {
949
1016
  response = this.errorResponse(requestType, valueHandle, ATT_ECODE_INVALID_OFFSET);
950
1017
  }
951
1018
  } else {
952
- this._preparedWriteRequest = {
1019
+ this._preparedWriteRequests.set(connection, {
953
1020
  handle,
954
1021
  valueHandle,
955
1022
  offset,
956
1023
  data
957
- };
1024
+ });
958
1025
 
959
1026
  response = Buffer.alloc(request.length);
960
1027
  request.copy(response);
@@ -973,19 +1040,20 @@ class Gatt extends EventEmitter {
973
1040
  return response;
974
1041
  }
975
1042
 
976
- handleExecuteWriteRequest (request) {
1043
+ handleExecuteWriteRequest (request, connection) {
977
1044
  let response = null;
978
1045
 
979
1046
  const requestType = request[0];
980
1047
  const flag = request[1];
981
1048
 
982
- if (this._preparedWriteRequest) {
983
- const valueHandle = this._preparedWriteRequest.valueHandle;
1049
+ if (this._preparedWriteRequests.has(connection)) {
1050
+ const preparedWriteRequest = this._preparedWriteRequests.get(connection);
1051
+ const valueHandle = preparedWriteRequest.valueHandle;
984
1052
 
985
1053
  if (flag === 0x00) {
986
1054
  response = Buffer.from([ATT_OP_EXEC_WRITE_RESP]);
987
1055
  } else if (flag === 0x01) {
988
- const callback = (function (requestType, valueHandle) {
1056
+ const callback = (function (requestType, valueHandle, connection) {
989
1057
  return function (result) {
990
1058
  let callbackResponse;
991
1059
 
@@ -997,16 +1065,16 @@ class Gatt extends EventEmitter {
997
1065
 
998
1066
  debug('execute write response: ' + callbackResponse.toString('hex'));
999
1067
 
1000
- this.send(callbackResponse);
1068
+ this.send(callbackResponse, connection);
1001
1069
  }.bind(this);
1002
- }.bind(this))(requestType, this._preparedWriteRequest.valueHandle);
1070
+ }.bind(this))(requestType, valueHandle, connection);
1003
1071
 
1004
- this._preparedWriteRequest.handle.attribute.emit('writeRequest', this._preparedWriteRequest.data, this._preparedWriteRequest.offset, false, callback);
1072
+ preparedWriteRequest.handle.attribute.emit('writeRequest', connection, preparedWriteRequest.data, preparedWriteRequest.offset, false, callback);
1005
1073
  } else {
1006
1074
  response = this.errorResponse(requestType, 0x0000, ATT_ECODE_UNLIKELY);
1007
1075
  }
1008
1076
 
1009
- this._preparedWriteRequest = null;
1077
+ this._preparedWriteRequests.delete(connection);
1010
1078
  } else {
1011
1079
  response = this.errorResponse(requestType, 0x0000, ATT_ECODE_UNLIKELY);
1012
1080
  }
@@ -1014,14 +1082,18 @@ class Gatt extends EventEmitter {
1014
1082
  return response;
1015
1083
  }
1016
1084
 
1017
- handleConfirmation (request) {
1018
- if (this._lastIndicatedAttribute) {
1019
- if (this._lastIndicatedAttribute.emit) {
1020
- this._lastIndicatedAttribute.emit('indicate');
1021
- }
1085
+ handleConfirmation (request, connection) {
1086
+ if (this._lastIndicatedAttributes.has(connection) === false) {
1087
+ return;
1088
+ }
1022
1089
 
1023
- this._lastIndicatedAttribute = null;
1090
+ const lastIndicatedAttribute = this._lastIndicatedAttributes.get(connection);
1091
+ if (lastIndicatedAttribute.emit) {
1092
+ lastIndicatedAttribute.emit('indicate', connection);
1024
1093
  }
1094
+
1095
+ this._lastIndicatedAttributes.delete(connection);
1096
+ this._lastIndicatedAttributes.delete(connection);
1025
1097
  }
1026
1098
  }
1027
1099
 
@@ -1,8 +1,8 @@
1
1
  const debug = require('debug')('hci');
2
2
 
3
3
  const { EventEmitter } = require('events');
4
+ const { loadDriver } = require('@stoprocent/bluetooth-hci-socket');
4
5
 
5
- const BluetoothHciSocket = require('@stoprocent/bluetooth-hci-socket');
6
6
  const vendorSpecific = require('./vs');
7
7
 
8
8
  const HCI_COMMAND_PKT = 0x01;
@@ -77,10 +77,12 @@ const STATUS_MAPPER = require('./hci-status');
77
77
  class Hci extends EventEmitter {
78
78
  constructor (options) {
79
79
  super();
80
-
81
80
  options = options || {};
82
- this._manufacturer = null;
81
+
82
+ const BluetoothHciSocket = loadDriver(options.hciDriver || 'default');
83
83
  this._socket = new BluetoothHciSocket();
84
+
85
+ this._manufacturer = null;
84
86
  this._isDevUp = null;
85
87
  this._state = null;
86
88
  this._deviceId = null;
@@ -86,4 +86,4 @@ class Mgmt {
86
86
  }
87
87
  }
88
88
 
89
- module.exports = new Mgmt();
89
+ module.exports = Mgmt;