Bug fixes, hubs now wait for hub properties before being connected

This commit is contained in:
Nathan Kellenicki 2019-12-19 15:44:35 -08:00
parent bc644c85b2
commit 035017617e
4 changed files with 93 additions and 56 deletions

View File

@ -0,0 +1,37 @@
/*
*
* This demonstrates connecting multiple hubs to your laptop. Once connected, all the hubs LED lights will cycle through the same colors simultaneously.
*
*/
const PoweredUP = require("..");
const poweredUP = new PoweredUP.PoweredUP();
poweredUP.scan(); // Start scanning for hubs
console.log("Looking for Hubs...");
poweredUP.on("discover", async (hub) => { // Wait to discover hubs
await hub.connect(); // Connect to hub
console.log(`Connected to ${hub.name}!`);
const motorA = await hub.waitForDeviceAtPort("A");
console.log("Got motor A");
const motorB = await hub.waitForDeviceAtPort("B");
console.log("Got motor B");
const motorC = await hub.waitForDeviceAtPort("C");
console.log("Got motor C");
const motorD = await hub.waitForDeviceAtPort("D");
console.log("Got motor D");
motorA.setPower(30);
motorB.setPower(30);
motorC.setPower(30);
motorD.setPower(30);
hub.on("disconnect", () => {
console.log("Hub disconnected");
});
});

View File

