Skip to content

Commit

Permalink
feat(multi-connect): wip
Browse files Browse the repository at this point in the history
  • Loading branch information
stoprocent committed Dec 23, 2024
1 parent 2c76cba commit 2c7a223
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 160 deletions.
37 changes: 37 additions & 0 deletions examples/echo/async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const bleno = require('../..');

const BlenoPrimaryService = bleno.PrimaryService;

const EchoCharacteristic = require('./characteristic');

console.log('bleno - echo');

async function run() {

Check failure on line 9 in examples/echo/async.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 9 in examples/echo/async.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
try {
await bleno.waitForPoweredOnAsync();
console.log("Powered on");
await bleno.setAddressAsync('11:22:44:55:99:77');
console.log("Address set");
await bleno.startAdvertisingAsync('echo', ['ec00']);
console.log("Advertising started");
await bleno.setServicesAsync([
new BlenoPrimaryService({
uuid: 'ec00',
characteristics: [
new EchoCharacteristic()
]
})
]);
console.log("Services set");
} catch (error) {
console.error("Error: ", error);
}
}

bleno.on('accept', async (address) => {
console.log("Accepted: ", address);
await bleno.startAdvertisingAsync('echo', ['ec00']);
console.log("Advertising started");
});

run();
18 changes: 9 additions & 9 deletions examples/echo/characteristic.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,34 @@ class EchoCharacteristic extends BlenoCharacteristic {
});

this._value = Buffer.alloc(0);
this._updateValueCallback = null;
this._updateValueCallbacks = new Map();
}

onReadRequest (offset, callback) {
onReadRequest (connection, offset, callback) {
console.log('EchoCharacteristic - onReadRequest: value = ' + this._value.toString('hex'));
callback(this.RESULT_SUCCESS, this._value);
}

onWriteRequest (data, offset, withoutResponse, callback) {
onWriteRequest (connection, data, offset, withoutResponse, callback) {
this._value = data;
console.log('EchoCharacteristic - onWriteRequest: value = ' + this._value.toString('hex'));

if (this._updateValueCallback) {
for (const updateValueCallback of this._updateValueCallbacks.values()) {
console.log('EchoCharacteristic - onWriteRequest: notifying');
this._updateValueCallback(this._value);
updateValueCallback(this._value);
}

callback(this.RESULT_SUCCESS);
}

onSubscribe (maxValueSize, updateValueCallback) {
onSubscribe (connection, maxValueSize, updateValueCallback) {
console.log('EchoCharacteristic - onSubscribe');
this._updateValueCallback = updateValueCallback;
this._updateValueCallbacks.set(connection, updateValueCallback);
}

onUnsubscribe () {
onUnsubscribe (connection) {
console.log('EchoCharacteristic - onUnsubscribe');
this._updateValueCallback = null;
this._updateValueCallbacks.delete(connection);
}
}

Expand Down
23 changes: 23 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,29 @@ export interface Bleno extends NodeJS.EventEmitter {

updateRssi(callback?: (err: null, rssi: number) => void): void;

// Async methods
waitForPoweredOn(timeout?: number): Promise<void>;

setAddressAsync(address: string): Promise<void>;

setServicesAsync(services: ReadonlyArray<PrimaryService>): Promise<void>;

startAdvertisingAsync(name: string, serviceUuids?: ReadonlyArray<string>): Promise<void>;

startAdvertisingIBeaconAsync(
uuid: string,
major: number,
minor: number,
measuredPower: number
): Promise<void>;

startAdvertisingWithEIRDataAsync(advertisementData: Buffer): Promise<void>;
startAdvertisingWithEIRDataAsync(advertisementData: Buffer, scanData: Buffer): Promise<void>;

stopAdvertisingAsync(): Promise<void>;

updateRssiAsync(): Promise<number>;

on(event: 'stateChange', cb: (state: State) => void): this;
on(event: 'platform', cb: (platform: NodeJS.Platform) => void): this;
on(event: 'addressChange', cb: (address: string) => void): this;
Expand Down
95 changes: 95 additions & 0 deletions lib/bleno.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,29 @@ class Bleno extends EventEmitter {
this.emit('disconnect', clientAddress);
}

async waitForPoweredOnAsync(timeout = 10000) {

Check failure on line 80 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 80 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
if (this.state === 'poweredOn') {
return;
}

return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
this.removeListener('stateChange', stateChangeHandler);
reject(new Error(`Timeout waiting for poweredOn state. Current state: ${this.state}`));
}, timeout);

const stateChangeHandler = (state) => {
if (state === 'poweredOn') {
clearTimeout(timeoutId);
this.removeListener('stateChange', stateChangeHandler);
resolve();
}
};

this.on('stateChange', stateChangeHandler);
});
}

setAddress (address) {
if (this._bindings.setAddress) {
this._bindings.setAddress(address);
Expand All @@ -85,6 +108,24 @@ class Bleno extends EventEmitter {
}
}

setAddressAsync(address) {

Check failure on line 111 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 111 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Timeout waiting for address change'));
}, 2000);
this._bindings.once('addressChange', (address) => {
if (address === address) {
clearTimeout(timeout);
resolve();
}
else {
reject(new Error('Address change failed'));
}
});
this.setAddress(address);
});
}

