@stoprocent/noble 1.11.7 → 1.13.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.
package/binding.gyp CHANGED
@@ -1,4 +1,7 @@
1
1
  {
2
+ 'variables': {
3
+ 'openssl_fips' : ''
4
+ },
2
5
  'targets': [
3
6
  {
4
7
  'target_name': 'noble',
@@ -0,0 +1,28 @@
1
+ const noble = require('../with-custom-binding');
2
+
3
+ // Needs to export env: BLUETOOTH_HCI_SOCKET_FORCE_UART=1
4
+
5
+ const nobleUartA = noble({ bindParams: { uart: { port: '/dev/tty.usbmodem1...' } } });
6
+ const nobleUartB = noble({ bindParams: { uart: { port: '/dev/tty.usbmodem2...' } } });
7
+
8
+ nobleUartA.on('discover', peripheral => {
9
+ console.log('UART A', peripheral.address);
10
+ });
11
+
12
+ nobleUartB.on('discover', peripheral => {
13
+ console.log('UART B', peripheral.address);
14
+ });
15
+
16
+ nobleUartA.on('stateChange', state => {
17
+ if (state === 'poweredOn') {
18
+ nobleUartA.setAddress('00:11:22:33:44:01');
19
+ nobleUartA.startScanning();
20
+ }
21
+ });
22
+
23
+ nobleUartB.on('stateChange', state => {
24
+ if (state === 'poweredOn') {
25
+ nobleUartB.setAddress('00:11:22:33:44:02');
26
+ nobleUartB.startScanning();
27
+ }
28
+ });
@@ -34,6 +34,10 @@ NobleBindings.prototype.setScanParameters = function (interval, window) {
34
34
  this._gap.setScanParameters(interval, window);
35
35
  };
36
36
 
37
+ NobleBindings.prototype.setAddress = function (address) {
38
+ this._hci.setAddress(address);
39
+ };
40
+
37
41
  NobleBindings.prototype.startScanning = function (
38
42
  serviceUuids,
39
43
  allowDuplicates
@@ -4,6 +4,7 @@ const events = require('events');
4
4
  const util = require('util');
5
5
 
6
6
  const BluetoothHciSocket = require('@stoprocent/bluetooth-hci-socket');
7
+ const vendorSpecific = require('./vs');
7
8
 
8
9
  const HCI_COMMAND_PKT = 0x01;
9
10
  const HCI_ACLDATA_PKT = 0x02;
@@ -32,7 +33,6 @@ const OCF_DISCONNECT = 0x0006;
32
33
  const OGF_HOST_CTL = 0x03;
33
34
  const OCF_SET_EVENT_MASK = 0x0001;
34
35
  const OCF_RESET = 0x0003;
35
- const OCF_SET_RANDOM_MAC = 0x0005;
36
36
  const OCF_SET_PHY = 0x0031;
37
37
  const OCF_READ_LE_HOST_SUPPORTED = 0x006c;
38
38
  const OCF_WRITE_LE_HOST_SUPPORTED = 0x006d;
@@ -96,10 +96,12 @@ const STATUS_MAPPER = require('./hci-status');
96
96
 
97
97
  const Hci = function (options) {
98
98
  options = options || {};
99
+ this._manufacturer = null;
99
100
  this._socket = new BluetoothHciSocket();
100
101
  this._isDevUp = null;
101
102
  this._isExtended = 'extended' in options && options.extended;
102
103
  this._state = null;
104
+ this._bindParams = 'bindParams' in options ? options.bindParams : undefined;
103
105
 
104
106
  this._handleBuffers = {};
105
107
 
@@ -151,13 +153,13 @@ Hci.prototype.init = function (options) {
151
153
  this._socket.on('error', this.onSocketError.bind(this));
152
154
 
153
155
  if (this._userChannel) {
154
- this._socket.bindUser(this._deviceId);
156
+ this._socket.bindUser(this._deviceId, this._bindParams);
155
157
  this._socket.start();
156
158
 
157
159
  this.reset();
158
160
  } else {
159
161
  if (!this._bound) {
160
- this._socket.bindRaw(this._deviceId);
162
+ this._socket.bindRaw(this._deviceId, this._bindParams);
161
163
  this._bound = true;
162
164
  }
163
165
  this._socket.start();
@@ -218,26 +220,20 @@ Hci.prototype.setCodedPhySupport = function () {
218
220
  this._socket.write(cmd);
219
221
  };
220
222
 
221
- Hci.prototype.setRandomMAC = function () {
222
- const cmd = Buffer.alloc(10);
223
+ Hci.prototype.setAddress = function (address) {
224
+ // Command
225
+ const addrCmd = vendorSpecific.setAddressCmd(this._manufacturer, address);
223
226
 
224
- // header
225
- cmd.writeUInt8(HCI_COMMAND_PKT, 0);
226
- cmd.writeUInt16LE(OCF_SET_RANDOM_MAC | (OGF_LE_CTL << 10), 1);
227
+ if (addrCmd !== null && Buffer.isBuffer(addrCmd)) {
228
+ // Make Command Buffer
229
+ const cmd = Buffer.alloc(1 + addrCmd.byteLength);
230
+ cmd.writeUInt8(HCI_COMMAND_PKT, 0);
231
+ addrCmd.copy(cmd, 1);
227
232
 
228
- // length
229
- cmd.writeUInt8(0x06, 3);
230
-
231
- // data
232
- cmd.writeUInt8(0x05, 4); // mac 6 byte
233
- cmd.writeUInt8(0x04, 5); // mac 5 byte
234
- cmd.writeUInt8(0x03, 6); // mac 4 byte
235
- cmd.writeUInt8(0x02, 7); // mac 3 byte
236
- cmd.writeUInt8(0x01, 8); // mac 2 byte
237
- cmd.writeUInt8(0x00, 9); // mac 1 byte
238
-
239
- debug(`set random mac address - writing: ${cmd.toString('hex')}`);
240
- this._socket.write(cmd);
233
+ debug(`set address - writing: ${cmd.toString('hex')}`);
234
+ this._socket.write(cmd);
235
+ this.readBdAddr();
236
+ }
241
237
  };
242
238
 
243
239
  Hci.prototype.setSocketFilter = function () {
@@ -938,6 +934,9 @@ Hci.prototype.processCmdCompleteEvent = function (cmd, status, result) {
938
934
  this.setScanParameters();
939
935
  }
940
936
 
937
+ // Update manufacturer
938
+ this._manufacturer = manufacturer;
939
+
941
940
  this.emit(
942
941
  'readLocalVersion',
943
942
  hciVer,
@@ -0,0 +1,156 @@
1
+ // This file is based on the bluez implementation
2
+ // https://github.com/bluez/bluez/blob/master/tools/bdaddr.c
3
+
4
+ const OGF_VENDOR_CMD = 0x3f;
5
+
6
+ const OCF_ERICSSON_WRITE_BD_ADDR = 0x000d;
7
+ const OCF_TI_WRITE_BD_ADDR = 0x0006;
8
+ const OCF_LINUX_FOUNDATION_WRITE_BD_ADDR = 0x0006;
9
+ const OCF_BCM_WRITE_BD_ADDR = 0x0001;
10
+ const OCF_ZEEVO_WRITE_BD_ADDR = 0x0001;
11
+ const OCF_MRVL_WRITE_BD_ADDR = 0x0022;
12
+ const OCF_ERICSSON_STORE_IN_FLASH = 0x0022;
13
+ const ERICSSON_STORE_IN_FLASH_CP_SIZE = 0xFF;
14
+
15
+ function parseAddress (address) {
16
+ // Parse MAC Address as in 00:00:00:00:00:00 into Buffer (needs to reverse byte order)
17
+ const macAddress = Buffer.from(address.split(':').reverse().join(''), 'hex');
18
+
19
+ if (Buffer.isBuffer(macAddress) && macAddress.byteLength !== 6) {
20
+ throw new Error('Invalid MAC Address. Should be formated as 00:00:00:00:00:00 string.');
21
+ }
22
+
23
+ return macAddress;
24
+ }
25
+
26
+ // eslint-disable-next-line camelcase
27
+ function csr_write_bd_addr (address) {
28
+ // Parse MAC Address
29
+ const macAddress = parseAddress(address);
30
+
31
+ if (macAddress === null) {
32
+ return null;
33
+ }
34
+
35
+ // Base command
36
+ const base = Buffer.from([
37
+ 0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
38
+ 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
39
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
40
+ ]);
41
+
42
+ // Command
43
+ const cmd = Buffer.alloc(3 + base.byteLength);
44
+
45
+ cmd.writeUInt16LE(0x00 | OGF_VENDOR_CMD << 10, 0);
46
+ cmd.writeUInt8(0xC2, 2);
47
+
48
+ base.writeUint8(macAddress.readUInt8(2), 16);
49
+ base.writeUint8(0x00, 17);
50
+ base.writeUint8(macAddress.readUInt8(0), 18);
51
+ base.writeUint8(macAddress.readUInt8(1), 19);
52
+ base.writeUint8(macAddress.readUInt8(3), 20);
53
+ base.writeUint8(0x00, 21);
54
+ base.writeUint8(macAddress.readUInt8(4), 22);
55
+ base.writeUint8(macAddress.readUInt8(5), 23);
56
+ base.copy(cmd, 3);
57
+
58
+ return cmd;
59
+ }
60
+
61
+ // eslint-disable-next-line camelcase
62
+ function ericsson_store_in_flash (user_id, data) {
63
+ // Check Data
64
+ if (Buffer.isBuffer(data) === false || data.byteLength > OCF_ERICSSON_STORE_IN_FLASH - 2) {
65
+ return null;
66
+ }
67
+
68
+ // Command
69
+ const cmd = Buffer.alloc(3 + ERICSSON_STORE_IN_FLASH_CP_SIZE);
70
+
71
+ cmd.writeUInt16LE(OCF_ERICSSON_STORE_IN_FLASH | OGF_VENDOR_CMD << 10, 0);
72
+ cmd.writeUInt8(ERICSSON_STORE_IN_FLASH_CP_SIZE, 2);
73
+ cmd.writeUInt8(user_id, 3); // user_id
74
+ cmd.writeUInt8(data.byteLength, 4); // flash_length
75
+ data.copy(cmd, 5); // flash_data
76
+
77
+ return cmd;
78
+ }
79
+
80
+ // eslint-disable-next-line camelcase
81
+ function st_write_bd_addr (address) {
82
+ // Parse MAC Address
83
+ const macAddress = parseAddress(address);
84
+
85
+ if (macAddress === null) {
86
+ return null;
87
+ }
88
+
89
+ return ericsson_store_in_flash(0xFE, macAddress);
90
+ }
91
+
92
+ // eslint-disable-next-line camelcase
93
+ function mrvl_write_bd_addr (address) {
94
+ // Parse MAC Address
95
+ const macAddress = parseAddress(address);
96
+
97
+ if (macAddress === null) {
98
+ return null;
99
+ }
100
+
101
+ // Command
102
+ const cmd = Buffer.alloc(11);
103
+
104
+ cmd.writeUInt16LE(OCF_MRVL_WRITE_BD_ADDR | OGF_VENDOR_CMD << 10, 0);
105
+ cmd.writeUInt8(0x08, 2);
106
+ cmd.writeUInt8(0xFE, 3); // parameter_id
107
+ cmd.writeUInt8(0x06, 4); // bdaddr_len
108
+ macAddress.copy(cmd, 5); // bdaddr
109
+
110
+ return cmd;
111
+ }
112
+
113
+ // eslint-disable-next-line camelcase
114
+ function write_common_bd_addr (OCF_VS_WRITE_BD_ADDR) {
115
+ // Return a function
116
+ return (address) => {
117
+ // Parse MAC Address
118
+ const macAddress = parseAddress(address);
119
+
120
+ if (macAddress === null) {
121
+ return null;
122
+ }
123
+
124
+ // Command
125
+ const cmd = Buffer.alloc(9);
126
+
127
+ cmd.writeUInt16LE(OCF_VS_WRITE_BD_ADDR | OGF_VENDOR_CMD << 10, 0);
128
+ cmd.writeUInt8(0x06, 2);
129
+ macAddress.copy(cmd, 3); // bdaddr
130
+
131
+ return cmd;
132
+ };
133
+ }
134
+
135
+ const vendors = new Map();
136
+
137
+ vendors.set(0, write_common_bd_addr(OCF_ERICSSON_WRITE_BD_ADDR));
138
+ vendors.set(10, csr_write_bd_addr);
139
+ vendors.set(13, write_common_bd_addr(OCF_TI_WRITE_BD_ADDR));
140
+ vendors.set(15, write_common_bd_addr(OCF_BCM_WRITE_BD_ADDR));
141
+ vendors.set(18, write_common_bd_addr(OCF_ZEEVO_WRITE_BD_ADDR));
142
+ vendors.set(48, st_write_bd_addr);
143
+ vendors.set(57, write_common_bd_addr(OCF_ERICSSON_WRITE_BD_ADDR));
144
+ vendors.set(72, mrvl_write_bd_addr);
145
+ vendors.set(1521, write_common_bd_addr(OCF_LINUX_FOUNDATION_WRITE_BD_ADDR));
146
+
147
+ module.exports = {
148
+ // Vendor Specific Set Address
149
+ setAddressCmd: (manufacturer, address) => {
150
+ const generateCommand = vendors.get(manufacturer);
151
+ if (typeof generateCommand === 'function') {
152
+ return generateCommand(address) || null;
153
+ }
154
+ return null;
155
+ }
156
+ };
@@ -1,26 +1,38 @@
1
1
  {
2
+ 'variables': {
3
+ 'openssl_fips' : ''
4
+ },
2
5
  'targets': [
3
6
  {
4
7
  'target_name': 'binding',
5
- 'sources': [ 'src/noble_mac.mm', 'src/napi_objc.mm', 'src/ble_manager.mm', 'src/objc_cpp.mm', 'src/callbacks.cc' ],
6
- 'include_dirs': ["<!@(node -p \"require('node-addon-api').include\")"],
7
- 'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"],
8
+ 'sources': [
9
+ 'src/noble_mac.mm',
10
+ 'src/napi_objc.mm',
11
+ 'src/ble_manager.mm',
12
+ 'src/objc_cpp.mm',
13
+ 'src/callbacks.cc'
14
+ ],
15
+ 'include_dirs': [
16
+ "<!(node -p \"require('node-addon-api').include_dir\")"
17
+ ],
8
18
  'cflags!': [ '-fno-exceptions' ],
9
19
  'cflags_cc!': [ '-fno-exceptions' ],
20
+ "defines": ["NAPI_CPP_EXCEPTIONS"],
10
21
  'xcode_settings': {
11
22
  'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
23
+ 'MACOSX_DEPLOYMENT_TARGET': '10.9',
12
24
  'CLANG_CXX_LIBRARY': 'libc++',
13
- 'MACOSX_DEPLOYMENT_TARGET': '10.7',
14
25
  'OTHER_CFLAGS': [
15
- '-fobjc-arc',
26
+ '-fobjc-arc',
27
+ '-arch x86_64',
28
+ '-arch arm64'
16
29
  ],
17
- },
18
- 'link_settings': {
19
- 'libraries': [
20
- '$(SDKROOT)/System/Library/Frameworks/CoreBluetooth.framework',
30
+ 'OTHER_LDFLAGS': [
31
+ '-framework CoreBluetooth',
32
+ '-arch x86_64',
33
+ '-arch arm64'
21
34
  ]
22
- },
23
- 'product_dir': '../lib/mac/native',
35
+ }
24
36
  }
25
37
  ]
26
38
  }
package/lib/noble.js CHANGED
@@ -110,6 +110,14 @@ Noble.prototype.onScanParametersSet = function () {
110
110
  this.emit('scanParametersSet');
111
111
  };
112
112
 
113
+ Noble.prototype.setAddress = function (address) {
114
+ if (this._bindings.setAddress) {
115
+ this._bindings.setAddress(address);
116
+ } else {
117
+ this.emit('warning', 'current binding does not implement setAddress method.');
118
+ }
119
+ };
120
+
113
121
  const startScanning = function (serviceUuids, allowDuplicates, callback) {
114
122
  if (typeof serviceUuids === 'function') {
115
123
  this.emit('warning', 'calling startScanning(callback) is deprecated');
@@ -1,22 +1,42 @@
1
1
  {
2
+ 'variables': {
3
+ 'openssl_fips' : ''
4
+ },
2
5
  'targets': [
3
6
  {
4
7
  'target_name': 'binding',
5
- 'sources': [ 'src/noble_winrt.cc', 'src/napi_winrt.cc', 'src/peripheral_winrt.cc', 'src/radio_watcher.cc', 'src/notify_map.cc', 'src/ble_manager.cc', 'src/winrt_cpp.cc', 'src/winrt_guid.cc', 'src/callbacks.cc' ],
6
- 'include_dirs': ["<!@(node -p \"require('node-addon-api').include\")", "<!@(node -p \"require('napi-thread-safe-callback').include\")"],
7
- 'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"],
8
+ 'sources': [
9
+ 'src/noble_winrt.cc',
10
+ 'src/napi_winrt.cc',
11
+ 'src/peripheral_winrt.cc',
12
+ 'src/radio_watcher.cc',
13
+ 'src/notify_map.cc',
14
+ 'src/ble_manager.cc',
15
+ 'src/winrt_cpp.cc',
16
+ 'src/winrt_guid.cc',
17
+ 'src/callbacks.cc'
18
+ ],
19
+ 'include_dirs': [
20
+ "<!(node -p \"require('node-addon-api').include_dir\")",
21
+ "<!@(node -p \"require('napi-thread-safe-callback').include\")"
22
+ ],
8
23
  'cflags!': [ '-fno-exceptions' ],
9
24
  'cflags_cc!': [ '-fno-exceptions' ],
10
25
  'msvs_settings': {
11
26
  'VCCLCompilerTool': {
12
27
  'ExceptionHandling': 1,
13
- 'AdditionalOptions': ['/await', '/std:c++latest'],
28
+ 'AdditionalOptions': [
29
+ '/await',
30
+ '/std:c++latest'
31
+ ],
14
32
  },
15
33
  },
16
34
  'msvs_target_platform_version':'10.0.18362.0',
17
35
  'msvs_target_platform_minversion':'10.0.18362.0',
18
36
  'conditions': [
19
- ['OS=="win"', { 'defines': [ '_HAS_EXCEPTIONS=1' ] }]
37
+ ['OS=="win"', {
38
+ 'defines': [ '_HAS_EXCEPTIONS=1' ]
39
+ }]
20
40
  ],
21
41
  }
22
42
  ]
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
- "author": "Sandeep Mistry",
2
+ "author": "Sandeep Mistry <sandeep.mistry@gmail.com>",
3
3
  "maintainers": [
4
- "Jacob Rosenthal",
5
- "Luis Montes"
4
+ "Marek Serafin <marek@serafin.email>"
6
5
  ],
7
6
  "license": "MIT",
8
7
  "name": "@stoprocent/noble",
9
8
  "description": "A Node.js BLE (Bluetooth Low Energy) central library.",
10
- "version": "1.11.7",
9
+ "version": "1.13.0",
11
10
  "repository": {
12
11
  "type": "git",
13
12
  "url": "https://github.com/stoprocent/noble.git"
@@ -28,12 +27,6 @@
28
27
  "engines": {
29
28
  "node": ">=6"
30
29
  },
31
- "os": [
32
- "darwin",
33
- "linux",
34
- "freebsd",
35
- "win32"
36
- ],
37
30
  "dependencies": {
38
31
  "debug": "^4.3.4",
39
32
  "napi-thread-safe-callback": "^0.0.6",
@@ -41,9 +34,10 @@
41
34
  "node-gyp-build": "^4.5.0"
42
35
  },
43
36
  "optionalDependencies": {
44
- "@stoprocent/bluetooth-hci-socket": "^0.6.4"
37
+ "@stoprocent/bluetooth-hci-socket": "^1.1.2"
45
38
  },
46
39
  "devDependencies": {
40
+ "@semantic-release/exec": "^6.0.3",
47
41
  "async": "^3.2.4",
48
42
  "cross-env": "^7.0.3",
49
43
  "eslint": "^8.31.0",
@@ -53,12 +47,13 @@
53
47
  "eslint-plugin-n": "^15.6.0",
54
48
  "eslint-plugin-promise": "^6.1.1",
55
49
  "mocha": "^10.2.0",
56
- "node-gyp": "^9.3.1",
50
+ "node-gyp": "^9.4.0",
57
51
  "nyc": "^15.1.0",
58
52
  "prebuildify": "^5.0.1",
59
- "prebuildify-ci": "^1.0.5",
53
+ "prebuildify-cross": "5.0.0",
60
54
  "prettier": "^2.8.1",
61
55
  "proxyquire": "^2.1.3",
56
+ "semantic-release": "21.1.0",
62
57
  "should": "~13.2.3",
63
58
  "sinon": "^15.0.1",
64
59
  "ws": "^8.11.0"
@@ -67,11 +62,9 @@
67
62
  "install": "node-gyp-build",
68
63
  "lint": "eslint \"**/*.js\"",
69
64
  "lint-fix": "eslint \"**/*.js\" --fix",
70
- "prebuild": "prebuildify --napi --strip",
71
- "prebuild-darwin": "prebuildify --napi --strip --arch x64+arm64",
72
- "prebuild-win32": "prebuildify --napi --strip",
73
- "prebuild-linux": "prebuildify --napi --strip",
74
- "prebuild-download": "prebuildify-ci download",
65
+ "prebuildify": "prebuildify --napi --target 14.0.0 --force --strip --verbose",
66
+ "prebuildify-cross": "prebuildify-cross --napi --target 14.0.0 --force --strip --verbose",
67
+ "semantic-release": "semantic-release",
75
68
  "pretest": "npm run rebuild",
76
69
  "rebuild": "node-gyp rebuild",
77
70
  "coverage": "nyc npm test && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
@@ -80,9 +73,7 @@
80
73
  "browser": {
81
74
  "./lib/resolve-bindings.js": "./lib/resolve-bindings-web.js"
82
75
  },
83
- "binary": {
84
- "napi_versions": [
85
- 4
86
- ]
76
+ "publishConfig": {
77
+ "access": "public"
87
78
  }
88
79
  }
@@ -22,6 +22,7 @@ describe('hci-socket hci', () => {
22
22
  Socket.prototype.isDevUp = sinon.stub();
23
23
  Socket.prototype.removeAllListeners = sinon.stub();
24
24
  Socket.prototype.setFilter = sinon.stub();
25
+ Socket.prototype.setAddress = sinon.stub();
25
26
  Socket.prototype.write = sinon.stub();
26
27
 
27
28
  hci = new Hci({});
@@ -43,7 +44,7 @@ describe('hci-socket hci', () => {
43
44
  assert.calledWithMatch(hci._socket.on, 'data', sinon.match.func);
44
45
  assert.calledWithMatch(hci._socket.on, 'error', sinon.match.func);
45
46
 
46
- assert.calledOnceWithExactly(hci._socket.bindUser, deviceId);
47
+ assert.calledOnceWithExactly(hci._socket.bindUser, deviceId, undefined);
47
48
  assert.calledOnceWithExactly(hci._socket.start);
48
49
 
49
50
  assert.calledOnceWithExactly(hci.reset);
@@ -60,7 +61,7 @@ describe('hci-socket hci', () => {
60
61
  assert.calledWithMatch(hci._socket.on, 'data', sinon.match.func);
61
62
  assert.calledWithMatch(hci._socket.on, 'error', sinon.match.func);
62
63
 
63
- assert.calledOnceWithExactly(hci._socket.bindRaw, deviceId);
64
+ assert.calledOnceWithExactly(hci._socket.bindRaw, deviceId, undefined);
64
65
  assert.calledOnceWithExactly(hci._socket.start);
65
66
 
66
67
  assert.calledOnceWithExactly(hci.pollIsDevUp);
@@ -230,11 +231,6 @@ describe('hci-socket hci', () => {
230
231
  assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x31, 0x20, 0x03, 0x00, 0x05, 0x05]));
231
232
  });
232
233
 
233
- it('should write randomMAC command', () => {
234
- hci.setRandomMAC();
235
- assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x05, 0x20, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00]));
236
- });
237
-
238
234
  it('should setSocketFilter', () => {
239
235
  hci.setSocketFilter();
240
236
  assert.calledOnceWithExactly(hci._socket.setFilter, Buffer.from([0x16, 0, 0, 0, 0x20, 0xc1, 0x08, 0, 0, 0, 0, 0x40, 0, 0]));
@@ -270,6 +266,50 @@ describe('hci-socket hci', () => {
270
266
  assert.calledOnceWithExactly(hci._socket.write, Buffer.from([1, 9, 0x10, 0]));
271
267
  });
272
268
 
269
+ describe('setAddress', () => {
270
+ it('should write vendor specific (Linux Foundation) command based on read local version response', () => {
271
+ hci.readBdAddr = sinon.spy();
272
+ hci.setScanEnabled = sinon.spy();
273
+ hci.setScanParameters = sinon.spy();
274
+
275
+ const cmd = 4097;
276
+ const status = 0;
277
+ // hciVer=12, hciRev=0, lmpVer=12, manufacturer=1521, lmpSubVer=65535
278
+ const result = Buffer.from([0x0C, 0x00, 0x00, 0x0C, 0xF1, 0x05, 0xFF, 0xFF]);
279
+
280
+ hci.processCmdCompleteEvent(cmd, status, result);
281
+
282
+ hci.setAddress('11:22:33:44:55:66');
283
+ assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x06, 0xfc, 0x06, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]));
284
+ });
285
+
286
+ it('should write vendor specific (Ericsson) command based on manufacturer value (', () => {
287
+ hci._manufacturer = 0;
288
+ hci.readBdAddr = sinon.spy();
289
+ hci.setAddress('11:22:33:44:55:66');
290
+ assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x0d, 0xfc, 0x06, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]));
291
+ });
292
+
293
+ it('should write vendor specific (Texas Instrument) command based on manufacturer value', () => {
294
+ hci._manufacturer = 13;
295
+ hci.readBdAddr = sinon.spy();
296
+ hci.setAddress('11:22:33:44:55:66');
297
+ assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x06, 0xfc, 0x06, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]));
298
+ });
299
+
300
+ it('should write vendor specific (BCM) command based on manufacturer value', () => {
301
+ hci._manufacturer = 15;
302
+ hci.readBdAddr = sinon.spy();
303
+ hci.setAddress('11:22:33:44:55:66');
304
+ assert.calledOnceWithExactly(hci._socket.write, Buffer.from([0x01, 0x01, 0xfc, 0x06, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]));
305
+ });
306
+
307
+ it('should not write vendor specific command', () => {
308
+ hci.setAddress('11:22:33:44:55:66');
309
+ assert.notCalled(hci._socket.write);
310
+ });
311
+ });
312
+
273
313
  describe('setLeEventMask', () => {
274
314
  it('should setLeEventMask', () => {
275
315
  hci.setLeEventMask();
@@ -0,0 +1,25 @@
1
+ const should = require('should');
2
+ const sinon = require('sinon');
3
+ const proxyquire = require('proxyquire').noCallThru();
4
+
5
+ const fakeOs = {};
6
+ const { assert } = sinon;
7
+ const vendorSpecific = proxyquire('../../../lib/hci-socket/vs', { os: fakeOs });
8
+
9
+ describe('hci-socket vs', () => {
10
+ afterEach(() => {
11
+ sinon.reset();
12
+ });
13
+
14
+ describe('parseAddress', () => {
15
+ it('should convert to Buffer', () => {
16
+ assert.match(vendorSpecific.setAddressCmd(0, '00:11:22:33:44:55').slice(3), Buffer.from([0x55, 0x44, 0x33, 0x22, 0x11, 0x00]));
17
+ });
18
+
19
+ it('should not convert to Buffer and throw an Error', () => {
20
+ should.throws(function () {
21
+ vendorSpecific.setAddressCmd(0, '00:11:22:33:44');
22
+ });
23
+ });
24
+ });
25
+ });
package/.eslintrc.js DELETED
@@ -1,25 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- extends: ['eslint:recommended', 'semistandard'],
4
- parserOptions: {
5
- ecmaVersion: 2017
6
- },
7
- env: {
8
- browser: true,
9
- mocha: true,
10
- node: true
11
- },
12
- globals: {
13
- Promise: true
14
- },
15
- rules: {
16
- 'space-before-function-paren': ['error', 'always'],
17
- 'no-unused-vars': [
18
- 'error',
19
- {
20
- args: 'none'
21
- }
22
- ],
23
- semi: 'error'
24
- }
25
- };
@@ -1,2 +0,0 @@
1
- github: [rzr]
2
- custom: ["https://www.paypal.me/rzrfreefr", www.rzr.online.fr]
@@ -1,16 +0,0 @@
1
- # YAML
2
- ---
3
- name: fediverse-action
4
- on: [push]
5
- jobs:
6
- post:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/checkout@v3
10
- - id: log
11
- run: echo "::set-output name=message::$(git log --no-merges -1 --oneline)"
12
- - if: "contains(steps.log.outputs.message, 'Release ')"
13
- uses: rzr/fediverse-action@master
14
- with:
15
- access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }}
16
- message: "https://github.com/${{ github.repository }}/commit/${{ steps.log.outputs.message }} ~ #FediVerseAction"
@@ -1,68 +0,0 @@
1
- name: Node.js package
2
-
3
- on:
4
- pull_request:
5
- branches:
6
- - master
7
- push:
8
- branches:
9
- - master
10
-
11
- jobs:
12
- build:
13
- runs-on: ${{ matrix.os }}
14
- strategy:
15
- matrix:
16
- os: [ubuntu-20.04, ubuntu-latest, macos-latest, windows-2019]
17
- node: [12, 14, 16, 18]
18
- steps:
19
- - uses: actions/checkout@v3
20
- - uses: actions/setup-node@v3
21
- with:
22
- node-version: ${{ matrix.node }}
23
- - name: Install dependencies (ubuntu-latest)
24
- if: ${{ matrix.os == 'ubuntu-latest' }}
25
- run: |
26
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
27
- sudo apt -qq update
28
- sudo apt install -y g++-9
29
- export CC="g++-9"
30
- - name: Install NPM packages
31
- run: |
32
- npm install
33
- - name: Run tests
34
- run: |
35
- npm test
36
- - name: Lint
37
- run: |
38
- npm run lint
39
-
40
- quality:
41
- name: Quality phase
42
- runs-on: ubuntu-latest
43
- steps:
44
- - name: ⬇️ Checkout code
45
- uses: actions/checkout@v3
46
- - name: 💽 Setup nodejs
47
- uses: actions/setup-node@v3
48
- with:
49
- node-version: '14'
50
- - name: 📇 Use npm cache
51
- uses: c-hive/gha-npm-cache@v1
52
- - name: Install dependencies (ubuntu-latest)
53
- run: |
54
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
55
- sudo apt -qq update
56
- sudo apt install -y g++-9
57
- export CC="g++-9"
58
- - name: 📦 Install NPM packages
59
- run: |
60
- npm install
61
- - name: ✅ Test with coverage
62
- run: |
63
- npm run coverage
64
- - name: 📄 Codecov report upload
65
- uses: codecov/codecov-action@v2
66
- with:
67
- fail_ci_if_error: true
68
- file: .nyc_output/lcov.info
@@ -1,26 +0,0 @@
1
- name: npm-publish
2
- on:
3
- push:
4
- branches:
5
- - master # Change this to your default branch
6
- jobs:
7
- npm-publish:
8
- name: npm-publish
9
- runs-on: ubuntu-latest
10
- steps:
11
- - uses: actions/checkout@master
12
- - id: log
13
- run: echo "::set-output name=message::$(git log --no-merges -1 --oneline)"
14
- - if: "contains(steps.log.outputs.message, 'Release ')"
15
- uses: actions/setup-node@master
16
- with:
17
- node-version: 16.0.0
18
- - if: "contains(steps.log.outputs.message, 'Release ')"
19
- uses: pascalgn/npm-publish-action@1.3.9
20
- with: # All of these inputs are optional
21
- tag_name: "v%s"
22
- tag_message: "v%s"
23
- commit_pattern: "^Release (\\S+)"
24
- env: # More info about the environment variables in the README
25
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Leave this as is, it's automatically generated
26
- NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} # You need to set this in your repo settings
@@ -1,66 +0,0 @@
1
- name: prebuild
2
-
3
- on:
4
- push:
5
- branches:
6
- - master
7
- tags:
8
- - '*'
9
- pull_request:
10
- branches:
11
- - master
12
- workflow_dispatch:
13
-
14
- jobs:
15
- prebuild:
16
- strategy:
17
- matrix:
18
- include:
19
- - name: darwin
20
- os: macos-11
21
- node: x64
22
- - name: linux
23
- os: ubuntu-latest
24
- - name: win32
25
- os: windows-2019
26
- name: Build ${{ matrix.name }}
27
- runs-on: ${{ matrix.os }}
28
- steps:
29
- - if: matrix.node
30
- uses: actions/setup-node@v3
31
- with:
32
- node-version: 14.x
33
- architecture: ${{ matrix.node }}
34
- - uses: actions/checkout@v3
35
- - name: Install dependencies (ubuntu-latest)
36
- # Use g++-9 only on versions after 'ubuntu-18.04'
37
- if: ${{ matrix.os == 'ubuntu-latest' }}
38
- run: |
39
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
40
- sudo apt -qq update
41
- sudo apt install -y g++-9
42
- export CC="g++-9"
43
- - run: npm install --ignore-scripts
44
- - run: npm run prebuild-${{ matrix.name }}
45
- - run: tar -zcvf ${{ matrix.name }}.tar.gz -C prebuilds .
46
- - uses: actions/upload-artifact@v2
47
- with:
48
- name: ${{ matrix.name }}
49
- path: ${{ matrix.name }}.tar.gz
50
- retention-days: 1
51
- release:
52
- needs: prebuild
53
- name: Release
54
- runs-on: ubuntu-latest
55
- if: startsWith(github.ref, 'refs/tags/')
56
- steps:
57
- - uses: actions/checkout@v3
58
- - uses: actions/download-artifact@v2
59
- with:
60
- path: artifacts
61
- - uses: docker://antonyurchenko/git-release:v4
62
- env:
63
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64
- ALLOW_EMPTY_CHANGELOG: true
65
- with:
66
- args: artifacts/*/*.tar.gz
package/CHANGELOG.md DELETED
@@ -1,119 +0,0 @@
1
- ## Version 1.9.1
2
-
3
- * Don't forget previously discovered services and characteristics ([@elafargue](https://github.com/elafargue))
4
- * Fixed peripheral-explorer example with newer async versions
5
- * web socket binding: various fixes ([@hadrienk](https://github.com/hadrienk))
6
- * Fix multiple init of bindings with multiple stateChange listeners added or noble.state is accessed
7
-
8
- ## Version 1.9.0
9
-
10
- * Don't initialize bindings until first state change listener added
11
- * webble: hooked up disconnect event
12
- * webble: clear cached services on reconnect
13
- * hci-socket: Added upport 32-bit and 128-bit service data UUIDs ([@arekzelechowski](https://github.com/arekzelechowski))
14
- * Update 'connectable' property upon discovery ([@dimitrisx](https://github.com/dimitrisx))
15
- * macOS: Added support for High Sierra
16
- * webble: remove subscribe listeners on disconnect
17
-
18
- ## Version 1.8.1
19
-
20
- * easier install instructions for Windows ([@don](https://github.com/don))
21
- * hci-socket binding: more descriptive error outputs ([@mbifulco](https://github.com/mbifulco))
22
- * hci-socket binding: report non-connectable advertisements without scan response
23
- * Corrected deprecated `read` event for characteristics no emitting for notifications
24
-
25
- ## Version 1.8.0
26
-
27
- * hci-socket binding: always set scan parameters before scanning ([@Lahorde](https://github.com/Lahorde))
28
- * hci-socket binding: add L2CAP signaling layer for non-Linux or Linux user channel mode
29
- * hci-socket binding: Workarounds for scanning with N.T.C. C.H.I.P
30
- * hci-socket binding: if `init()` fails we don't want to try and clear up ([@gfwilliams](https://github.com/gfwilliams))
31
- * Fix read events firing for notifications ([@zkiiito](https://github.com/zkiiito))
32
- * Add FreeBSD support ([@myfreeweb](https://github.com/myfreeweb))
33
- * Fix startScanning callback calling setting error to try ([@MarSoft](https://github.com/MarSoft))
34
- * New Web Bluetooth API shim ([@monteslu](https://github.com/monteslu))
35
-
36
- ## Version 1.7.0
37
-
38
- * hci-socket binding: now supports "long writes" ([@projectgus](https://github.com/projectgus))
39
- * hci-socket binding: use latest bluetooth-hci-socket dependency (~0.5.1)
40
- * hci-socket binding: add support to extract service solicitation UUID's from advertisement ([@smartyw](https://github.com/smartyw))
41
- * web-socket binding: fixed write handle not working ([@christopherhex](https://github.com/christopherhex))
42
- * hci-socket binding: initial bindUser support via HCI_CHANNEL_USER environment variable
43
-
44
- ## Version 1.6.0
45
-
46
- * hci-socket binding: use latest bluetooth-hci-socket dependency (~0.4.4)
47
- * Added characteristic.subscribe and characteristic.unsubscribe API's (characteristic.notify is now deprecated)
48
- * hci-socket binding: use OCF_LE_SET_EVENT_MASK for LE_SET_EVENT_MASK_CMD
49
- * hci-socket binding: check READ_LE_HOST_SUPPORTED_CMD status before parsing result
50
-
51
- ## Version 1.5.0
52
-
53
- * hci-socket binding: add NOBLE_MULTI_ROLE flag for ignoring peripheral role commands ([@popasquat89](https://github.com/bradjc))
54
- * Fix variable typo in ```with-bindings.js`` ([@rclai](https://github.com/rclai))
55
-
56
- ## Version 1.4.0
57
-
58
- * hci-socket binding: include service data UUID's when filtering discover
59
- * hci-socket binding: emit scan start/stop when external app changes scanning start ([@bradjc](https://github.com/bradjc))
60
- * Support for pluggable bindings ([@hgwood](https://github.com/hgwood))
61
- * hci-socket binding: don't kill all descriptors when looking for new Characteristics ([@Neutrosider](https://github.com/Neutrosider))
62
-
63
- ## Version 1.3.0
64
-
65
- * Check and report LE Create Conn command status
66
- * Correct parsing master clock accuracy value from LE Conn Complete event
67
- * Added logic to reject rather than ignore unknown requests/commands. ([@george-hawkins](https://github.com/george-hawkins))
68
- * Don't reset scan state on read local version response if state is powered on
69
- * Expose local adapter address via ```noble.address```, available after ```poweredOn``` state change event
70
- * Fix ```serviceUuids``` var check in ```peripheral-explorer.js``` ([@jrobeson](https://github.com/jrobeson))
71
-
72
- ## Version 1.2.1
73
-
74
- * Use latest v0.4.1 bluetooth-hci-socket dependency (for kernel 4.1.x disconnect workaround)
75
- * Add read + write LE host supported commands (for kernel 4.1.x disconnect workaround)
76
- * Fix a potential exception when accessing a non existent element ([@Loghorn](https://github.com/Loghorn))
77
-
78
- ## Version 1.2.0
79
-
80
- * Use v0.4.0 of bluetooth-hci-socket
81
- * Ignore peripherals with only connectable flag on OS X 10.10
82
- * Bindings no longer init themselves
83
- * Fix this._discoveredPeripheralUUids = []; variable not initalized in constructor ([@jacobrosenthal](https://github.com/jacobrosenthal))
84
- * New ```peripheral.connectable``` property
85
- * Updates to Linux prerequisites in read me
86
- * Throw error if scanning is started when state is not powered on
87
-
88
- ## Version 1.1.0
89
-
90
- * Introduce ```peripheral.id```, ```periheral.uuid``` is deprecated now
91
- * Initial Windows support via WinUSB and bluetooth-hci-socket
92
- * Rework Linux stack to use [bluetooth-hci-socket](https://github.com/sandeepmistry/node-bluetooth-hci-socket)
93
- * Clarify notify related API's in read me ([@OJFord](https://github.com/OJFord))
94
-
95
- ## Version 1.0.2
96
-
97
- * Add mac dummy in binding.pyq ([@DomiR](https://github.com/DomiR))
98
- * Fixes for distributed and websocket bindings ([@Loghorn](https://github.com/Loghorn))
99
- * OS X Mavericks and legacy: manually emit write event for write without response requests
100
- * Update README for packages needed for rpm-based systems ([@ppannuto](https://github.com/ppannuto))
101
- * Linux: refresh serviceUuids for incoming advertisement ([@BBarash](https://github.com/BBarash))
102
-
103
- ## Version 1.0.1
104
-
105
- * correct peripherals not being created correctly
106
-
107
- ## Version 1.0
108
-
109
- * remove unneeded setTimeout's in OS X bindings
110
- * added persistent peripherals between calls to .startScanning() on mavericks ([@andySigler](https://github.com/andySigler))
111
- * report error or print warning if startScanning is called with state is not poweredOn
112
- * emit events for warnings ([@voodootikigod ](https://github.com/voodootikigod))
113
- * disable scanning flag on start on Linux to prevent unsupport adapter state in some cases
114
- * update debug dependency version
115
- * add address type to peripheral if known
116
-
117
- ## Older
118
-
119
- * Changes not recorded
package/MAINTAINERS.md DELETED
@@ -1 +0,0 @@
1
- * Philippe Coval <mailto:p.coval@samsung.com> (https://www.npmjs.com/~rzr)
package/test.js DELETED
@@ -1,131 +0,0 @@
1
- const noble = require('./index');
2
-
3
- console.log('noble');
4
-
5
- noble.on('stateChange', function (state) {
6
- console.log('on -> stateChange: ' + state);
7
-
8
- if (state === 'poweredOn') {
9
- noble.startScanning([], true);
10
- } else {
11
- noble.stopScanning();
12
- }
13
- });
14
-
15
- noble.on('scanStart', function () {
16
- console.log('on -> scanStart');
17
- });
18
-
19
- noble.on('scanStop', function () {
20
- console.log('on -> scanStop');
21
- });
22
-
23
- noble.on('discover', function (peripheral) {
24
- console.log('on -> discover: ' + peripheral);
25
-
26
- noble.stopScanning();
27
-
28
- peripheral.on('connect', function () {
29
- console.log('on -> connect');
30
- this.updateRssi();
31
- });
32
-
33
- peripheral.on('disconnect', function () {
34
- console.log('on -> disconnect');
35
- });
36
-
37
- peripheral.on('rssiUpdate', function (rssi) {
38
- console.log('on -> RSSI update ' + rssi);
39
- this.discoverServices();
40
- });
41
-
42
- peripheral.on('servicesDiscover', function (services) {
43
- console.log('on -> peripheral services discovered ' + services);
44
-
45
- const serviceIndex = 0;
46
-
47
- services[serviceIndex].on(
48
- 'includedServicesDiscover',
49
- function (includedServiceUuids) {
50
- console.log(
51
- 'on -> service included services discovered ' + includedServiceUuids
52
- );
53
- this.discoverCharacteristics();
54
- }
55
- );
56
-
57
- services[serviceIndex].on(
58
- 'characteristicsDiscover',
59
- function (characteristics) {
60
- console.log(
61
- 'on -> service characteristics discovered ' + characteristics
62
- );
63
-
64
- const characteristicIndex = 0;
65
-
66
- characteristics[characteristicIndex].on(
67
- 'read',
68
- function (data, isNotification) {
69
- console.log(
70
- 'on -> characteristic read ' + data + ' ' + isNotification
71
- );
72
- console.log(data);
73
-
74
- peripheral.disconnect();
75
- }
76
- );
77
-
78
- characteristics[characteristicIndex].on('write', function () {
79
- console.log('on -> characteristic write ');
80
-
81
- peripheral.disconnect();
82
- });
83
-
84
- characteristics[characteristicIndex].on('broadcast', function (state) {
85
- console.log('on -> characteristic broadcast ' + state);
86
-
87
- peripheral.disconnect();
88
- });
89
-
90
- characteristics[characteristicIndex].on('notify', function (state) {
91
- console.log('on -> characteristic notify ' + state);
92
-
93
- peripheral.disconnect();
94
- });
95
-
96
- characteristics[characteristicIndex].on(
97
- 'descriptorsDiscover',
98
- function (descriptors) {
99
- console.log('on -> descriptors discover ' + descriptors);
100
-
101
- const descriptorIndex = 0;
102
-
103
- descriptors[descriptorIndex].on('valueRead', function (data) {
104
- console.log('on -> descriptor value read ' + data);
105
- console.log(data);
106
- peripheral.disconnect();
107
- });
108
-
109
- descriptors[descriptorIndex].on('valueWrite', function () {
110
- console.log('on -> descriptor value write ');
111
- peripheral.disconnect();
112
- });
113
-
114
- descriptors[descriptorIndex].readValue();
115
- // descriptors[descriptorIndex].writeValue(new Buffer([0]));
116
- }
117
- );
118
-
119
- characteristics[characteristicIndex].read();
120
- // characteristics[characteristicIndex].write(new Buffer('hello'));
121
- // characteristics[characteristicIndex].broadcast(true);
122
- // characteristics[characteristicIndex].notify(true);
123
- // characteristics[characteristicIndex].discoverDescriptors();
124
- }
125
- );
126
-
127
- services[serviceIndex].discoverIncludedServices();
128
- });
129
-
130
- peripheral.connect();
131
- });