@stoprocent/bleno 0.7.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/.jshintrc +5 -0
- package/LICENSE +20 -0
- package/README.md +409 -0
- package/binding.gyp +17 -0
- package/examples/battery-service/README.md +14 -0
- package/examples/battery-service/battery-level-characteristic.js +45 -0
- package/examples/battery-service/battery-service.js +16 -0
- package/examples/battery-service/main.js +28 -0
- package/examples/battery-service/package-lock.json +1314 -0
- package/examples/battery-service/package.json +20 -0
- package/examples/blink1/README.md +44 -0
- package/examples/blink1/blink1-fade-rgb-characteristic.js +42 -0
- package/examples/blink1/blink1-rgb-characteristic.js +38 -0
- package/examples/blink1/blink1-service.js +19 -0
- package/examples/blink1/device-information-service.js +19 -0
- package/examples/blink1/hardware-revision-characteristic.js +32 -0
- package/examples/blink1/main.js +32 -0
- package/examples/blink1/serial-number-characteristic.js +21 -0
- package/examples/echo/characteristic.js +45 -0
- package/examples/echo/main.js +33 -0
- package/examples/pizza/README.md +16 -0
- package/examples/pizza/peripheral.js +57 -0
- package/examples/pizza/pizza-bake-characteristic.js +40 -0
- package/examples/pizza/pizza-crust-characteristic.js +52 -0
- package/examples/pizza/pizza-service.js +20 -0
- package/examples/pizza/pizza-toppings-characteristic.js +41 -0
- package/examples/pizza/pizza.js +58 -0
- package/examples/uart/main.js +23 -0
- package/index.d.ts +153 -0
- package/index.js +1 -0
- package/lib/bleno.js +231 -0
- package/lib/characteristic.js +91 -0
- package/lib/descriptor.js +17 -0
- package/lib/hci-socket/acl-stream.js +37 -0
- package/lib/hci-socket/bindings.js +219 -0
- package/lib/hci-socket/crypto.js +74 -0
- package/lib/hci-socket/gap.js +212 -0
- package/lib/hci-socket/gatt.js +1028 -0
- package/lib/hci-socket/hci-status.json +67 -0
- package/lib/hci-socket/hci.js +796 -0
- package/lib/hci-socket/mgmt.js +89 -0
- package/lib/hci-socket/smp.js +160 -0
- package/lib/hci-socket/vs.js +156 -0
- package/lib/mac/binding.gyp +39 -0
- package/lib/mac/bindings.js +12 -0
- package/lib/mac/src/ble_peripheral_manager.h +32 -0
- package/lib/mac/src/ble_peripheral_manager.mm +241 -0
- package/lib/mac/src/bleno_mac.h +26 -0
- package/lib/mac/src/bleno_mac.mm +167 -0
- package/lib/mac/src/callbacks.h +76 -0
- package/lib/mac/src/callbacks.mm +124 -0
- package/lib/mac/src/napi_objc.h +30 -0
- package/lib/mac/src/napi_objc.mm +286 -0
- package/lib/mac/src/noble_mac.h +34 -0
- package/lib/mac/src/noble_mac.mm +260 -0
- package/lib/mac/src/objc_cpp.h +27 -0
- package/lib/mac/src/objc_cpp.mm +144 -0
- package/lib/mac/src/peripheral.h +23 -0
- package/lib/primary-service.js +19 -0
- package/lib/resolve-bindings.js +19 -0
- package/lib/uuid-util.js +7 -0
- package/package.json +77 -0
- package/prebuilds/android-arm/node.napi.armv7.node +0 -0
- package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
- package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/node.napi.musl.node +0 -0
- package/prebuilds/win32-ia32/node.napi.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/test/characteristic.test.js +174 -0
- package/test/descriptor.test.js +46 -0
- package/test/mocha.setup.js +0 -0
- package/with-bindings.js +5 -0
- package/with-custom-binding.js +6 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Type definitions for bleno 0.4
|
|
2
|
+
// Project: https://github.com/sandeepmistry/bleno
|
|
3
|
+
// Definitions by: Manuel Francisco Naranjo <naranjo.manuel@gmail.com>
|
|
4
|
+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
|
|
6
|
+
/// <reference types="node" />
|
|
7
|
+
|
|
8
|
+
type State = 'poweredOn' | 'poweredOff' | 'unauthorized' | 'unsupported' | 'unknown' | 'resetting';
|
|
9
|
+
|
|
10
|
+
type Property = 'read' | 'write' | 'indicate' | 'notify' | 'writeWithoutResponse';
|
|
11
|
+
|
|
12
|
+
interface CharacteristicOptions {
|
|
13
|
+
uuid: string;
|
|
14
|
+
properties?: ReadonlyArray<Property> | null;
|
|
15
|
+
secure?: ReadonlyArray<Property> | null;
|
|
16
|
+
value?: Buffer | null;
|
|
17
|
+
descriptors?: ReadonlyArray<Descriptor> | null;
|
|
18
|
+
onIndicate?: (() => void) | null;
|
|
19
|
+
onNotify?: (() => void) | null;
|
|
20
|
+
onReadRequest?: ((
|
|
21
|
+
offset: number,
|
|
22
|
+
callback: (result: number, data?: Buffer) => void
|
|
23
|
+
) => void) | null;
|
|
24
|
+
onSubscribe?: ((maxValueSize: number, updateValueCallback: (data: Buffer) => void) => void) | null;
|
|
25
|
+
onUnsubscribe?: (() => void) | null;
|
|
26
|
+
onWriteRequest?: ((
|
|
27
|
+
data: Buffer,
|
|
28
|
+
offset: number,
|
|
29
|
+
withoutResponse: boolean,
|
|
30
|
+
callback: (result: number) => void
|
|
31
|
+
) => void) | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare class Characteristic {
|
|
35
|
+
uuid: string;
|
|
36
|
+
properties: ReadonlyArray<Property>;
|
|
37
|
+
secure: ReadonlyArray<Property>;
|
|
38
|
+
value: Buffer | null;
|
|
39
|
+
descriptors: ReadonlyArray<Descriptor>;
|
|
40
|
+
|
|
41
|
+
constructor(options: CharacteristicOptions);
|
|
42
|
+
|
|
43
|
+
onIndicate(): void;
|
|
44
|
+
|
|
45
|
+
onNotify(): void;
|
|
46
|
+
|
|
47
|
+
onReadRequest(offset: number, callback: (result: number, data?: Buffer) => void): void;
|
|
48
|
+
|
|
49
|
+
onSubscribe(maxValueSize: number, updateValueCallback: (data: Buffer) => void): void;
|
|
50
|
+
|
|
51
|
+
onUnsubscribe(): void;
|
|
52
|
+
|
|
53
|
+
onWriteRequest(data: Buffer, offset: number, withoutResponse: boolean, callback: (result: number) => void): void;
|
|
54
|
+
|
|
55
|
+
toString(): string;
|
|
56
|
+
|
|
57
|
+
readonly RESULT_ATTR_NOT_LONG: number;
|
|
58
|
+
|
|
59
|
+
readonly RESULT_INVALID_ATTRIBUTE_LENGTH: number;
|
|
60
|
+
|
|
61
|
+
readonly RESULT_INVALID_OFFSET: number;
|
|
62
|
+
|
|
63
|
+
readonly RESULT_SUCCESS: number;
|
|
64
|
+
|
|
65
|
+
readonly RESULT_UNLIKELY_ERROR: number;
|
|
66
|
+
|
|
67
|
+
static readonly RESULT_ATTR_NOT_LONG: number;
|
|
68
|
+
|
|
69
|
+
static readonly RESULT_INVALID_ATTRIBUTE_LENGTH: number;
|
|
70
|
+
|
|
71
|
+
static readonly RESULT_INVALID_OFFSET: number;
|
|
72
|
+
|
|
73
|
+
static readonly RESULT_SUCCESS: number;
|
|
74
|
+
|
|
75
|
+
static readonly RESULT_UNLIKELY_ERROR: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface DescriptorOptions {
|
|
79
|
+
uuid: string;
|
|
80
|
+
value?: Buffer | string | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare class Descriptor {
|
|
84
|
+
uuid: string;
|
|
85
|
+
value: Buffer;
|
|
86
|
+
|
|
87
|
+
constructor(options: DescriptorOptions);
|
|
88
|
+
|
|
89
|
+
toString(): string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface PrimaryServiceOptions {
|
|
93
|
+
uuid: string;
|
|
94
|
+
characteristics?: ReadonlyArray<Characteristic> | null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
declare class PrimaryService {
|
|
98
|
+
uuid: string;
|
|
99
|
+
characteristics: ReadonlyArray<Characteristic>;
|
|
100
|
+
|
|
101
|
+
constructor(options: PrimaryServiceOptions);
|
|
102
|
+
|
|
103
|
+
toString(): string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface Bleno extends NodeJS.EventEmitter {
|
|
107
|
+
readonly Characteristic: typeof Characteristic;
|
|
108
|
+
readonly Descriptor: typeof Descriptor;
|
|
109
|
+
readonly PrimaryService: typeof PrimaryService;
|
|
110
|
+
|
|
111
|
+
readonly address: string;
|
|
112
|
+
|
|
113
|
+
readonly mtu: number;
|
|
114
|
+
|
|
115
|
+
readonly platform: string;
|
|
116
|
+
|
|
117
|
+
readonly rssi: number;
|
|
118
|
+
|
|
119
|
+
readonly state: State;
|
|
120
|
+
|
|
121
|
+
disconnect(): void;
|
|
122
|
+
|
|
123
|
+
setAddress(address: string): void;
|
|
124
|
+
|
|
125
|
+
setServices(services: ReadonlyArray<PrimaryService>, callback?: (arg: Error | undefined | null) => void): void;
|
|
126
|
+
|
|
127
|
+
startAdvertising(name: string, serviceUuids?: ReadonlyArray<string>, callback?: (arg: Error | undefined | null) => void): void;
|
|
128
|
+
|
|
129
|
+
startAdvertisingIBeacon(uuid: string, major: number, minor: number, measuredPower: number, callback?: (arg: Error | undefined | null) => void): void;
|
|
130
|
+
|
|
131
|
+
startAdvertisingWithEIRData(advertisementData: Buffer, callback?: (arg: Error | undefined | null) => void): void;
|
|
132
|
+
startAdvertisingWithEIRData(advertisementData: Buffer, scanData: Buffer, callback?: (arg: Error | undefined | null) => void): void;
|
|
133
|
+
|
|
134
|
+
stopAdvertising(callback?: () => void): void;
|
|
135
|
+
|
|
136
|
+
updateRssi(callback?: (err: null, rssi: number) => void): void;
|
|
137
|
+
|
|
138
|
+
on(event: 'stateChange', cb: (state: State) => void): this;
|
|
139
|
+
on(event: 'platform', cb: (platform: NodeJS.Platform) => void): this;
|
|
140
|
+
on(event: 'addressChange', cb: (address: string) => void): this;
|
|
141
|
+
on(event: 'accept', cb: (address: string) => void): this;
|
|
142
|
+
on(event: 'mtuChange', cb: (mtu: number) => void): this;
|
|
143
|
+
on(event: 'disconnect', cb: (clientAddress: string) => void): this;
|
|
144
|
+
on(event: 'advertisingStart', cb: (err?: Error | null) => void): this;
|
|
145
|
+
on(event: 'advertisingStartError', cb: (err: Error) => void): this;
|
|
146
|
+
on(event: 'advertisingStop', cb: () => void): this;
|
|
147
|
+
on(event: 'servicesSet', cb: (err?: Error | null) => void): this;
|
|
148
|
+
on(event: 'servicesSetError', cb: (err: Error) => void): this;
|
|
149
|
+
on(event: 'rssiUpdate', cb: (rssi: number) => void): this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
declare const bleno: Bleno;
|
|
153
|
+
export = bleno;
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./with-custom-binding')();
|
package/lib/bleno.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const debug = require('debug')('bleno');
|
|
2
|
+
const UuidUtil = require('./uuid-util');
|
|
3
|
+
|
|
4
|
+
const { EventEmitter } = require('events');
|
|
5
|
+
|
|
6
|
+
const PrimaryService = require('./primary-service');
|
|
7
|
+
const Characteristic = require('./characteristic');
|
|
8
|
+
const Descriptor = require('./descriptor');
|
|
9
|
+
|
|
10
|
+
class Bleno extends EventEmitter {
|
|
11
|
+
constructor (bindings) {
|
|
12
|
+
super();
|
|
13
|
+
this.initialized = false;
|
|
14
|
+
this.platform = 'unknown';
|
|
15
|
+
this.state = 'unknown';
|
|
16
|
+
this.address = 'unknown';
|
|
17
|
+
this.rssi = 0;
|
|
18
|
+
this.mtu = 20;
|
|
19
|
+
|
|
20
|
+
this._bindings = bindings;
|
|
21
|
+
|
|
22
|
+
this._bindings.on('stateChange', this.onStateChange.bind(this));
|
|
23
|
+
this._bindings.on('platform', this.onPlatform.bind(this));
|
|
24
|
+
this._bindings.on('addressChange', this.onAddressChange.bind(this));
|
|
25
|
+
this._bindings.on('advertisingStart', this.onAdvertisingStart.bind(this));
|
|
26
|
+
this._bindings.on('advertisingStop', this.onAdvertisingStop.bind(this));
|
|
27
|
+
this._bindings.on('servicesSet', this.onServicesSet.bind(this));
|
|
28
|
+
this._bindings.on('accept', this.onAccept.bind(this));
|
|
29
|
+
this._bindings.on('mtuChange', this.onMtuChange.bind(this));
|
|
30
|
+
this._bindings.on('disconnect', this.onDisconnect.bind(this));
|
|
31
|
+
this._bindings.on('rssiUpdate', this.onRssiUpdate.bind(this));
|
|
32
|
+
|
|
33
|
+
this.on('newListener', (event) => {
|
|
34
|
+
if (event === 'stateChange' && !this.initialized) {
|
|
35
|
+
this._bindings.init();
|
|
36
|
+
|
|
37
|
+
this.initialized = true;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onPlatform (platform) {
|
|
43
|
+
debug('platform ' + platform);
|
|
44
|
+
|
|
45
|
+
this.platform = platform;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
onStateChange (state) {
|
|
49
|
+
debug('stateChange ' + state);
|
|
50
|
+
|
|
51
|
+
this.state = state;
|
|
52
|
+
|
|
53
|
+
this.emit('stateChange', state);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onAddressChange (address) {
|
|
57
|
+
debug('addressChange ' + address);
|
|
58
|
+
|
|
59
|
+
this.address = address;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onAccept (clientAddress) {
|
|
63
|
+
debug('accept ' + clientAddress);
|
|
64
|
+
this.emit('accept', clientAddress);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
onMtuChange (mtu) {
|
|
68
|
+
debug('mtu ' + mtu);
|
|
69
|
+
|
|
70
|
+
this.mtu = mtu;
|
|
71
|
+
|
|
72
|
+
this.emit('mtuChange', mtu);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onDisconnect (clientAddress) {
|
|
76
|
+
debug('disconnect ' + clientAddress);
|
|
77
|
+
this.emit('disconnect', clientAddress);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setAddress (address) {
|
|
81
|
+
if (this._bindings.setAddress) {
|
|
82
|
+
this._bindings.setAddress(address);
|
|
83
|
+
} else {
|
|
84
|
+
this.emit('warning', 'current binding does not implement setAddress method.');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
startAdvertising (name, serviceUuids, callback) {
|
|
89
|
+
if (this.state !== 'poweredOn') {
|
|
90
|
+
const error = new Error('Could not start advertising, state is ' + this.state + ' (not poweredOn)');
|
|
91
|
+
|
|
92
|
+
if (typeof callback === 'function') {
|
|
93
|
+
callback(error);
|
|
94
|
+
} else {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
if (typeof callback === 'function') {
|
|
99
|
+
this.once('advertisingStart', callback);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const undashedServiceUuids = [];
|
|
103
|
+
|
|
104
|
+
if (serviceUuids && serviceUuids.length) {
|
|
105
|
+
for (let i = 0; i < serviceUuids.length; i++) {
|
|
106
|
+
undashedServiceUuids[i] = UuidUtil.removeDashes(serviceUuids[i]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this._bindings.startAdvertising(name, undashedServiceUuids);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
startAdvertisingIBeacon (uuid, major, minor, measuredPower, callback) {
|
|
115
|
+
if (this.state !== 'poweredOn') {
|
|
116
|
+
const error = new Error('Could not start advertising, state is ' + this.state + ' (not poweredOn)');
|
|
117
|
+
|
|
118
|
+
if (typeof callback === 'function') {
|
|
119
|
+
callback(error);
|
|
120
|
+
} else {
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const undashedUuid = UuidUtil.removeDashes(uuid);
|
|
125
|
+
const uuidData = Buffer.from(undashedUuid, 'hex');
|
|
126
|
+
const uuidDataLength = uuidData.length;
|
|
127
|
+
const iBeaconData = Buffer.alloc(uuidData.length + 5);
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < uuidDataLength; i++) {
|
|
130
|
+
iBeaconData[i] = uuidData[i];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
iBeaconData.writeUInt16BE(major, uuidDataLength);
|
|
134
|
+
iBeaconData.writeUInt16BE(minor, uuidDataLength + 2);
|
|
135
|
+
iBeaconData.writeInt8(measuredPower, uuidDataLength + 4);
|
|
136
|
+
|
|
137
|
+
if (typeof callback === 'function') {
|
|
138
|
+
this.once('advertisingStart', callback);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
debug('iBeacon data = ' + iBeaconData.toString('hex'));
|
|
142
|
+
|
|
143
|
+
this._bindings.startAdvertisingIBeacon(iBeaconData);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onAdvertisingStart (error) {
|
|
148
|
+
debug('advertisingStart: ' + error);
|
|
149
|
+
|
|
150
|
+
if (error) {
|
|
151
|
+
this.emit('advertisingStartError', error);
|
|
152
|
+
} else {
|
|
153
|
+
this.emit('advertisingStart', error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
startAdvertisingWithEIRData (advertisementData, scanData, callback) {
|
|
158
|
+
if (typeof scanData === 'function') {
|
|
159
|
+
callback = scanData;
|
|
160
|
+
scanData = null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (this.state !== 'poweredOn') {
|
|
164
|
+
const error = new Error('Could not advertising scanning, state is ' + this.state + ' (not poweredOn)');
|
|
165
|
+
|
|
166
|
+
if (typeof callback === 'function') {
|
|
167
|
+
callback(error);
|
|
168
|
+
} else {
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
if (typeof callback === 'function') {
|
|
173
|
+
this.once('advertisingStart', callback);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this._bindings.startAdvertisingWithEIRData(advertisementData, scanData);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
stopAdvertising (callback) {
|
|
181
|
+
if (typeof callback === 'function') {
|
|
182
|
+
this.once('advertisingStop', callback);
|
|
183
|
+
}
|
|
184
|
+
this._bindings.stopAdvertising();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
onAdvertisingStop () {
|
|
188
|
+
debug('advertisingStop');
|
|
189
|
+
this.emit('advertisingStop');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
setServices (services, callback) {
|
|
193
|
+
if (typeof callback === 'function') {
|
|
194
|
+
this.once('servicesSet', callback);
|
|
195
|
+
}
|
|
196
|
+
this._bindings.setServices(services);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
onServicesSet (error) {
|
|
200
|
+
debug('servicesSet');
|
|
201
|
+
|
|
202
|
+
if (error) {
|
|
203
|
+
this.emit('servicesSetError', error);
|
|
204
|
+
} else {
|
|
205
|
+
this.emit('servicesSet', error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
disconnect () {
|
|
210
|
+
debug('disconnect');
|
|
211
|
+
this._bindings.disconnect();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
updateRssi (callback) {
|
|
215
|
+
if (typeof callback === 'function') {
|
|
216
|
+
this.once('rssiUpdate', (rssi) => callback(null, rssi));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this._bindings.updateRssi();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
onRssiUpdate (rssi) {
|
|
223
|
+
this.emit('rssiUpdate', rssi);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
Bleno.prototype.PrimaryService = PrimaryService;
|
|
228
|
+
Bleno.prototype.Characteristic = Characteristic;
|
|
229
|
+
Bleno.prototype.Descriptor = Descriptor;
|
|
230
|
+
|
|
231
|
+
module.exports = Bleno;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const { EventEmitter } = require('events');
|
|
2
|
+
const UuidUtil = require('./uuid-util');
|
|
3
|
+
|
|
4
|
+
class Characteristic extends EventEmitter {
|
|
5
|
+
constructor (options) {
|
|
6
|
+
super();
|
|
7
|
+
|
|
8
|
+
this.uuid = UuidUtil.removeDashes(options.uuid);
|
|
9
|
+
this.properties = options.properties || [];
|
|
10
|
+
this.secure = options.secure || [];
|
|
11
|
+
this.value = options.value || null;
|
|
12
|
+
this.descriptors = options.descriptors || [];
|
|
13
|
+
|
|
14
|
+
if (this.value && (this.properties.length !== 1 || this.properties[0] !== 'read')) {
|
|
15
|
+
throw new Error('Characteristics with value can be read only!');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (options.onReadRequest) {
|
|
19
|
+
this.onReadRequest = options.onReadRequest;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (options.onWriteRequest) {
|
|
23
|
+
this.onWriteRequest = options.onWriteRequest;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (options.onSubscribe) {
|
|
27
|
+
this.onSubscribe = options.onSubscribe;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.onUnsubscribe) {
|
|
31
|
+
this.onUnsubscribe = options.onUnsubscribe;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (options.onNotify) {
|
|
35
|
+
this.onNotify = options.onNotify;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (options.onIndicate) {
|
|
39
|
+
this.onIndicate = options.onIndicate;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.on('readRequest', this.onReadRequest.bind(this));
|
|
43
|
+
this.on('writeRequest', this.onWriteRequest.bind(this));
|
|
44
|
+
this.on('subscribe', this.onSubscribe.bind(this));
|
|
45
|
+
this.on('unsubscribe', this.onUnsubscribe.bind(this));
|
|
46
|
+
this.on('notify', this.onNotify.bind(this));
|
|
47
|
+
this.on('indicate', this.onIndicate.bind(this));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
toString () {
|
|
51
|
+
return JSON.stringify({
|
|
52
|
+
uuid: this.uuid,
|
|
53
|
+
properties: this.properties,
|
|
54
|
+
secure: this.secure,
|
|
55
|
+
value: this.value,
|
|
56
|
+
descriptors: this.descriptors
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
onReadRequest (offset, callback) {
|
|
61
|
+
callback(this.RESULT_UNLIKELY_ERROR, null);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
onWriteRequest (data, offset, withoutResponse, callback) {
|
|
65
|
+
callback(this.RESULT_UNLIKELY_ERROR);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onSubscribe (maxValueSize, updateValueCallback) {
|
|
69
|
+
this.maxValueSize = maxValueSize;
|
|
70
|
+
this.updateValueCallback = updateValueCallback;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
onUnsubscribe () {
|
|
74
|
+
this.maxValueSize = null;
|
|
75
|
+
this.updateValueCallback = null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onNotify () {
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
onIndicate () {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Characteristic.RESULT_SUCCESS = Characteristic.prototype.RESULT_SUCCESS = 0x00;
|
|
86
|
+
Characteristic.RESULT_INVALID_OFFSET = Characteristic.prototype.RESULT_INVALID_OFFSET = 0x07;
|
|
87
|
+
Characteristic.RESULT_ATTR_NOT_LONG = Characteristic.prototype.RESULT_ATTR_NOT_LONG = 0x0b;
|
|
88
|
+
Characteristic.RESULT_INVALID_ATTRIBUTE_LENGTH = Characteristic.prototype.RESULT_INVALID_ATTRIBUTE_LENGTH = 0x0d;
|
|
89
|
+
Characteristic.RESULT_UNLIKELY_ERROR = Characteristic.prototype.RESULT_UNLIKELY_ERROR = 0x0e;
|
|
90
|
+
|
|
91
|
+
module.exports = Characteristic;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const UuidUtil = require('./uuid-util');
|
|
2
|
+
|
|
3
|
+
class Descriptor {
|
|
4
|
+
constructor (options) {
|
|
5
|
+
this.uuid = UuidUtil.removeDashes(options.uuid);
|
|
6
|
+
this.value = options.value || Buffer.alloc(0);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toString () {
|
|
10
|
+
return JSON.stringify({
|
|
11
|
+
uuid: this.uuid,
|
|
12
|
+
value: Buffer.isBuffer(this.value) ? this.value.toString('hex') : this.value
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = Descriptor;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { EventEmitter } = require('events');
|
|
2
|
+
const Smp = require('./smp');
|
|
3
|
+
|
|
4
|
+
class AclStream extends EventEmitter {
|
|
5
|
+
constructor (hci, handle, localAddressType, localAddress, remoteAddressType, remoteAddress) {
|
|
6
|
+
super();
|
|
7
|
+
this._hci = hci;
|
|
8
|
+
this._handle = handle;
|
|
9
|
+
this.encypted = false;
|
|
10
|
+
|
|
11
|
+
this._smp = new Smp(this, localAddressType, localAddress, remoteAddressType, remoteAddress);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
write (cid, data) {
|
|
15
|
+
this._hci.queueAclDataPkt(this._handle, cid, data);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
push (cid, data) {
|
|
19
|
+
if (data) {
|
|
20
|
+
this.emit('data', cid, data);
|
|
21
|
+
} else {
|
|
22
|
+
this.emit('end');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pushEncrypt (encrypt) {
|
|
27
|
+
this.encrypted = !!encrypt;
|
|
28
|
+
|
|
29
|
+
this.emit('encryptChange', this.encrypted);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pushLtkNegReply () {
|
|
33
|
+
this.emit('ltkNegReply');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = AclStream;
|