Skip to content

Commit

Permalink
Track port value state internally
Browse files Browse the repository at this point in the history
Signed-off-by: Rick Waldron <waldron.rick@gmail.com>
  • Loading branch information
rwaldron committed Mar 15, 2016
1 parent 2f5dcd7 commit b8e7bf8
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 16 deletions.
37 changes: 26 additions & 11 deletions lib/firmata.js
Expand Up @@ -120,8 +120,8 @@ MIDI_RESPONSE[REPORT_VERSION] = function(board) {
*/

MIDI_RESPONSE[ANALOG_MESSAGE] = function(board) {
var value = board.currentBuffer[1] | (board.currentBuffer[2] << 7);
var pin = board.currentBuffer[0] & 0x0F;
var value = board.currentBuffer[1] | (board.currentBuffer[2] << 7);

if (board.pins[board.analogPins[pin]]) {
board.pins[board.analogPins[pin]].value = value;
Expand Down Expand Up @@ -152,8 +152,17 @@ MIDI_RESPONSE[DIGITAL_MESSAGE] = function(board) {
for (var i = 0; i < 8; i++) {
var pinNumber = 8 * port + i;
var pin = board.pins[pinNumber];
var bit = 1 << i;

if (pin && (pin.mode === board.MODES.INPUT)) {
pin.value = (portValue >> (i & 0x07)) & 0x01;

if (pin.value) {
board.ports[port] |= bit;
} else {
board.ports[port] &= ~bit;
}

board.emit("digital-read-" + pinNumber, pin.value);
board.emit("digital-read", {
pin: pinNumber,
Expand Down Expand Up @@ -520,6 +529,7 @@ function Board(port, options, callback) {
this.HIGH = 1;
this.LOW = 0;
this.pins = [];
this.ports = Array(16).fill(0);
this.analogPins = [];
this.version = {};
this.firmware = {};
Expand Down Expand Up @@ -841,17 +851,22 @@ Board.prototype.pinMode = function(pin, mode) {
*/

Board.prototype.digitalWrite = function(pin, value) {
var port = Math.floor(pin / 8);
var portValue = 0;
var pinRecord;
var port = pin >> 3;
var bit = 1 << (pin & 0x07);

this.pins[pin].value = value;
for (var i = 0; i < 8; i++) {
pinRecord = this.pins[8 * port + i];
if (pinRecord && pinRecord.value) {
portValue |= (1 << i);
}

if (value) {
this.ports[port] |= bit;
} else {
this.ports[port] &= ~bit;
}
this.transport.write(new Buffer([DIGITAL_MESSAGE | port, portValue & 0x7F, (portValue >> 7) & 0x7F]));

this.transport.write(new Buffer([
DIGITAL_MESSAGE | port,
this.ports[port] & 0x7F,
(this.ports[port] >> 7) & 0x7F
]));
};

/**
Expand Down Expand Up @@ -1477,7 +1492,7 @@ Board.prototype.reportAnalogPin = function(pin, value) {
*/

Board.prototype.reportDigitalPin = function(pin, value) {
var port = Math.floor(pin / 8);
var port = pin >> 3;
if (value === 0 || value === 1) {
this.pins[pin].report = value;
this.transport.write(new Buffer([REPORT_DIGITAL | port, value]));
Expand Down
181 changes: 176 additions & 5 deletions test/firmata.test.js
Expand Up @@ -1001,15 +1001,183 @@ describe("Board: lifecycle", function() {
});

it("must be able to write a value to a digital output", function(done) {
board.digitalWrite(3, board.HIGH);
assert.deepEqual(transport.lastWrite, [DIGITAL_MESSAGE, 8, 0]);

board.digitalWrite(3, board.LOW);
assert.deepEqual(transport.lastWrite, [DIGITAL_MESSAGE, 0, 0]);
var write = sandbox.stub(SerialPort.prototype, "write");
var expect = [
[ 144, 1, 0 ],
[ 144, 2, 0 ],
[ 144, 4, 0 ],
[ 144, 8, 0 ],
[ 144, 16, 0 ],
[ 144, 32, 0 ],
[ 144, 64, 0 ],
[ 144, 0, 1 ],
[ 145, 1, 0 ],
[ 145, 2, 0 ],
[ 145, 4, 0 ],
[ 145, 8, 0 ],
[ 145, 16, 0 ],
[ 145, 32, 0 ],
[ 145, 64, 0 ],
[ 145, 0, 1 ],
[ 146, 1, 0 ],
[ 146, 2, 0 ],
[ 146, 4, 0 ],
[ 146, 8, 0 ],
];

for (var i = 0; i < board.pins.length; i++) {
board.digitalWrite(i, board.HIGH);
assert.deepEqual(Array.from(write.lastCall.args[0]), expect[i]);

board.digitalWrite(i, board.LOW);
}
done();
});

it("must be able to track digital writes via ports property", function(done) {
for (var i = 0; i < board.pins.length; i++) {
board.pins[i].mode = board.MODES.UNKNOWN;
}

var write = sandbox.stub(SerialPort.prototype, "write");
var expecting = [
1,
2,
4,
8,
16,
32,
64,
128,
1,
2,
4,
8,
16,
32,
64,
128,
1,
2,
4,
8,
];

for (var j = 0; j < board.pins.length; j++) {
var port = j >> 3;
var expect = expecting[j];

board.digitalWrite(j, board.HIGH);

assert.equal(board.ports[port], expect);

board.digitalWrite(j, board.LOW);
}
done();
});

it("must be able to write and read to a digital port without garbling state", function(done) {
/* This test will change the value of port 1 as follows:
0b00000001
0b00000000
0b00000001
0b00000101
0b00000000
0b00000101
0b00000001
*/

var write = sandbox.stub(SerialPort.prototype, "write");
var state = 0;
var calls = 0;
var expecting = [
// 10 is high, 9 is low, 8 is high
"101",
// 10 is low, 9 is low, 8 is low
"0",
// 10 is high, 9 is low, 8 is (still) low
"100",
// 10 is low, 9 is low, 8 is high
"1"
];

for (var i = 0; i < board.pins.length; i++) {
board.pins[i].mode = board.MODES.UNKNOWN;
}

for (var j = 0; j < board.ports.length; j++) {
board.ports[j] = 0;
}

// No Pins are high on this port
assert.equal(board.ports[1].toString(2), "0");


board.pinMode(8, board.MODES.OUTPUT);
board.pinMode(10, board.MODES.INPUT);
board.digitalRead(10, function(data) {
assert.equal(board.ports[1].toString(2), expecting[calls++]);

if (calls === 4) {
done();
}
});
/*
Pin Byte high Value
8 0b00000001 1
9 0b00000010 2
10 0b00000100 4
11 0b00001000 8
12 0b00010000 16
13 0b00100000 32
14 0b01000000 64
15 0b10000000 128
*/

// Pin 8 is bit 0 of port byte 1, it should now be ON
board.digitalWrite(8, 1);
assert.equal(board.ports[1].toString(2), "1");


// Pin 8 is bit 0 of port byte 1, it should now be OFF
board.digitalWrite(8, 0);
assert.equal(board.ports[1].toString(2), "0");


// Pin 8 is bit 0 of port byte 1, it should now be ON
board.digitalWrite(8, 1);
assert.equal(board.ports[1].toString(2), "1");


transport.emit("data", [DIGITAL_MESSAGE | 1, 4, 0]);
board.digitalWrite(8, 0);
// Pin 10 is bit 2 (value = 4) of port byte 1, it should now be ON
// Pin 8 is bit 0 (value = 1) of port byte 1, it should now be OFF
assert.equal(board.ports[1].toString(2), "100");


transport.emit("data", [DIGITAL_MESSAGE | 1, 0, 0]);
// Pin 10 is bit 2 (value = 4) of port byte 1, it should now be OFF
// Pin 8 is bit 0 (value = 1) of port byte 1, it should now be OFF
assert.equal(board.ports[1].toString(2), "0");


// Pin 10 is bit 2 (value = 4) of port byte 1, it should now be ON
// Pin 8 is bit 0 (value = 1) of port byte 1, it should now be ON
transport.emit("data", [DIGITAL_MESSAGE | 1, 4, 0]);
board.digitalWrite(8, 1);
assert.equal(board.ports[1].toString(2), "101");


// Pin 10 is bit 2 (value = 4) of port byte 1, it should now be OFF
// Pin 8 is bit 0 (value = 1) of port byte 1, it should now be ON
transport.emit("data", [DIGITAL_MESSAGE | 1, 0, 0]);
board.digitalWrite(8, 1);
assert.equal(board.ports[1].toString(2), "1");
});

it("must be able to write a value to a digital output to a board that skipped capabilities check", function(done) {
var transport = new SerialPort("/path/to/fake/usb");
var board = new Board(transport, {skipCapabilities: true}, initNoop);
Expand All @@ -1030,8 +1198,11 @@ describe("Board: lifecycle", function() {
});

it("must be able to write a value to an analog pin being used as a digital output", function(done) {
board.digitalWrite(19, board.HIGH);
board.ports[2] = 0;

// `DIGITAL_MESSAGE | 2` => Digital Message on Port 2
//
board.digitalWrite(19, board.HIGH);
assert.deepEqual(transport.lastWrite, [DIGITAL_MESSAGE | 2, 8, 0]);

board.digitalWrite(19, board.LOW);
Expand Down

0 comments on commit b8e7bf8

Please sign in to comment.