johnny-five-electron
Version:
Temporary fork to support Electron (to be deprecated)
1,991 lines (1,537 loc) • 42.5 kB
JavaScript
var Emitter = require("events").EventEmitter;
var MockFirmata = require("./util/mock-firmata");
var controller = require("./util/mock-expander-controller");
var five = require("../lib/johnny-five.js");
var sinon = require("sinon");
var Board = five.Board;
var Expander = five.Expander;
var Led = five.Led;
var Button = five.Button;
function newBoard() {
var io = new MockFirmata();
var board = new Board({
io: io,
debug: false,
repl: false
});
io.emit("connect");
io.emit("ready");
return board;
}
function restore(target) {
for (var prop in target) {
if (Array.isArray(target[prop])) {
continue;
}
if (target[prop] != null && typeof target[prop].restore === "function") {
target[prop].restore();
}
if (typeof target[prop] === "object") {
restore(target[prop]);
}
}
}
exports["Expander"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.board = newBoard();
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
noparams: function(test) {
test.expect(1);
test.throws(function() {
new Expander();
});
test.done();
},
invalidControllerString: function(test) {
test.expect(1);
test.throws(function() {
new Expander("INVALID_CONTROLLER_STRING");
});
test.done();
},
validControllerString: function(test) {
test.expect(6);
[
"MCP23017",
"MCP23008",
"PCF8574",
"PCF8574A",
"PCF8575",
"PCA9685",
].forEach(function(controller) {
test.doesNotThrow(function() {
new Expander(controller);
});
});
test.done();
},
skipsPinNormalizationCall: function(test) {
test.expect(6);
this.normalize = sinon.spy(Board.Pins, "normalize");
[
"MCP23017",
"MCP23008",
"PCF8574",
"PCF8574A",
"PCF8575",
"PCA9685",
].forEach(function(controller) {
new Expander(controller);
test.equal(this.normalize.called, false);
}, this);
test.done();
},
noController: function(test) {
test.expect(1);
test.throws(function() {
new Expander({
board: this.board
});
}.bind(this));
test.done();
},
userController: function(test) {
test.expect(1);
test.doesNotThrow(function() {
new Expander({
board: this.board,
controller: {}
});
}.bind(this));
test.done();
},
emitter: function(test) {
test.expect(1);
var expander = new Expander({
board: this.board,
controller: "PCA9685"
});
test.ok(expander instanceof Emitter);
test.done();
},
initializes: function(test) {
test.expect(1);
this.initialize = sinon.spy(controller.initialize, "value");
new Expander({
board: this.board,
controller: controller
});
test.equal(this.initialize.callCount, 1);
test.done();
},
virtualBoardBase: function(test) {
test.expect(5);
var expander = new Expander({
board: this.board,
controller: controller
});
test.equal(expander.HIGH, 1);
test.equal(expander.LOW, 0);
test.deepEqual(expander.MODES, {});
test.deepEqual(expander.pins, []);
test.deepEqual(expander.analogPins, []);
test.done();
},
virtualBoard: function(test) {
test.expect(13);
this.initialize = sinon.stub(controller.initialize, "value", function() {
this.MODES.INPUT = this.io.MODES.INPUT;
this.MODES.OUTPUT = this.io.MODES.OUTPUT;
for (var i = 0; i < 8; i++) {
this.pins.push({
supportedModes: [
this.io.MODES.INPUT,
this.io.MODES.OUTPUT
],
mode: 0,
value: 0,
report: 0,
analogChannel: 127
});
this.pinMode(i, this.MODES.OUTPUT);
this.digitalWrite(i, this.LOW);
}
this.name = "Expander:SOME_CHIP";
this.isReady = true;
});
this.pinMode = sinon.spy(controller.pinMode, "value");
this.digitalWrite = sinon.spy(controller.digitalWrite, "value");
this.digitalRead = sinon.spy(controller.digitalRead, "value");
var expander = new Expander({
board: this.board,
controller: controller
});
var board = new Board.Virtual({
io: expander
});
test.equal(this.initialize.callCount, 1);
test.equal(this.pinMode.callCount, 8);
test.equal(this.digitalWrite.callCount, 8);
test.equal(expander.MODES.INPUT, this.board.io.MODES.INPUT);
test.equal(expander.MODES.OUTPUT, this.board.io.MODES.OUTPUT);
var led = new Led({
pin: 0,
board: board
});
led.on();
led.off();
test.equal(this.pinMode.callCount, 9);
test.equal(this.digitalWrite.callCount, 10);
test.deepEqual(this.pinMode.lastCall.args, [0, 1]);
test.deepEqual(this.digitalWrite.getCall(8).args, [0, 1]);
test.deepEqual(this.digitalWrite.getCall(9).args, [0, 0]);
var button = new Button({
pin: 1,
board: board
});
var callback = this.digitalRead.args[0][1];
test.equal(this.pinMode.callCount, 10);
test.equal(this.digitalRead.callCount, 1);
// Fake timers and debounce don't play well.
button.on("down", function() {
test.ok(true);
test.done();
});
callback(button.downValue);
},
};
exports["Expander.Active"] = {
setUp: function(done) {
this.board = newBoard();
this.expander = new Expander({
controller: "PCF8574",
board: this.board
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
has: function(test) {
test.expect(4);
test.equal(Expander.Active.has({ address: 0x20 }), true);
test.equal(Expander.Active.has({ controller: "PCF8574" }), true);
test.equal(Expander.Active.has({ address: 0x20, controller: "PCF8574" }), true);
test.equal(Expander.Active.has({ address: 0x20, controller: "ANOTHER" }), true);
test.done();
},
byAddress: function(test) {
test.expect(2);
test.equal(Expander.Active.byAddress(0x20), this.expander);
test.equal(Expander.Active.byAddress(0x38), undefined);
test.done();
},
byController: function(test) {
test.expect(2);
test.equal(Expander.Active.byController("PCF8574"), this.expander);
test.equal(Expander.Active.byController("ANOTHER"), undefined);
test.done();
},
};
exports["Expander - MCP23017"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "MCP23017",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "MCP23017",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(34);
test.equal(this.i2cConfig.callCount, 1);
// 2 initialization calls + (16 * (pinMode + digitalWrite))
test.equal(this.i2cWrite.callCount, 34);
// console.log(this.i2cWrite.getCall(0).args);
// 2 For initialization
test.deepEqual(this.i2cWrite.getCall(0).args, [ 32, [ 0, 255 ] ]);
test.deepEqual(this.i2cWrite.getCall(1).args, [ 32, [ 1, 255 ] ]);
var byte = 0x100;
var dir = 0;
var gpio = 18;
var multiple = 2;
for (var i = 2; i < 32; i += 2) {
if (i === 18) {
dir = 1;
gpio = 19;
multiple = 2;
}
test.deepEqual(this.i2cWrite.getCall(i).args, [ 32, [ dir, byte - multiple ] ]);
test.deepEqual(this.i2cWrite.getCall(i + 1).args, [ 32, [ gpio, byte - multiple ] ]);
multiple <<= 1;
}
test.done();
},
normalize: function(test) {
test.expect(16);
for (var i = 0; i < 16; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinMode: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 0);
}
var expects = [
[ 32, [ 0, 1 ] ],
[ 32, [ 0, 3 ] ],
[ 32, [ 0, 7 ] ],
[ 32, [ 0, 15 ] ],
[ 32, [ 0, 31 ] ],
[ 32, [ 0, 63 ] ],
[ 32, [ 0, 127 ] ],
[ 32, [ 0, 255 ] ],
[ 32, [ 1, 1 ] ],
[ 32, [ 1, 3 ] ],
[ 32, [ 1, 7 ] ],
[ 32, [ 1, 15 ] ],
[ 32, [ 1, 31 ] ],
[ 32, [ 1, 63 ] ],
[ 32, [ 1, 127 ] ],
[ 32, [ 1, 255 ] ]
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 32, [ 18, 1 ] ],
[ 32, [ 18, 3 ] ],
[ 32, [ 18, 7 ] ],
[ 32, [ 18, 15 ] ],
[ 32, [ 18, 31 ] ],
[ 32, [ 18, 63 ] ],
[ 32, [ 18, 127 ] ],
[ 32, [ 18, 255 ] ],
[ 32, [ 19, 1 ] ],
[ 32, [ 19, 3 ] ],
[ 32, [ 19, 7 ] ],
[ 32, [ 19, 15 ] ],
[ 32, [ 19, 31 ] ],
[ 32, [ 19, 63 ] ],
[ 32, [ 19, 127 ] ],
[ 32, [ 19, 255 ] ]
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
pullUp: function(test) {
test.expect(1);
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.pullUp(j, 1);
}
var expects = [
[ 32, [ 12, 1 ] ],
[ 32, [ 12, 3 ] ],
[ 32, [ 12, 7 ] ],
[ 32, [ 12, 15 ] ],
[ 32, [ 12, 31 ] ],
[ 32, [ 12, 63 ] ],
[ 32, [ 12, 127 ] ],
[ 32, [ 12, 255 ] ],
[ 32, [ 13, 1 ] ],
[ 32, [ 13, 3 ] ],
[ 32, [ 13, 7 ] ],
[ 32, [ 13, 15 ] ],
[ 32, [ 13, 31 ] ],
[ 32, [ 13, 63 ] ],
[ 32, [ 13, 127 ] ],
[ 32, [ 13, 255 ] ]
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalRead: function(test) {
test.expect(1);
var spy = sinon.spy();
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 1);
}
this.i2cRead.reset();
for (var j = 0; j < 16; j++) {
this.expander.digitalRead(j, spy);
}
var expects = [
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 18, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ],
[ 32, 19, 1 ]
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.done();
},
unsupported: function(test) {
test.expect(10);
sinon.spy(this.expander, "analogWrite");
test.throws(this.expander.analogWrite);
test.equal(
this.expander.analogWrite.lastCall.exception.message,
"Expander:MCP23017 does not support analogWrite"
);
sinon.spy(this.expander, "servoWrite");
test.throws(this.expander.servoWrite);
test.equal(
this.expander.servoWrite.lastCall.exception.message,
"Expander:MCP23017 does not support servoWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:MCP23017 does not support i2cWrite"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:MCP23017 does not support analogRead"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:MCP23017 does not support i2cRead"
);
test.done();
},
};
exports["Expander - MCP23008"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "MCP23008",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "MCP23008",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(19);
test.equal(this.i2cConfig.callCount, 1);
// 2 initialization calls + (16 * (pinMode + digitalWrite))
test.equal(this.i2cWrite.callCount, 17);
// console.log(this.i2cWrite.getCall(0).args);
// 2 For initialization
test.deepEqual(this.i2cWrite.getCall(0).args, [ 32, [ 0, 255 ] ]);
var byte = 0x100;
var dir = 0;
var gpio = 9;
var multiple = 2;
for (var i = 1; i < 16; i += 2) {
test.deepEqual(this.i2cWrite.getCall(i).args, [ 32, [ dir, byte - multiple ] ]);
test.deepEqual(this.i2cWrite.getCall(i + 1).args, [ 32, [ gpio, byte - multiple ] ]);
multiple <<= 1;
}
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinMode: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 0);
}
var expects = [
[ 32, [ 0, 1 ] ],
[ 32, [ 0, 3 ] ],
[ 32, [ 0, 7 ] ],
[ 32, [ 0, 15 ] ],
[ 32, [ 0, 31 ] ],
[ 32, [ 0, 63 ] ],
[ 32, [ 0, 127 ] ],
[ 32, [ 0, 255 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 32, [ 9, 1 ] ],
[ 32, [ 9, 3 ] ],
[ 32, [ 9, 7 ] ],
[ 32, [ 9, 15 ] ],
[ 32, [ 9, 31 ] ],
[ 32, [ 9, 63 ] ],
[ 32, [ 9, 127 ] ],
[ 32, [ 9, 255 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
pullUp: function(test) {
test.expect(1);
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 8; j++) {
this.expander.pullUp(j, 1);
}
var expects = [
[ 32, [ 6, 1 ] ],
[ 32, [ 6, 3 ] ],
[ 32, [ 6, 7 ] ],
[ 32, [ 6, 15 ] ],
[ 32, [ 6, 31 ] ],
[ 32, [ 6, 63 ] ],
[ 32, [ 6, 127 ] ],
[ 32, [ 6, 255 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalRead: function(test) {
test.expect(1);
var spy = sinon.spy();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cRead.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalRead(j, spy);
}
var expects = [
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ],
[ 32, 9, 1 ]
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.done();
},
unsupported: function(test) {
test.expect(10);
sinon.spy(this.expander, "analogWrite");
test.throws(this.expander.analogWrite);
test.equal(
this.expander.analogWrite.lastCall.exception.message,
"Expander:MCP23008 does not support analogWrite"
);
sinon.spy(this.expander, "servoWrite");
test.throws(this.expander.servoWrite);
test.equal(
this.expander.servoWrite.lastCall.exception.message,
"Expander:MCP23008 does not support servoWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:MCP23008 does not support i2cWrite"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:MCP23008 does not support analogRead"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:MCP23008 does not support i2cRead"
);
test.done();
},
};
exports["Expander - PCF8574"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "PCF8574",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "PCF8574",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(4);
test.equal(this.i2cConfig.callCount, 1);
// 1 initialization call + (8 * (pinMode + digitalWrite))
test.equal(this.i2cWrite.callCount, 16);
test.deepEqual(this.i2cWrite.getCall(0).args, [ 32, 0 ]);
test.deepEqual(this.i2cWrite.args, [
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ]
]);
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinModeInput: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 0);
}
var expects = [
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
pinModeOutput: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
var expects = [
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
[ 32, 0 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 32, 1 ],
[ 32, 3 ],
[ 32, 7 ],
[ 32, 15 ],
[ 32, 31 ],
[ 32, 63 ],
[ 32, 127 ],
[ 32, 255 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalRead: function(test) {
test.expect(1);
var spy = sinon.spy();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cRead.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalRead(j, spy);
}
var expects = [
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ],
[ 32, 1 ]
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.done();
},
unsupported: function(test) {
test.expect(10);
sinon.spy(this.expander, "analogWrite");
test.throws(this.expander.analogWrite);
test.equal(
this.expander.analogWrite.lastCall.exception.message,
"Expander:PCF8574 does not support analogWrite"
);
sinon.spy(this.expander, "servoWrite");
test.throws(this.expander.servoWrite);
test.equal(
this.expander.servoWrite.lastCall.exception.message,
"Expander:PCF8574 does not support servoWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:PCF8574 does not support i2cWrite"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:PCF8574 does not support analogRead"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:PCF8574 does not support i2cRead"
);
test.done();
},
};
exports["Expander - PCF8574A"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "PCF8574A",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "PCF8574A",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(4);
test.equal(this.i2cConfig.callCount, 1);
// 1 initialization call + (8 * (pinMode + digitalWrite))
test.equal(this.i2cWrite.callCount, 16);
test.deepEqual(this.i2cWrite.getCall(0).args, [ 56, 0 ]);
test.deepEqual(this.i2cWrite.args, [
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ]
]);
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinModeInput: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 0);
}
var expects = [
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
pinModeOutput: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
var expects = [
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
[ 56, 0 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 56, 1 ],
[ 56, 3 ],
[ 56, 7 ],
[ 56, 15 ],
[ 56, 31 ],
[ 56, 63 ],
[ 56, 127 ],
[ 56, 255 ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalRead: function(test) {
test.expect(1);
var spy = sinon.spy();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cRead.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalRead(j, spy);
}
var expects = [
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ],
[ 56, 1 ]
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.done();
},
unsupported: function(test) {
test.expect(10);
sinon.spy(this.expander, "analogWrite");
test.throws(this.expander.analogWrite);
test.equal(
this.expander.analogWrite.lastCall.exception.message,
"Expander:PCF8574A does not support analogWrite"
);
sinon.spy(this.expander, "servoWrite");
test.throws(this.expander.servoWrite);
test.equal(
this.expander.servoWrite.lastCall.exception.message,
"Expander:PCF8574A does not support servoWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:PCF8574A does not support i2cWrite"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:PCF8574A does not support analogRead"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:PCF8574A does not support i2cRead"
);
test.done();
},
};
exports["Expander - PCF8575"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "PCF8575",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "PCF8575",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(4);
test.equal(this.i2cConfig.callCount, 1);
// 1 initialization call + (8 * (pinMode + digitalWrite))
test.equal(this.i2cWrite.callCount, 17);
test.deepEqual(this.i2cWrite.getCall(0).args, [ 32, [ 0, 0 ] ]);
test.deepEqual(this.i2cWrite.args, [
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
[ 32, [ 0, 0 ] ],
]);
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinMode: function(test) {
test.expect(1);
this.i2cWrite.reset();
test.equal(this.i2cWrite.callCount, 0);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
[ 32, [ 255, 0 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
digitalRead: function(test) {
test.expect(1);
var spy = sinon.spy();
for (var i = 0; i < 8; i++) {
this.expander.pinMode(i, 1);
}
this.i2cRead.reset();
for (var j = 0; j < 8; j++) {
this.expander.digitalRead(j, spy);
}
var expects = [
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
[ 32, 2 ],
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.done();
},
unsupported: function(test) {
test.expect(10);
sinon.spy(this.expander, "analogWrite");
test.throws(this.expander.analogWrite);
test.equal(
this.expander.analogWrite.lastCall.exception.message,
"Expander:PCF8575 does not support analogWrite"
);
sinon.spy(this.expander, "servoWrite");
test.throws(this.expander.servoWrite);
test.equal(
this.expander.servoWrite.lastCall.exception.message,
"Expander:PCF8575 does not support servoWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:PCF8575 does not support i2cWrite"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:PCF8575 does not support analogRead"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:PCF8575 does not support i2cRead"
);
test.done();
},
};
exports["Expander - PCA9685"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWriteReg = sinon.spy(MockFirmata.prototype, "i2cWriteReg");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "PCA9685",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "PCA9685",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(4);
test.equal(this.i2cConfig.callCount, 1);
test.equal(this.i2cWrite.callCount, 16);
//(8 * (pinMode + digitalWrite))
test.equal(this.i2cWriteReg.callCount, 5);
test.deepEqual(this.i2cWrite.args, [
[ 64, [ 6, 0, 0, 0, 0 ] ],
[ 64, [ 10, 0, 0, 0, 0 ] ],
[ 64, [ 14, 0, 0, 0, 0 ] ],
[ 64, [ 18, 0, 0, 0, 0 ] ],
[ 64, [ 22, 0, 0, 0, 0 ] ],
[ 64, [ 26, 0, 0, 0, 0 ] ],
[ 64, [ 30, 0, 0, 0, 0 ] ],
[ 64, [ 34, 0, 0, 0, 0 ] ],
[ 64, [ 38, 0, 0, 0, 0 ] ],
[ 64, [ 42, 0, 0, 0, 0 ] ],
[ 64, [ 46, 0, 0, 0, 0 ] ],
[ 64, [ 50, 0, 0, 0, 0 ] ],
[ 64, [ 54, 0, 0, 0, 0 ] ],
[ 64, [ 58, 0, 0, 0, 0 ] ],
[ 64, [ 62, 0, 0, 0, 0 ] ],
[ 64, [ 66, 0, 0, 0, 0 ] ]
]);
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinMode: function(test) {
test.expect(2);
this.i2cWrite.reset();
this.i2cWriteReg.reset();
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 0);
}
// No calls are made, pinMode is purely for compatibility
test.deepEqual(this.i2cWrite.callCount, 0);
test.deepEqual(this.i2cWriteReg.callCount, 0);
test.done();
},
digitalWrite: function(test) {
test.expect(1);
for (var i = 0; i < 16; i++) {
this.expander.pinMode(i, 1);
}
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.digitalWrite(j, 1);
}
var expects = [
[ 64, [ 6, 0, 0, 4095, 15 ] ],
[ 64, [ 10, 0, 0, 4095, 15 ] ],
[ 64, [ 14, 0, 0, 4095, 15 ] ],
[ 64, [ 18, 0, 0, 4095, 15 ] ],
[ 64, [ 22, 0, 0, 4095, 15 ] ],
[ 64, [ 26, 0, 0, 4095, 15 ] ],
[ 64, [ 30, 0, 0, 4095, 15 ] ],
[ 64, [ 34, 0, 0, 4095, 15 ] ],
[ 64, [ 38, 0, 0, 4095, 15 ] ],
[ 64, [ 42, 0, 0, 4095, 15 ] ],
[ 64, [ 46, 0, 0, 4095, 15 ] ],
[ 64, [ 50, 0, 0, 4095, 15 ] ],
[ 64, [ 54, 0, 0, 4095, 15 ] ],
[ 64, [ 58, 0, 0, 4095, 15 ] ],
[ 64, [ 62, 0, 0, 4095, 15 ] ],
[ 64, [ 66, 0, 0, 4095, 15 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
pwmWrite: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.pwmWrite(j, 255);
}
var expects = [
[ 64, [ 6, 0, 0, 4095, 15 ] ],
[ 64, [ 10, 0, 0, 4095, 15 ] ],
[ 64, [ 14, 0, 0, 4095, 15 ] ],
[ 64, [ 18, 0, 0, 4095, 15 ] ],
[ 64, [ 22, 0, 0, 4095, 15 ] ],
[ 64, [ 26, 0, 0, 4095, 15 ] ],
[ 64, [ 30, 0, 0, 4095, 15 ] ],
[ 64, [ 34, 0, 0, 4095, 15 ] ],
[ 64, [ 38, 0, 0, 4095, 15 ] ],
[ 64, [ 42, 0, 0, 4095, 15 ] ],
[ 64, [ 46, 0, 0, 4095, 15 ] ],
[ 64, [ 50, 0, 0, 4095, 15 ] ],
[ 64, [ 54, 0, 0, 4095, 15 ] ],
[ 64, [ 58, 0, 0, 4095, 15 ] ],
[ 64, [ 62, 0, 0, 4095, 15 ] ],
[ 64, [ 66, 0, 0, 4095, 15 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
servoWrite: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.servoWrite(j, 180);
}
var expects = [
[ 64, [ 6, 0, 0, 4095, 15 ] ],
[ 64, [ 10, 0, 0, 4095, 15 ] ],
[ 64, [ 14, 0, 0, 4095, 15 ] ],
[ 64, [ 18, 0, 0, 4095, 15 ] ],
[ 64, [ 22, 0, 0, 4095, 15 ] ],
[ 64, [ 26, 0, 0, 4095, 15 ] ],
[ 64, [ 30, 0, 0, 4095, 15 ] ],
[ 64, [ 34, 0, 0, 4095, 15 ] ],
[ 64, [ 38, 0, 0, 4095, 15 ] ],
[ 64, [ 42, 0, 0, 4095, 15 ] ],
[ 64, [ 46, 0, 0, 4095, 15 ] ],
[ 64, [ 50, 0, 0, 4095, 15 ] ],
[ 64, [ 54, 0, 0, 4095, 15 ] ],
[ 64, [ 58, 0, 0, 4095, 15 ] ],
[ 64, [ 62, 0, 0, 4095, 15 ] ],
[ 64, [ 66, 0, 0, 4095, 15 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
analogWrite: function(test) {
test.expect(1);
this.i2cWrite.reset();
for (var j = 0; j < 16; j++) {
this.expander.analogWrite(j, 255);
}
var expects = [
[ 64, [ 6, 0, 0, 4095, 15 ] ],
[ 64, [ 10, 0, 0, 4095, 15 ] ],
[ 64, [ 14, 0, 0, 4095, 15 ] ],
[ 64, [ 18, 0, 0, 4095, 15 ] ],
[ 64, [ 22, 0, 0, 4095, 15 ] ],
[ 64, [ 26, 0, 0, 4095, 15 ] ],
[ 64, [ 30, 0, 0, 4095, 15 ] ],
[ 64, [ 34, 0, 0, 4095, 15 ] ],
[ 64, [ 38, 0, 0, 4095, 15 ] ],
[ 64, [ 42, 0, 0, 4095, 15 ] ],
[ 64, [ 46, 0, 0, 4095, 15 ] ],
[ 64, [ 50, 0, 0, 4095, 15 ] ],
[ 64, [ 54, 0, 0, 4095, 15 ] ],
[ 64, [ 58, 0, 0, 4095, 15 ] ],
[ 64, [ 62, 0, 0, 4095, 15 ] ],
[ 64, [ 66, 0, 0, 4095, 15 ] ],
];
test.deepEqual(this.i2cWrite.args, expects);
test.done();
},
unsupported: function(test) {
test.expect(8);
sinon.spy(this.expander, "digitalRead");
test.throws(this.expander.digitalRead);
test.equal(
this.expander.digitalRead.lastCall.exception.message,
"Expander:PCA9685 does not support digitalRead"
);
sinon.spy(this.expander, "analogRead");
test.throws(this.expander.analogRead);
test.equal(
this.expander.analogRead.lastCall.exception.message,
"Expander:PCA9685 does not support analogRead"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:PCA9685 does not support i2cWrite"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:PCA9685 does not support i2cRead"
);
test.done();
},
};
exports["Expander - PCF8591"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig");
this.i2cWrite = sinon.spy(MockFirmata.prototype, "i2cWrite");
this.i2cRead = sinon.spy(MockFirmata.prototype, "i2cRead");
this.board = newBoard();
this.expander = new Expander({
controller: "PCF8591",
board: this.board
});
this.virtual = new Board.Virtual({
io: this.expander
});
done();
},
tearDown: function(done) {
Board.purge();
Expander.purge();
restore(this);
done();
},
fwdOptionsToi2cConfig: function(test) {
test.expect(3);
this.i2cConfig.reset();
new Expander({
controller: "PCF8591",
address: 0xff,
bus: "i2c-1",
board: this.board
});
var forwarded = this.i2cConfig.lastCall.args[0];
test.equal(this.i2cConfig.callCount, 1);
test.equal(forwarded.address, 0xff);
test.equal(forwarded.bus, "i2c-1");
test.done();
},
initialization: function(test) {
test.expect(2);
test.equal(this.i2cConfig.callCount, 1);
test.equal(this.i2cWrite.callCount, 1);
test.done();
},
normalize: function(test) {
test.expect(8);
for (var i = 0; i < 8; i++) {
test.equal(this.expander.normalize(i), i);
}
test.done();
},
pinMode: function(test) {
test.expect(5);
this.i2cWrite.reset();
for (var i = 0; i < 4; i++) {
this.expander.pinMode(i, 2);
}
test.equal(this.expander.pins[0].mode, 2);
test.equal(this.expander.pins[1].mode, 2);
test.equal(this.expander.pins[2].mode, 2);
test.equal(this.expander.pins[3].mode, 2);
test.deepEqual(this.i2cWrite.callCount, 0);
test.done();
},
analogRead: function(test) {
test.expect(4);
var spy = sinon.spy();
for (var i = 0; i < 4; i++) {
this.expander.pinMode(i, 2);
}
this.i2cRead.reset();
for (var j = 0; j < 4; j++) {
this.expander.analogRead(j, spy);
}
var expects = [
[ 72, 4 ],
];
test.deepEqual(
this.i2cRead.args.map(function(args) { return args.slice(0, -1); }),
expects
);
test.equal(this.i2cRead.callCount, 1);
var callback = this.i2cRead.lastCall.args[2];
callback([0x00, 0x0f, 0xf0, 0xff]);
test.equal(spy.callCount, 4);
test.deepEqual(
spy.args.map(function(args) { return args[0]; }),
[0x00 << 2, 0x0f << 2, 0xf0 << 2, 0xff << 2]
);
test.done();
},
unsupported: function(test) {
test.expect(8);
sinon.spy(this.expander, "digitalRead");
test.throws(this.expander.digitalRead);
test.equal(
this.expander.digitalRead.lastCall.exception.message,
"Expander:PCF8591 does not support digitalRead"
);
sinon.spy(this.expander, "digitalWrite");
test.throws(this.expander.digitalWrite);
test.equal(
this.expander.digitalWrite.lastCall.exception.message,
"Expander:PCF8591 does not support digitalWrite"
);
sinon.spy(this.expander, "i2cWrite");
test.throws(this.expander.i2cWrite);
test.equal(
this.expander.i2cWrite.lastCall.exception.message,
"Expander:PCF8591 does not support i2cWrite"
);
sinon.spy(this.expander, "i2cRead");
test.throws(this.expander.i2cRead);
test.equal(
this.expander.i2cRead.lastCall.exception.message,
"Expander:PCF8591 does not support i2cRead"
);
test.done();
},
};