@stoprocent/noble 1.15.1 → 1.16.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/examples/peripheral-explorer-async.js +16 -4
- package/index.d.ts +1 -0
- package/lib/hci-socket/bindings.js +7 -5
- package/lib/hci-socket/hci.js +40 -11
- package/lib/noble.js +9 -1
- package/lib/win/binding.gyp +1 -1
- package/package.json +3 -3
- package/prebuilds/darwin-x64+arm64/@stoprocent+noble.node +0 -0
- package/prebuilds/linux-x64/@stoprocent+noble.musl.node +0 -0
- package/prebuilds/win32-ia32/@stoprocent+noble.node +0 -0
- package/prebuilds/win32-x64/@stoprocent+noble.node +0 -0
- package/test/lib/hci-socket/bindings.test.js +22 -5
- package/test/lib/hci-socket/hci.test.js +78 -15
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
const noble = require('../');
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const directConnect = process.argv[2].toLowerCase();
|
|
4
|
+
const peripheralIdOrAddress = process.argv[3].toLowerCase();
|
|
5
|
+
|
|
6
|
+
const starTime = Date.now();
|
|
4
7
|
|
|
5
8
|
noble.on('stateChange', async (state) => {
|
|
6
9
|
if (state === 'poweredOn') {
|
|
7
|
-
|
|
10
|
+
if (directConnect === '1') {
|
|
11
|
+
await noble.stopScanningAsync();
|
|
12
|
+
await noble.connectAsync(peripheralIdOrAddress.replace(/:/g, ''))
|
|
13
|
+
} else {
|
|
14
|
+
await noble.startScanningAsync();
|
|
15
|
+
}
|
|
8
16
|
}
|
|
9
17
|
});
|
|
10
18
|
|
|
11
19
|
noble.on('discover', async (peripheral) => {
|
|
12
20
|
if ([peripheral.id, peripheral.address].includes(peripheralIdOrAddress)) {
|
|
13
21
|
await noble.stopScanningAsync();
|
|
14
|
-
|
|
22
|
+
|
|
15
23
|
console.log(`Peripheral with ID ${peripheral.id} found`);
|
|
16
24
|
const advertisement = peripheral.advertisement;
|
|
17
25
|
|
|
@@ -59,7 +67,9 @@ const explore = async (peripheral) => {
|
|
|
59
67
|
process.exit(0);
|
|
60
68
|
});
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
if (peripheral.state !== 'connected') {
|
|
71
|
+
await peripheral.connectAsync();
|
|
72
|
+
}
|
|
63
73
|
|
|
64
74
|
const services = await peripheral.discoverServicesAsync([]);
|
|
65
75
|
|
|
@@ -114,7 +124,9 @@ const explore = async (peripheral) => {
|
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
|
|
127
|
+
console.log(`Time taken: ${Date.now() - starTime}ms`);
|
|
117
128
|
await peripheral.disconnectAsync();
|
|
129
|
+
|
|
118
130
|
};
|
|
119
131
|
|
|
120
132
|
process.on('SIGINT', function () {
|
package/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare function connect(peripheralUuid: string, options?: object, callba
|
|
|
29
29
|
export declare function connectAsync(peripheralUuid: string, options?: object): Promise<Peripheral>;
|
|
30
30
|
export declare function cancelConnect(peripheralUuid: string, options?: object): void;
|
|
31
31
|
export declare function reset(): void;
|
|
32
|
+
export declare function stop(): void;
|
|
32
33
|
|
|
33
34
|
export declare function setAddress(address: string): void;
|
|
34
35
|
|
|
@@ -53,11 +53,12 @@ NobleBindings.prototype.stopScanning = function () {
|
|
|
53
53
|
|
|
54
54
|
NobleBindings.prototype.connect = function (peripheralUuid, parameters) {
|
|
55
55
|
let address = this._addresses[peripheralUuid];
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
let addressType = this._addresseTypes[peripheralUuid] || 'random'; // Default to 'random' if type is not defined
|
|
57
|
+
|
|
58
58
|
// If address is not available, generate it from the UUID using the transformation logic inline
|
|
59
59
|
if (!address) {
|
|
60
60
|
address = peripheralUuid.match(/.{1,2}/g).join(':'); // Converts UUID back to MAC address format
|
|
61
|
+
addressType = (parseInt(address.slice(0, 2).slice(0,2), 16) & 0x02) === 0 ? 'public' : 'random';
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// Manage connection attempts
|
|
@@ -113,7 +114,7 @@ NobleBindings.prototype.init = function () {
|
|
|
113
114
|
is present it can throw an exception - in which case we don't
|
|
114
115
|
want to try and clear up afterwards (issue #502) */
|
|
115
116
|
process.on('SIGINT', this.onSigIntBinded);
|
|
116
|
-
process.on('exit', this.
|
|
117
|
+
process.on('exit', this.stop.bind(this));
|
|
117
118
|
};
|
|
118
119
|
|
|
119
120
|
NobleBindings.prototype.onSigInt = function () {
|
|
@@ -126,12 +127,13 @@ NobleBindings.prototype.onSigInt = function () {
|
|
|
126
127
|
}
|
|
127
128
|
};
|
|
128
129
|
|
|
129
|
-
NobleBindings.prototype.
|
|
130
|
+
NobleBindings.prototype.stop = function () {
|
|
130
131
|
this.stopScanning();
|
|
131
|
-
|
|
132
132
|
for (const handle in this._aclStreams) {
|
|
133
133
|
this._hci.disconnect(handle);
|
|
134
134
|
}
|
|
135
|
+
this._hci.reset();
|
|
136
|
+
this._hci.stop();
|
|
135
137
|
};
|
|
136
138
|
|
|
137
139
|
NobleBindings.prototype.onStateChange = function (state) {
|
package/lib/hci-socket/hci.js
CHANGED
|
@@ -49,6 +49,7 @@ const OCF_READ_RSSI = 0x0005;
|
|
|
49
49
|
const OGF_LE_CTL = 0x08;
|
|
50
50
|
const OCF_LE_SET_EVENT_MASK = 0x0001;
|
|
51
51
|
const OCF_LE_READ_BUFFER_SIZE = 0x0002;
|
|
52
|
+
const OCF_LE_READ_LOCAL_SUPPORTED_FEATURES = 0x0003;
|
|
52
53
|
const OCF_LE_SET_EXTENDED_SCAN_PARAMETERS = 0x0041;
|
|
53
54
|
const OCF_LE_SET_EXTENDED_SCAN_ENABLE = 0x0042;
|
|
54
55
|
const OCF_LE_SET_SCAN_PARAMETERS = 0x000b;
|
|
@@ -77,6 +78,7 @@ const READ_RSSI_CMD = OCF_READ_RSSI | (OGF_STATUS_PARAM << 10);
|
|
|
77
78
|
|
|
78
79
|
const LE_SET_EVENT_MASK_CMD = OCF_LE_SET_EVENT_MASK | (OGF_LE_CTL << 10);
|
|
79
80
|
const LE_READ_BUFFER_SIZE_CMD = OCF_LE_READ_BUFFER_SIZE | (OGF_LE_CTL << 10);
|
|
81
|
+
const LE_READ_LOCAL_SUPPORTED_FEATURES = OCF_LE_READ_LOCAL_SUPPORTED_FEATURES | (OGF_LE_CTL << 10);
|
|
80
82
|
const LE_SET_EXTENDED_SCAN_PARAMETERS_CMD =
|
|
81
83
|
OCF_LE_SET_EXTENDED_SCAN_PARAMETERS | (OGF_LE_CTL << 10);
|
|
82
84
|
const LE_SET_EXTENDED_SCAN_ENABLE_CMD =
|
|
@@ -164,7 +166,8 @@ Hci.prototype.init = function (options) {
|
|
|
164
166
|
this._bound = true;
|
|
165
167
|
}
|
|
166
168
|
this._socket.start();
|
|
167
|
-
|
|
169
|
+
|
|
170
|
+
this.reset();
|
|
168
171
|
this.pollIsDevUp();
|
|
169
172
|
}
|
|
170
173
|
};
|
|
@@ -181,17 +184,9 @@ Hci.prototype.pollIsDevUp = function () {
|
|
|
181
184
|
return;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
|
-
if (this._isExtended) {
|
|
185
|
-
this.setCodedPhySupport();
|
|
186
|
-
}
|
|
187
187
|
this.setSocketFilter();
|
|
188
|
-
this.
|
|
189
|
-
|
|
190
|
-
this.readLocalVersion();
|
|
191
|
-
this.writeLeHostSupported();
|
|
192
|
-
this.readLeHostSupported();
|
|
193
|
-
this.readLeBufferSize();
|
|
194
|
-
this.readBdAddr();
|
|
188
|
+
this.readLeSupportedFeatures();
|
|
189
|
+
// Subsequent calls moved to processCmdCompleteEvent for LE_READ_LOCAL_SUPPORTED_FEATURES
|
|
195
190
|
} else {
|
|
196
191
|
this.emit('stateChange', 'poweredOff');
|
|
197
192
|
}
|
|
@@ -290,6 +285,10 @@ Hci.prototype.reset = function () {
|
|
|
290
285
|
this._socket.write(cmd);
|
|
291
286
|
};
|
|
292
287
|
|
|
288
|
+
Hci.prototype.stop = function () {
|
|
289
|
+
this._socket.stop();
|
|
290
|
+
};
|
|
291
|
+
|
|
293
292
|
Hci.prototype.readSupportedCommands = function () {
|
|
294
293
|
const cmd = Buffer.alloc(4);
|
|
295
294
|
|
|
@@ -365,6 +364,20 @@ Hci.prototype.setLeEventMask = function () {
|
|
|
365
364
|
this._socket.write(cmd);
|
|
366
365
|
};
|
|
367
366
|
|
|
367
|
+
Hci.prototype.readLeSupportedFeatures = function () {
|
|
368
|
+
const cmd = Buffer.alloc(4);
|
|
369
|
+
|
|
370
|
+
// header
|
|
371
|
+
cmd.writeUInt8(HCI_COMMAND_PKT, 0);
|
|
372
|
+
cmd.writeUInt16LE(LE_READ_LOCAL_SUPPORTED_FEATURES, 1);
|
|
373
|
+
|
|
374
|
+
// length
|
|
375
|
+
cmd.writeUInt8(0x0, 3);
|
|
376
|
+
|
|
377
|
+
debug(`le read supported feature - writing: ${cmd.toString('hex')}`);
|
|
378
|
+
this._socket.write(cmd);
|
|
379
|
+
};
|
|
380
|
+
|
|
368
381
|
Hci.prototype.readLeBufferSize = function () {
|
|
369
382
|
const cmd = Buffer.alloc(4);
|
|
370
383
|
|
|
@@ -913,6 +926,22 @@ Hci.prototype.processCmdCompleteEvent = function (cmd, status, result) {
|
|
|
913
926
|
this.setLeEventMask();
|
|
914
927
|
this.readLocalVersion();
|
|
915
928
|
this.readBdAddr();
|
|
929
|
+
} else if (cmd === LE_READ_LOCAL_SUPPORTED_FEATURES) {
|
|
930
|
+
if (status === 0) {
|
|
931
|
+
const featuresLow = result.readUInt32LE(0);
|
|
932
|
+
this._isExtended = (featuresLow & (1 << 6)) !== 0;
|
|
933
|
+
|
|
934
|
+
if (this._isExtended) {
|
|
935
|
+
this.setCodedPhySupport();
|
|
936
|
+
}
|
|
937
|
+
this.setEventMask();
|
|
938
|
+
this.setLeEventMask();
|
|
939
|
+
this.readLocalVersion();
|
|
940
|
+
this.writeLeHostSupported();
|
|
941
|
+
this.readLeHostSupported();
|
|
942
|
+
this.readLeBufferSize();
|
|
943
|
+
this.readBdAddr();
|
|
944
|
+
}
|
|
916
945
|
} else if (cmd === READ_LE_HOST_SUPPORTED_CMD) {
|
|
917
946
|
if (status === 0) {
|
|
918
947
|
const le = result.readUInt8(0);
|
package/lib/noble.js
CHANGED
|
@@ -190,7 +190,15 @@ Noble.prototype.onScanStop = function () {
|
|
|
190
190
|
};
|
|
191
191
|
|
|
192
192
|
Noble.prototype.reset = function () {
|
|
193
|
-
this._bindings.reset
|
|
193
|
+
if (this._bindings.reset) {
|
|
194
|
+
this._bindings.reset();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
Noble.prototype.stop = function () {
|
|
199
|
+
if (this._bindings.stop) {
|
|
200
|
+
this._bindings.stop();
|
|
201
|
+
}
|
|
194
202
|
};
|
|
195
203
|
|
|
196
204
|
Noble.prototype.onDiscover = function (uuid, address, addressType, connectable, advertisement, rssi, scannable) {
|
package/lib/win/binding.gyp
CHANGED
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"name": "@stoprocent/noble",
|
|
8
8
|
"description": "A Node.js BLE (Bluetooth Low Energy) central library.",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.16.0",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/stoprocent/noble.git"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"node-gyp-build": "^4.8.1"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@stoprocent/bluetooth-hci-socket": "^1.4.
|
|
37
|
+
"@stoprocent/bluetooth-hci-socket": "^1.4.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@commitlint/cli": "^19.3.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"mocha": "^10.7.0",
|
|
53
53
|
"nyc": "^17.0.0",
|
|
54
54
|
"prebuildify": "^6.0.1",
|
|
55
|
-
"prebuildify-cross": "
|
|
55
|
+
"prebuildify-cross": "^5.1.1",
|
|
56
56
|
"semantic-release": "^24.1.1",
|
|
57
57
|
"jshint": "^2.13.6",
|
|
58
58
|
"prettier": "^3.3.3",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -132,7 +132,7 @@ describe('hci-socket bindings', () => {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
describe('connect', () => {
|
|
135
|
-
it('missing peripheral, no queue', () => {
|
|
135
|
+
it('missing peripheral, no queue, public address', () => {
|
|
136
136
|
bindings._hci.createLeConn = fake.resolves(null);
|
|
137
137
|
|
|
138
138
|
bindings.connect('112233445566', 'parameters');
|
|
@@ -140,7 +140,18 @@ describe('hci-socket bindings', () => {
|
|
|
140
140
|
should(bindings._pendingConnectionUuid).eql('112233445566');
|
|
141
141
|
|
|
142
142
|
assert.calledOnce(bindings._hci.createLeConn);
|
|
143
|
-
assert.calledWith(bindings._hci.createLeConn, '11:22:33:44:55:66', '
|
|
143
|
+
assert.calledWith(bindings._hci.createLeConn, '11:22:33:44:55:66', 'public', 'parameters');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('missing peripheral, no queue, random address', () => {
|
|
147
|
+
bindings._hci.createLeConn = fake.resolves(null);
|
|
148
|
+
|
|
149
|
+
bindings.connect('f32233445566', 'parameters');
|
|
150
|
+
|
|
151
|
+
should(bindings._pendingConnectionUuid).eql('f32233445566');
|
|
152
|
+
|
|
153
|
+
assert.calledOnce(bindings._hci.createLeConn);
|
|
154
|
+
assert.calledWith(bindings._hci.createLeConn, 'f3:22:33:44:55:66', 'random', 'parameters');
|
|
144
155
|
});
|
|
145
156
|
|
|
146
157
|
it('existing peripheral, no queue', () => {
|
|
@@ -268,22 +279,28 @@ describe('hci-socket bindings', () => {
|
|
|
268
279
|
assert.calledTwice(process.on);
|
|
269
280
|
});
|
|
270
281
|
|
|
271
|
-
describe('
|
|
282
|
+
describe('stop', () => {
|
|
272
283
|
it('no handles', () => {
|
|
273
284
|
bindings._gap.stopScanning = fake.resolves(null);
|
|
285
|
+
bindings._hci.reset = fake.resolves(null);
|
|
286
|
+
bindings._hci.stop = fake.resolves(null);
|
|
274
287
|
|
|
275
|
-
bindings.
|
|
288
|
+
bindings.stop();
|
|
276
289
|
|
|
277
290
|
assert.calledOnce(bindings._gap.stopScanning);
|
|
291
|
+
assert.calledOnce(bindings._hci.reset);
|
|
292
|
+
assert.calledOnce(bindings._hci.stop);
|
|
278
293
|
});
|
|
279
294
|
|
|
280
295
|
it('with handles', () => {
|
|
281
296
|
bindings._gap.stopScanning = fake.resolves(null);
|
|
282
297
|
bindings._hci.disconnect = fake.resolves(null);
|
|
298
|
+
bindings._hci.reset = fake.resolves(null);
|
|
299
|
+
bindings._hci.stop = fake.resolves(null);
|
|
283
300
|
|
|
284
301
|
bindings._aclStreams = [1, 2, 3];
|
|
285
302
|
|
|
286
|
-
bindings.
|
|
303
|
+
bindings.stop();
|
|
287
304
|
|
|
288
305
|
assert.calledOnce(bindings._gap.stopScanning);
|
|
289
306
|
assert.calledThrice(bindings._hci.disconnect);
|
|
@@ -109,6 +109,7 @@ describe('hci-socket hci', () => {
|
|
|
109
109
|
hci.readLeBufferSize = sinon.spy();
|
|
110
110
|
hci.readBdAddr = sinon.spy();
|
|
111
111
|
hci.init = sinon.spy();
|
|
112
|
+
hci.readLeSupportedFeatures = sinon.spy();
|
|
112
113
|
hci.setCodedPhySupport = sinon.spy();
|
|
113
114
|
|
|
114
115
|
hci.on('stateChange', callback);
|
|
@@ -170,13 +171,7 @@ describe('hci-socket hci', () => {
|
|
|
170
171
|
hci.pollIsDevUp();
|
|
171
172
|
|
|
172
173
|
assert.calledOnceWithExactly(hci.setSocketFilter);
|
|
173
|
-
assert.calledOnceWithExactly(hci.
|
|
174
|
-
assert.calledOnceWithExactly(hci.setLeEventMask);
|
|
175
|
-
assert.calledOnceWithExactly(hci.readLocalVersion);
|
|
176
|
-
assert.calledOnceWithExactly(hci.writeLeHostSupported);
|
|
177
|
-
assert.calledOnceWithExactly(hci.readLeHostSupported);
|
|
178
|
-
assert.calledOnceWithExactly(hci.readLeBufferSize);
|
|
179
|
-
assert.calledOnceWithExactly(hci.readBdAddr);
|
|
174
|
+
assert.calledOnceWithExactly(hci.readLeSupportedFeatures);
|
|
180
175
|
|
|
181
176
|
assert.notCalled(hci.setCodedPhySupport);
|
|
182
177
|
assert.notCalled(hci._socket.removeAllListeners);
|
|
@@ -193,14 +188,7 @@ describe('hci-socket hci', () => {
|
|
|
193
188
|
hci.pollIsDevUp();
|
|
194
189
|
|
|
195
190
|
assert.calledOnceWithExactly(hci.setSocketFilter);
|
|
196
|
-
assert.calledOnceWithExactly(hci.
|
|
197
|
-
assert.calledOnceWithExactly(hci.setLeEventMask);
|
|
198
|
-
assert.calledOnceWithExactly(hci.readLocalVersion);
|
|
199
|
-
assert.calledOnceWithExactly(hci.writeLeHostSupported);
|
|
200
|
-
assert.calledOnceWithExactly(hci.readLeHostSupported);
|
|
201
|
-
assert.calledOnceWithExactly(hci.readLeBufferSize);
|
|
202
|
-
assert.calledOnceWithExactly(hci.readBdAddr);
|
|
203
|
-
assert.calledOnceWithExactly(hci.setCodedPhySupport);
|
|
191
|
+
assert.calledOnceWithExactly(hci.readLeSupportedFeatures);
|
|
204
192
|
|
|
205
193
|
assert.notCalled(hci._socket.removeAllListeners);
|
|
206
194
|
assert.notCalled(hci.init);
|
|
@@ -698,6 +686,81 @@ describe('hci-socket hci', () => {
|
|
|
698
686
|
should(hci._aclConnections).have.keys(4660, 4661);
|
|
699
687
|
should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
|
|
700
688
|
should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
|
|
689
|
+
|
|
690
|
+
describe('LE_READ_LOCAL_SUPPORTED_FEATURES', () => {
|
|
691
|
+
beforeEach(() => {
|
|
692
|
+
hci.setCodedPhySupport = sinon.spy();
|
|
693
|
+
hci.setEventMask = sinon.spy();
|
|
694
|
+
hci.setLeEventMask = sinon.spy();
|
|
695
|
+
hci.readLocalVersion = sinon.spy();
|
|
696
|
+
hci.writeLeHostSupported = sinon.spy();
|
|
697
|
+
hci.readLeHostSupported = sinon.spy();
|
|
698
|
+
hci.readLeBufferSize = sinon.spy();
|
|
699
|
+
hci.readBdAddr = sinon.spy();
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
it('should not process on error status', () => {
|
|
703
|
+
const cmd = 8195;
|
|
704
|
+
const status = 1;
|
|
705
|
+
const result = Buffer.from([0x00, 0x00, 0x00, 0x00]);
|
|
706
|
+
|
|
707
|
+
hci.processCmdCompleteEvent(cmd, status, result);
|
|
708
|
+
|
|
709
|
+
// Verify no methods were called
|
|
710
|
+
assert.notCalled(hci.setCodedPhySupport);
|
|
711
|
+
assert.notCalled(hci.setEventMask);
|
|
712
|
+
assert.notCalled(hci.setLeEventMask);
|
|
713
|
+
assert.notCalled(hci.readLocalVersion);
|
|
714
|
+
assert.notCalled(hci.writeLeHostSupported);
|
|
715
|
+
assert.notCalled(hci.readLeHostSupported);
|
|
716
|
+
assert.notCalled(hci.readLeBufferSize);
|
|
717
|
+
assert.notCalled(hci.readBdAddr);
|
|
718
|
+
|
|
719
|
+
should(hci._isExtended).equal(false);
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
it('should process without extended features', () => {
|
|
723
|
+
const cmd = 8195;
|
|
724
|
+
const status = 0;
|
|
725
|
+
const result = Buffer.from([0x00, 0x00, 0x00, 0x00]); // No bits set
|
|
726
|
+
|
|
727
|
+
hci.processCmdCompleteEvent(cmd, status, result);
|
|
728
|
+
|
|
729
|
+
// Verify extended-specific method not called
|
|
730
|
+
assert.notCalled(hci.setCodedPhySupport);
|
|
731
|
+
|
|
732
|
+
// Verify other methods were called
|
|
733
|
+
assert.calledOnce(hci.setEventMask);
|
|
734
|
+
assert.calledOnce(hci.setLeEventMask);
|
|
735
|
+
assert.calledOnce(hci.readLocalVersion);
|
|
736
|
+
assert.calledOnce(hci.writeLeHostSupported);
|
|
737
|
+
assert.calledOnce(hci.readLeHostSupported);
|
|
738
|
+
assert.calledOnce(hci.readLeBufferSize);
|
|
739
|
+
assert.calledOnce(hci.readBdAddr);
|
|
740
|
+
|
|
741
|
+
should(hci._isExtended).equal(false);
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it('should process with extended features', () => {
|
|
745
|
+
const cmd = 8195;
|
|
746
|
+
const status = 0;
|
|
747
|
+
const result = Buffer.from([0x40, 0x00, 0x00, 0x00]); // Bit 6 set for extended features
|
|
748
|
+
|
|
749
|
+
hci.processCmdCompleteEvent(cmd, status, result);
|
|
750
|
+
|
|
751
|
+
// Verify all methods were called including extended-specific
|
|
752
|
+
assert.calledOnce(hci.setCodedPhySupport);
|
|
753
|
+
assert.calledOnce(hci.setEventMask);
|
|
754
|
+
assert.calledOnce(hci.setLeEventMask);
|
|
755
|
+
assert.calledOnce(hci.readLocalVersion);
|
|
756
|
+
assert.calledOnce(hci.writeLeHostSupported);
|
|
757
|
+
assert.calledOnce(hci.readLeHostSupported);
|
|
758
|
+
assert.calledOnce(hci.readLeBufferSize);
|
|
759
|
+
assert.calledOnce(hci.readBdAddr);
|
|
760
|
+
|
|
761
|
+
should(hci._isExtended).equal(true);
|
|
762
|
+
});
|
|
763
|
+
});
|
|
701
764
|
});
|
|
702
765
|
|
|
703
766
|
it('should only processCmdStatusEvent - HCI_EVENT_PKT / EVT_CMD_STATUS', () => {
|