Skip to content

Commit

Permalink
Add support for PWM resolutions other than 8-bit
Browse files Browse the repository at this point in the history
Required for ESP32. Addresses #1275, #1276, and #1280
  • Loading branch information
dtex committed Aug 26, 2018
1 parent 210aaf4 commit b73a1d5
Show file tree
Hide file tree
Showing 11 changed files with 640 additions and 4 deletions.
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));
};

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
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

0 comments on commit b73a1d5

Please sign in to comment.