Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rework event timer comands
Browse files Browse the repository at this point in the history
use new PortOutputSleep instead of timer;
 * the promise returned by rampPower and rampBrightness gets
   resolved if the command is interrupted.
 * rampPower and rampBrightness can no longer be altered by
   other commands while in progress. Other commands now queue
   after the ramp command or interrupt and stop its execution.
Debenben committed Jun 6, 2022
1 parent a8c3a97 commit 407922d
Showing 6 changed files with 52 additions and 62 deletions.
6 changes: 3 additions & 3 deletions src/consts.ts
Original file line number Diff line number Diff line change
@@ -706,12 +706,12 @@ export enum MarioColor {

/**
* @typedef CommandFeedback
* @param {number} TRANSMISSION_PENDING 0x00 waiting for previous comands to complete transmission or execution
* @param {number} TRANSMISSION_PENDING 0x00 waiting for previous commands to complete transmission or execution
* @param {number} TRANSMISSION_BUSY 0x10 waiting for device to acknowledge reception
* @param {number} TRANSMISSION_DISCARDED 0x44 other command for immediate execution has been recieved or device disconnected
* @param {number} TRANSMISSION_DISCARDED 0x44 interrupt command has been recieved or device disconnected
* @param {number} EXECUTION_PENDING 0x20 device is waiting for previous command to complete
* @param {number} EXECUTION_BUSY 0x21 device is executing the command
* @param {number} EXECUTION_DISCARDED 0x24 device discarded the command e.g. due to other command for immediate execution
* @param {number} EXECUTION_DISCARDED 0x24 device discarded the command e.g. due to interrupt
* @param {number} EXECUTION_COMPLETED 0x22 device reported successful completion of command
* @param {number} FEEDBACK_MISSING 0x66 device disconnected or failed to report feedback
* @param {number} FEEDBACK_DISABLED 0x26 feedback not implemented for this command
16 changes: 5 additions & 11 deletions src/devices/basicmotor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Device } from "./device";

import { IDeviceInterface } from "../interfaces";

import * as Consts from "../consts";

import { calculateRamp, mapSpeed } from "../utils";

/**
@@ -39,15 +36,12 @@ export class BasicMotor extends Device {
* @returns {Promise<CommandFeedback>} Resolved upon completion of command.
*/
public rampPower (fromPower: number, toPower: number, time: number) {
return new Promise<Consts.CommandFeedback>((resolve) => {
calculateRamp(this, fromPower, toPower, time)
.on("changePower", (power) => {
this.setPower(power, false);
})
.on("finished", () => {
return resolve(Consts.CommandFeedback.FEEDBACK_DISABLED);
})
const powerValues = calculateRamp(fromPower, toPower, time);
powerValues.forEach(value => {
this.setPower(value);
this.addPortOutputSleep(Math.round(time/powerValues.length));
});
return this.setPower(toPower);
}


44 changes: 25 additions & 19 deletions src/devices/device.ts
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import { EventEmitter } from "events";

import { IDeviceInterface } from "../interfaces";
import { PortOutputCommand } from "../portoutputcommand";
import { PortOutputSleep } from "../portoutputsleep";

import * as Consts from "../consts";

@@ -19,7 +20,7 @@ export class Device extends EventEmitter {

protected _mode: number | undefined;
protected _bufferLength: number = 0;
protected _nextPortOutputCommands: PortOutputCommand[] = [];
protected _nextPortOutputCommands: (PortOutputCommand | PortOutputSleep)[] = [];
protected _transmittedPortOutputCommands: PortOutputCommand[] = [];

private _hub: IDeviceInterface;
@@ -30,7 +31,6 @@ export class Device extends EventEmitter {

private _isWeDo2SmartHub: boolean;
private _isVirtualPort: boolean = false;
private _eventTimer: NodeJS.Timer | null = null;

constructor (hub: IDeviceInterface, portId: number, modeMap: {[event: string]: number} = {}, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) {
super();
@@ -132,9 +132,6 @@ export class Device extends EventEmitter {
}

public writeDirect (mode: number, data: Buffer, interrupt: boolean = false) {
if (interrupt) {
this.cancelEventTimer();
}
if (this.isWeDo2SmartHub) {
return this.send(Buffer.concat([Buffer.from([this.portId, 0x01, 0x02]), data]), Consts.BLECharacteristic.WEDO2_MOTOR_VALUE_WRITE).then(() => { return Consts.CommandFeedback.FEEDBACK_DISABLED; });
} else {
@@ -183,15 +180,29 @@ export class Device extends EventEmitter {
this._nextPortOutputCommands = [];
return;
}
if(this._bufferLength !== this._transmittedPortOutputCommands.length) return;
if(!this._nextPortOutputCommands.length) return;
if(this._bufferLength < 2 || this._nextPortOutputCommands[0].interrupt) {
const nextCommand = this._nextPortOutputCommands[0];
if(nextCommand instanceof PortOutputSleep) {
if(nextCommand.state === Consts.CommandFeedback.EXECUTION_PENDING) {
nextCommand.state = Consts.CommandFeedback.EXECUTION_BUSY;
debug("sleep command ", nextCommand.duration);
setTimeout(() => {
const command = this._nextPortOutputCommands.shift();
if(command) command.resolve(Consts.CommandFeedback.EXECUTION_COMPLETED);
this.transmitNextPortOutputCommand();
}, nextCommand.duration);
}
return;
}
if(this._bufferLength !== this._transmittedPortOutputCommands.length) return;
if(this._bufferLength < 2 || nextCommand.interrupt) {
const command = this._nextPortOutputCommands.shift();
if(command) {
debug("transmit command ", command.startupAndCompletion, command.data);
this.send(Buffer.concat([Buffer.from([0x81, this.portId, command.startupAndCompletion]), command.data]));
command.state = Consts.CommandFeedback.TRANSMISSION_BUSY;
this._transmittedPortOutputCommands.push(command);
this.transmitNextPortOutputCommand(); // if PortOutputSleep this starts timeout
// one could start a timer here to ensure finish function is called
}
}
@@ -214,6 +225,12 @@ export class Device extends EventEmitter {
return command.promise;
}

public addPortOutputSleep(duration: number) {
const command = new PortOutputSleep(duration);
this._nextPortOutputCommands.push(command);
return command.promise;
}

public finish (message: number) {
debug("recieved command feedback ", message);
if((message & 0x08) === 0x08) this._bufferLength = 0;
@@ -309,7 +326,7 @@ export class Device extends EventEmitter {
this._missing();
this._busy();
}
// third command can only be interrupt, if busy === 2 it was queued
// third command can only be interrupt, if this._bufferLength === 2 it was queued
else {
this._missing();
this._missing();
@@ -321,17 +338,6 @@ export class Device extends EventEmitter {
this.transmitNextPortOutputCommand();
}

public setEventTimer (timer: NodeJS.Timer) {
this._eventTimer = timer;
}

public cancelEventTimer () {
if (this._eventTimer) {
clearTimeout(this._eventTimer);
this._eventTimer = null;
}
}

private _ensureConnected () {
if (!this.connected) {
throw new Error("Device is not connected");
16 changes: 5 additions & 11 deletions src/devices/light.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Device } from "./device";

import { IDeviceInterface } from "../interfaces";

import * as Consts from "../consts";
import { calculateRamp } from "../utils";

@@ -39,16 +37,12 @@ export class Light extends Device {
* @returns {Promise<CommandFeedback>} Resolved upon completion of command.
*/
public rampBrightness (fromBrightness: number, toBrightness: number, time: number) {
return new Promise<Consts.CommandFeedback>((resolve) => {
calculateRamp(this, fromBrightness, toBrightness, time)
.on("changePower", (power) => {
this.setBrightness(power, false);
})
.on("finished", () => {
return resolve(Consts.CommandFeedback.FEEDBACK_DISABLED);
});
const powerValues = calculateRamp(fromBrightness, toBrightness, time);
powerValues.forEach(value => {
this.setBrightness(value);
this.addPortOutputSleep(Math.round(time/powerValues.length));
});
return this.setBrightness(toBrightness);
}


}
11 changes: 11 additions & 0 deletions src/portoutputsleep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CommandFeedback } from "./consts";
import { PortOutputCommand } from "./portoutputcommand";

export class PortOutputSleep extends PortOutputCommand {
public duration: number
constructor(duration: number) {
super(Buffer.alloc(0), false);
this.duration = duration;
this.state = CommandFeedback.EXECUTION_PENDING;
}
}
21 changes: 3 additions & 18 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ export const roundAngleToNearest90 = (angle: number) => {
return -180;
};

export const calculateRamp = (device: Device, fromPower: number, toPower: number, time: number) => {
export const calculateRamp = (fromPower: number, toPower: number, time: number) => {
const emitter = new EventEmitter();
const steps = Math.abs(toPower - fromPower);
let delay = time / steps;
@@ -71,27 +71,12 @@ export const calculateRamp = (device: Device, fromPower: number, toPower: number
if (fromPower > toPower) {
increment = -increment;
}
let i = 0;
const interval = setInterval(() => {
let power = Math.round(fromPower + (++i * increment));
if (toPower > fromPower && power > toPower) {
power = toPower;
} else if (fromPower > toPower && power < toPower) {
power = toPower;
}
emitter.emit("changePower", power);
if (power === toPower) {
clearInterval(interval);
emitter.emit("finished");
}
}, delay);
device.setEventTimer(interval);
return emitter;
return Array(Math.round(time/delay)).fill(0).map((element, index) => fromPower + index*increment);
};

export const parseColor = (color: number) => {
if (color === 1 || color === 5) {
color = color + 1;
}
return color;
}
}

0 comments on commit 407922d

Please sign in to comment.