Skip to content

Commit

Permalink
parser improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
soundanalogous committed Mar 12, 2016
1 parent e2681c7 commit c46df52
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 11 deletions.
25 changes: 15 additions & 10 deletions lib/firmata.js
Expand Up @@ -387,7 +387,6 @@ SYSEX_RESPONSE[SERIAL_MESSAGE] = function(board) {
}
};


/**
* @class The Board object represents an arduino board.
* @augments EventEmitter
Expand Down Expand Up @@ -541,13 +540,7 @@ var Board = function(port, options, callback) {
}.bind(this));

this.transport.on("data", function(data) {
var byt, cmd;

if (!this.versionReceived && data[0] !== REPORT_VERSION) {
return;
} else {
this.versionReceived = true;
}
var byt, cmd, currByte;

for (var i = 0; i < data.length; i++) {
byt = data[i];
Expand All @@ -562,8 +555,17 @@ var Board = function(port, options, callback) {
SYSEX_RESPONSE[this.currentBuffer[1]] &&
this.currentBuffer[this.currentBuffer.length - 1] === END_SYSEX) {

SYSEX_RESPONSE[this.currentBuffer[1]](this);
if (this.versionReceived) {
SYSEX_RESPONSE[this.currentBuffer[1]](this);
}
this.currentBuffer.length = 0;
} else if (this.currentBuffer[0] === START_SYSEX && i > 0) {
// we have a new command after an incomplete sysex command
currByte = this.currentBuffer[i];
if (currByte > 0x7F) {
this.currentBuffer.length = 0;
this.currentBuffer.push(currByte);
}
} else if (this.currentBuffer[0] !== START_SYSEX) {
// Check if data gets out of sync: first byte in buffer
// must be a valid command if not START_SYSEX
Expand All @@ -589,7 +591,10 @@ var Board = function(port, options, callback) {
}

if (MIDI_RESPONSE[cmd]) {
MIDI_RESPONSE[cmd](this);
if (this.versionReceived || this.currentBuffer[0] === REPORT_VERSION) {
this.versionReceived = true;
MIDI_RESPONSE[cmd](this);
}
this.currentBuffer.length = 0;
} else {
// A bad serial read must have happened.
Expand Down
127 changes: 126 additions & 1 deletion test/firmata.test.js
Expand Up @@ -1590,7 +1590,7 @@ describe("Board: instances", function() {

it("allows an i2c peripheral's stopTX to be overridden", function(done) {
// var spy = sandbox.spy(board.transport, "write");
var mask = 0b01001000;
var mask = 0x48; // 01001000

board.i2cConfig({
address: 0x00,
Expand Down Expand Up @@ -2050,6 +2050,131 @@ describe("Board: instances", function() {
});

});

describe("parser", function() {

beforeEach(function() {
board.currentBuffer = [];
});

it("must parse a command from the beginning of a data packet", function (done) {
var spy = sandbox.spy();
var incoming = [REPORT_VERSION, 0x02, 0x03];
board.versionReceived = false;
board.on("reportversion", spy);
transport.emit("data", incoming);
assert.equal(spy.callCount, 1);
done();
});

it("must parse a command from the middle of a data packet", function (done) {
var spy = sandbox.spy();
// includes: analog input, report version, query firmware (incomplete)
var incoming = [
0xe0, 0x07, 0x07, 0xf9, 0x02, 0x05, 0xf0, 0x79, 0x02, 0x05, 0x53, 0x00, 0x74, 0x00, 0x61,
0x00, 0x6e, 0x00, 0x64, 0x00
];
board.versionReceived = false;
board.on("reportversion", spy);
transport.emit("data", incoming);
assert.equal(spy.callCount, 1);
done();
});

it("must not emit command events until REPORT_VERSION is received", function (done) {
var spyAnalog = sandbox.spy();
var spyVersion = sandbox.spy();
// includes: analog input, report version, query firmware (incomplete) and junk
// between analog input and report version
var incoming = [
0xe0, 0x00, 0x71, 0xf9, 0x02, 0x05, 0xf0, 0x79, 0x02, 0x05, 0x53, 0x00, 0x74,
0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00
];
board.versionReceived = false;
board.on("analog-read-0", spyAnalog);
board.on("reportversion", spyVersion);
transport.emit("data", incoming);
assert.equal(spyAnalog.callCount, 0);
assert.equal(spyVersion.callCount, 1);
done();
});

it("must parse multiple commands from a single packet", function (done) {
var spyAnalog = sandbox.spy();
var spyVersion = sandbox.spy();
// includes: report version, analog input, query firmware (incomplete) and junk
// between analog input and report version
var incoming = [
0xf9, 0x02, 0x05, 0xe0, 0x00, 0x71, 0xf0, 0x79, 0x02, 0x05, 0x53, 0x00, 0x74,
0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00
];
board.versionReceived = false;
board.on("reportversion", spyVersion);
board.on("analog-read-0", spyAnalog);
transport.emit("data", incoming);
assert.equal(spyVersion.callCount, 1);
assert.equal(spyAnalog.callCount, 1);
done();
});

it("must parse a complete sysex command after an incomplete sysex command", function (done) {
var spy = sandbox.spy();
// includes: query firmware (incomplete sysex), pin state response (pin 2)
var incoming = [
0xf0, 0x79, 0x02, 0x05, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
0xf0, 0x6e, 0x02, 0x01, 0x01, 0xf7
];
board.versionReceived = true;
board.on("pin-state-2", spy);
transport.emit("data", incoming);
assert.equal(spy.callCount, 1);
done();
});

it("must parse a non-sysex command after an incomplete sysex command", function (done) {
var spy = sandbox.spy();
// includes: query firmware (incomplete sysex), analog input
var incoming = [
0xf0, 0x79, 0x02, 0x05, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
0xe0, 0x00, 0x71
];
board.versionReceived = true;
board.on("analog-read-0", spy);
transport.emit("data", incoming);
assert.equal(spy.callCount, 1);
done();
});

it("must parse a command spread across multiple data packets", function (done) {
var spy = sandbox.spy();
// query firmware split across 3 packets with first packet preceeded by junk
var incoming1 = [0x07, 0x04, 240, 121, 2, 3, 83, 0, 116, 0, 97, 0, 110, 0, 100, 0];
var incoming2 = [97, 0, 114, 0, 100, 0, 70, 0, 105, 0, 114, 0, 109, 0];
var incoming3 = [97, 0, 116, 0, 97, 0, 247];

board.versionReceived = true;
board.on("queryfirmware", spy);
transport.emit("data", incoming1);
transport.emit("data", incoming2);
transport.emit("data", incoming3);
assert.equal(spy.callCount, 1);
done();
});

it("must parse a command spread across multiple single byte transfers", function (done) {
var spy = sandbox.spy();
var incoming = [REPORT_VERSION, 0x02, 0x03];

board.versionReceived = true;
board.on("reportversion", spy);
for (var i = 0; i < incoming.length; i++) {
transport.emit("data", [incoming[i]]);
}
assert.equal(spy.callCount, 1);
done();
});

});
});

describe("Board.encode/Board.decode", function() {
Expand Down

0 comments on commit c46df52

Please sign in to comment.