Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add support for PWM resolutions other than 8-bit #1495

Merged
merged 1 commit into from Sep 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/board.js
Expand Up @@ -291,6 +291,7 @@ function Board(opts) {
this.transport = this.io.transport || null;
this.port = this.io.name;
this.pins = Board.Pins(this);
this.RESOLUTION = this.io.RESOLUTION || { ADC: 1023, DAC: null, PWM: 255 };
} else {

if (this.port && opts.port) {
Expand Down Expand Up @@ -459,6 +460,11 @@ function finalizeAndBroadcast(data, type, io) {
}.bind(this), 1);
}.bind(this));
}

// Older versions of Firmata and some IO plugins
// may not have set RESOLUTION.
this.RESOLUTION = io.RESOLUTION || { ADC: 1023, DAC: null, PWM: 255 };

}

// If there is a REPL...
Expand Down
1 change: 1 addition & 0 deletions lib/led/led.js
Expand Up @@ -83,6 +83,7 @@ var Controllers = {
var state = priv.get(this);
var output = typeof input !== "undefined" ? input : state.value;
var value = state.isAnode ? 255 - Board.constrain(output, 0, 255) : output;
value = Fn.map(value, 0, 255, 0, this.board.RESOLUTION.PWM);

// If pin is not a PWM pin and brightness is not HIGH or LOW, emit an error
if (value !== this.io.LOW && value !== this.io.HIGH && this.mode !== this.io.MODES.PWM) {
Expand Down
1 change: 1 addition & 0 deletions lib/led/rgb.js
Expand Up @@ -38,6 +38,7 @@ var Controllers = {
if (state.isAnode) {
value = 255 - Board.constrain(value, 0, 255);
}
value = Fn.map(value, 0, 255, 0, this.board.RESOLUTION.PWM);

this.io.analogWrite(pin, value);
}, this);
Expand Down
4 changes: 2 additions & 2 deletions lib/motor.js
Expand Up @@ -646,7 +646,7 @@ Motor.prototype.setPin = function(pin, value) {
};

Motor.prototype.setPWM = function(pin, value) {
this.io.analogWrite(pin, value);
this.io.analogWrite(pin, __.map(value, 0, 255, 0, this.board.RESOLUTION.PWM));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do a pass on this file and change __ to Fn? Probably in another patch?

};

Motor.prototype.speed = function(opts) {
Expand All @@ -663,7 +663,7 @@ Motor.prototype.speed = function(opts) {
}

opts.speed = Board.constrain(opts.speed, 0, 255);

opts.saveSpeed = typeof opts.saveSpeed !== "undefined" ?
opts.saveSpeed : true;

Expand Down
2 changes: 1 addition & 1 deletion lib/pin.js
Expand Up @@ -273,7 +273,7 @@ Pin.prototype.query = function(callback) {
*/

Pin.prototype.high = function() {
var value = this.type === "analog" ? 255 : 1;
var value = this.type === "analog" ? this.board.RESOLUTION.PWM : 1;
Pin.write(this, value);
this.emit("high");
return this;
Expand Down
6 changes: 6 additions & 0 deletions test/board.js
Expand Up @@ -47,6 +47,12 @@ exports["Board"] = {
new Board();
},

defaultResolution: function(test) {
test.expect(1);
test.deepEqual(this.board.RESOLUTION, {PWM: 255, DAC: null, ADC: 1023});
test.done();
},

explicitTransport: function(test) {
test.expect(1);

Expand Down
4 changes: 2 additions & 2 deletions test/extended/servo.js
Expand Up @@ -217,7 +217,7 @@ exports["Servo"] = {

this.servo.on("move:complete", function() {
test.equal(this.servo.value, 80);
test.equal(this.servoWrite.lastCall.args[1], 70);
test.equal(this.servoWrite.lastCall.args[1], 1300);
test.done();
}.bind(this));

Expand All @@ -237,7 +237,7 @@ exports["Servo"] = {

this.servo.on("move:complete", function() {
test.equal(this.servo.value, 80);
test.equal(this.servoWrite.lastCall.args[1], 110);
test.equal(this.servoWrite.lastCall.args[1], 1700);
test.done();
}.bind(this));

Expand Down
145 changes: 145 additions & 0 deletions test/led.js
Expand Up @@ -584,6 +584,151 @@ exports["Led - PWM"] = {
},
};

exports["Led - 10-bit PWM"] = {
setUp: function(done) {
this.board = newBoard();
this.sandbox = sinon.sandbox.create();
this.clock = this.sandbox.useFakeTimers();
this.analogWrite = this.sandbox.spy(MockFirmata.prototype, "analogWrite");
this.pinMode = this.sandbox.spy(MockFirmata.prototype, "pinMode");
this.enqueue = this.sandbox.stub(Animation.prototype, "enqueue");

// Override PWM Resolution
this.board.RESOLUTION.PWM = 1023;

this.led = new Led({
pin: 11,
board: this.board
});

done();
},

tearDown: function(done) {
Board.purge();
this.sandbox.restore();
done();
},

shape: testLedShape,

on: function(test) {
test.expect(2);

this.led.on();
test.ok(this.analogWrite.firstCall.calledWith(11, 1023));
test.equal(this.analogWrite.callCount, 1);
test.done();
},

onFromNull: function(test) {
test.expect(4);

this.mapget = this.sandbox.spy(Map.prototype, "get");

this.led = new Led({
pin: 11,
board: this.board
});

var state = this.mapget.lastCall.returnValue;

test.equal(state.value, null);

this.led.on();

test.equal(state.value, 255);
test.equal(this.analogWrite.callCount, 1);
test.ok(this.analogWrite.firstCall.calledWith(11, 1023));
test.done();
},

off: function(test) {
test.expect(2);

this.led.off();
test.ok(this.analogWrite.firstCall.calledWith(11, 0));
test.equal(this.analogWrite.callCount, 1);

test.done();
},

blink: function(test) {
test.expect(4);
/*
This test is incredibly important!

What this is asserting is that blinking PWM LED will
analogWrite the correct value of 255 when there is an
ACTIVE interval and the last value was 0.
*/
this.mapget = this.sandbox.spy(Map.prototype, "get");

this.led.off();
test.equal(this.led.isOn, false);

this.led.blink(1);

var state = this.mapget.lastCall.returnValue;

test.equal(state.value, 0);

this.clock.tick(1);
test.equal(this.led.isOn, true);
test.ok(this.analogWrite.lastCall.calledWith(11, 1023));

test.done();
},

toggle: function(test) {
test.expect(5);

this.led.off();
this.analogWrite.reset();

this.led.toggle();
test.ok(this.analogWrite.lastCall.calledWith(11, 1023));
test.ok(this.led.isOn);

this.led.toggle();
test.ok(this.analogWrite.lastCall.calledWith(11, 0));
test.ok(!this.led.isOn);

test.equal(this.analogWrite.callCount, 2);

test.done();
},

brightness: function(test) {
test.expect(4);

this.led.off();
this.analogWrite.reset();

this.led.brightness(255);
test.ok(this.analogWrite.lastCall.calledWith(11, 1023));

this.led.brightness(100);
test.ok(this.analogWrite.lastCall.calledWith(11, 401));

this.led.brightness(0);
test.ok(this.analogWrite.lastCall.calledWith(11, 0));

test.equal(this.analogWrite.callCount, 3);

test.done();
},

pulse: function(test) {
test.expect(1);

this.led.pulse();

test.equal(this.enqueue.callCount, 1);
test.done();
}
};

exports["Led - PCA9685 (I2C)"] = {
setUp: function(done) {
this.board = newBoard();
Expand Down