@ -41,7 +41,7 @@ export class HubLED extends Device {
public setRGB (red: number, green: number, blue: number) {
return new Promise((resolve, reject) => {
this.subscribe(HubLED.Mode.RGB);
this.writeDirect(0x00, Buffer.from([red, green, blue]));
this.writeDirect(0x01, Buffer.from([red, green, blue]));
return resolve();
});
}

View File

@ -54,10 +54,11 @@ export class BaseHub extends EventEmitter {
private _type: Consts.HubType;
private _portMap: {[portName: string]: number} = {};
private _attachCallbacks: ((device: Device) => void)[] = [];
private _attachCallbacks: ((device: Device) => boolean)[] = [];
constructor (device: IBLEAbstraction, portMap: {[portName: string]: number} = {}, type: Consts.HubType = Consts.HubType.UNKNOWN) {
super();
this.setMaxListeners(20); // Technic Medium Hub has 9 built in devices + 4 external ports. Node.js throws a warning after 11 attached event listeners.
this._type = type;
this._bleDevice = device;
this._portMap = portMap;
@ -183,7 +184,7 @@ export class BaseHub extends EventEmitter {
public getDeviceAtPort (portName: string) {
const portId = this._portMap[portName];
if (portId) {
if (portId !== undefined) {
return this._attachedDevices[portId];
} else {
throw new Error(`Port ${portName} does not exist on this hub type`);
@ -199,7 +200,10 @@ export class BaseHub extends EventEmitter {
}
this._attachCallbacks.push((device) => {
if (device.portName === portName) {
return resolve(device);
resolve(device);
return true;
} else {
return false;
}
});
});
@ -224,7 +228,10 @@ export class BaseHub extends EventEmitter {
}
this._attachCallbacks.push((device) => {
if (device.type === deviceType) {
return resolve(device);
resolve(device);
return true;
} else {
return false;
}
})
});
@ -289,9 +296,15 @@ export class BaseHub extends EventEmitter {
* @param {Device} device
*/
this.emit("attach", device);
this._attachCallbacks.forEach((callback) => {
callback(device);
});
debug(`Attached device type ${device.type} (${Consts.DeviceTypeNames[device.type]}) on port ${device.portName} (${device.portId})`);
let i = this._attachCallbacks.length;
while (i--) {
const callback = this._attachCallbacks[i];
if (callback(device)) {
this._attachCallbacks.splice(i, 1);
}
}
}
@ -303,6 +316,7 @@ export class BaseHub extends EventEmitter {
* @param {Device} device
*/
this.emit("detach", device);
debug(`Detached device type ${device.type} (${Consts.DeviceTypeNames[device.type]}) on port ${device.portName} (${device.portId})`);
}

View File

@ -17,20 +17,24 @@ export class LPF2Hub extends BaseHub {
private _messageBuffer: Buffer = Buffer.alloc(0);
private _propertyRequestCallbacks: {[property: number]: ((data: Buffer) => void)} = {};
public connect () {
return new Promise(async (resolve, reject) => {
debug("LPF2Hub connecting");
await super.connect();
await this._bleDevice.discoverCharacteristicsForService(Consts.BLEService.LPF2_HUB);
this._bleDevice.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, this._parseMessage.bind(this));
await this.sleep(100);
this.send(Buffer.from([0x01, 0x02, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate button reports
this.send(Buffer.from([0x01, 0x03, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request firmware version
this.send(Buffer.from([0x01, 0x04, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request hardware version
this.send(Buffer.from([0x01, 0x05, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate RSSI updates
this.send(Buffer.from([0x01, 0x06, 0x02]), Consts.BLECharacteristic.LPF2_ALL); // Activate battery level reports
this.send(Buffer.from([0x01, 0x0d, 0x05]), Consts.BLECharacteristic.LPF2_ALL); // Request primary MAC address
await this.sleep(500);
this._requestHubPropertyReports(0x02); // Activate button reports
await this._requestHubPropertyValue(0x03); // Request firmware version
await this._requestHubPropertyValue(0x04); // Request hardware version
this._requestHubPropertyReports(0x05); // Activate RSSI updates
this._requestHubPropertyReports(0x06); // Activate battery level reports
await this._requestHubPropertyValue(0x0d); // Request primary MAC address
this.emit("connect");
debug("LPF2Hub connected");
resolve();
});
}
@ -131,7 +135,12 @@ export class LPF2Hub extends BaseHub {
switch (message[2]) {
case 0x01: {
this._parseDeviceInfo(message);
const property = message[3];
const callback = this._propertyRequestCallbacks[property];
if (callback) {
callback(message);
}
delete this._propertyRequestCallbacks[property];
break;
}
case 0x04: {
@ -164,7 +173,23 @@ export class LPF2Hub extends BaseHub {
}
private _parseDeviceInfo (message: Buffer) {
private _requestHubPropertyValue (property: number) {
return new Promise((resolve) => {
this._propertyRequestCallbacks[property] = (message) => {
this._parseHubPropertyResponse(message);
return resolve();
};
this.send(Buffer.from([0x01, property, 0x05]), Consts.BLECharacteristic.LPF2_ALL);
});
}
private _requestHubPropertyReports (property: number) {
this.send(Buffer.from([0x01, property, 0x02]), Consts.BLECharacteristic.LPF2_ALL);
}
private _parseHubPropertyResponse (message: Buffer) {
// Button press reports
if (message[3] === 0x02) {
@ -356,45 +381,6 @@ export class LPF2Hub extends BaseHub {
device.receive(message);
}
// if ((data[3] === 0x3d && this.type === Consts.HubType.CONTROL_PLUS_HUB)) { // Control+ CPU Temperature
// /**
// * Emits when a change is detected on a temperature sensor. Measured in degrees centigrade.
// * @event LPF2Hub#temp
// * @param {string} port For Control+ Hubs, port will be "CPU" as the sensor reports CPU temperature.
// * @param {number} temp
// */
// this.emit("temp", "CPU", ((data.readInt16LE(4) / 900) * 90).toFixed(2));
// return;
// }
// const port = this._getPortForPortNumber(data[3]);
// if (!port) {
// return;
// }
// if (port && port.connected) {
// switch (port.type) {
// case Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR: {
// if (data[4] <= 10) {
// this.emit("color", port.id, data[4]);
// }
// break;
// }
// case Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER: {
// /**
// * Emits on a speed change.
// * @event LPF2Hub#speed
// * @param {string} port
// * @param {number} speed
// */
// const speed = data.readInt16LE(4);
// this.emit("speed", port.id, speed);
// break;
// }
// }
// }
}