startAdvertising (name, serviceUuids, callback) {
if (this.state !== 'poweredOn') {
const error = new Error('Could not start advertising, state is ' + this.state + ' (not poweredOn)');
Expand All @@ -111,6 +152,15 @@ class Bleno extends EventEmitter {
}
}

startAdvertisingAsync(name, serviceUuids) {

Check failure on line 155 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 155 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.startAdvertising(name, serviceUuids, (error) => {
if (error) reject(error);
else resolve();
});
});
}

startAdvertisingIBeacon (uuid, major, minor, measuredPower, callback) {
if (this.state !== 'poweredOn') {
const error = new Error('Could not start advertising, state is ' + this.state + ' (not poweredOn)');
Expand Down Expand Up @@ -144,6 +194,15 @@ class Bleno extends EventEmitter {
}
}

startAdvertisingIBeaconAsync(uuid, major, minor, measuredPower) {

Check failure on line 197 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 197 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.startAdvertisingIBeacon(uuid, major, minor, measuredPower, (error) => {
if (error) reject(error);
else resolve();
});
});
}

onAdvertisingStart (error) {
debug('advertisingStart: ' + error);

Expand Down Expand Up @@ -177,13 +236,31 @@ class Bleno extends EventEmitter {
}
}

startAdvertisingWithEIRDataAsync(advertisementData, scanData) {

Check failure on line 239 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 239 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.startAdvertisingWithEIRData(advertisementData, scanData, (error) => {
if (error) reject(error);
else resolve();
});
});
}

stopAdvertising (callback) {
if (typeof callback === 'function') {
this.once('advertisingStop', callback);
}
this._bindings.stopAdvertising();
}

stopAdvertisingAsync() {

Check failure on line 255 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 255 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.stopAdvertising((error) => {
if (error) reject(error);
else resolve();
});
});
}

onAdvertisingStop () {
debug('advertisingStop');
this.emit('advertisingStop');
Expand All @@ -196,6 +273,15 @@ class Bleno extends EventEmitter {
this._bindings.setServices(services);
}

setServicesAsync(services) {

Check failure on line 276 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 276 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.setServices(services, (error) => {
if (error) reject(error);
else resolve();
});
});
}

onServicesSet (error) {
debug('servicesSet');

Expand Down Expand Up @@ -224,6 +310,15 @@ class Bleno extends EventEmitter {
this._bindings.updateRssi();
}

updateRssiAsync() {

Check failure on line 313 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses

Check failure on line 313 in lib/bleno.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
return new Promise((resolve, reject) => {
this.updateRssi((error) => {
if (error) reject(error);
else resolve();
});
});
}

onRssiUpdate (rssi) {
this.emit('rssiUpdate', rssi);
}
Expand Down
30 changes: 20 additions & 10 deletions lib/characteristic.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class Characteristic extends EventEmitter {
this.on('unsubscribe', this.onUnsubscribe.bind(this));
this.on('notify', this.onNotify.bind(this));
this.on('indicate', this.onIndicate.bind(this));

this._updateValueCallbacks = new Map();
}

toString () {
Expand All @@ -57,28 +59,36 @@ class Characteristic extends EventEmitter {
});
}

onReadRequest (offset, callback) {
onReadRequest (connection, offset, callback) {
callback(this.RESULT_UNLIKELY_ERROR, null);
}

onWriteRequest (data, offset, withoutResponse, callback) {
onWriteRequest (connection, data, offset, withoutResponse, callback) {
callback(this.RESULT_UNLIKELY_ERROR);
}

onSubscribe (maxValueSize, updateValueCallback) {
this.maxValueSize = maxValueSize;
this.updateValueCallback = updateValueCallback;
onSubscribe (connection, maxValueSize, updateValueCallback) {
this._updateValueCallbacks.set(connection, updateValueCallback);
}

onUnsubscribe (connection) {
this._updateValueCallbacks.delete(connection);
}

onUnsubscribe () {
this.maxValueSize = null;
this.updateValueCallback = null;
onNotify (connection) {
}

onNotify () {
onIndicate (connection) {
}

onIndicate () {
notify (data, connection = null) {
if (connection && this._updateValueCallbacks.has(connection)) {
this._updateValueCallbacks.get(connection)(data);
} else if (!connection) {
for (const callback of this._updateValueCallbacks.values()) {
callback(data);
}
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/hci-socket/acl-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ class AclStream extends EventEmitter {
this._hci.queueAclDataPkt(this._handle, cid, data);
}

push (cid, data) {
push (handle, cid, data) {
if (data) {
this.emit('data', cid, data);
this.emit('data', handle, cid, data);
} else {
this.emit('end');
this.emit('end', handle);
}
}

Expand Down
Loading

0 comments on commit 2c7a223

Please sign in to comment.