firmata/arduino — pull request #51 by soundanalogous (2013-04-14 06:43:23+00:00)
Title: For Review and Discussion: SHIFT IN/OUT feature class

I've added a shift in/out feature class. There are a few different ways to approach shift in/out. One approach would be to have a SHIFT_CONFIG to set up the pins for each shift registor, sensor, etc. That would require an array of structs to track the pin sets. I took a different method based on the 1st proposal here: http://firmata.org/wiki/Proposals#ShiftIn.2FOut_Proposal, but with some additions. This approach requires the user to specify all 3 pins (data, clock and latch) each time they want to send a shift-in or shift-out request. Here's the protocol I implemented:

0 START_SYSEX
1 SHIFT_DATA
2 COMMAND (SHIFT_OUT: 1, SHIFT_IN: 2, SHIFT_IN_REPLY: 3)
3 dataPin
4 clockPin
5 latchPin
6 bitOrder (MSBFIRST or LSBFIRST)
7 numBytes (only used for SHIFT_IN. For SHIFT_OUT or SHIFT_IN_REPLY, this byte is start of payload)
n ...
n+1 END_SYSEX

However, note that this approach requires the user to set-up the pin modes first. It could alternatively be possible to set them on the 1st call and then check but that introduces another conditional for each call.

Here's an example client implementation (in JavaScript):

```
sendShiftOut: function (dataPin, clockPin, latchPin, bitOrder, value) {
var shiftOut = [],
SHIFT_OUT = 1,
len;

shiftOut[0] = START_SYSEX;
shiftOut[1] = SHIFT_DATA;
shiftOut[2] = SHIFT_OUT;
shiftOut[3] = dataPin.number;
shiftOut[4] = clockPin.number;
shiftOut[5] = latchPin.number;
shiftOut[6] = bitOrder || MSBFIRST;

Encoder7Bit.startBinaryWrite();
Encoder7Bit.writeBinary(value);
Encoder7Bit.endBinaryWrite();

len = Encoder7Bit.binaryData.length;
for (var i = 0; i < len; i++) {
shiftOut.push(Encoder7Bit.binaryData[i]);
}
shiftOut.push(END_SYSEX);

this.send(shiftOut);
},

sendShiftIn: function (dataPin, clockPin, latchPin, bitOrder, numBytes) {
var shiftIn = [],
SHIFT_IN = 2;

shiftIn[0] = START_SYSEX;
shiftIn[1] = SHIFT_DATA;
shiftIn[2] = SHIFT_IN;
shiftIn[3] = dataPin.number;
shiftIn[4] = clockPin.number;
shiftIn[5] = latchPin.number;
shiftIn[6] = bitOrder || MSBFIRST;
shiftIn[7] = numBytes || 1;
shiftIn[8] = END_SYSEX;

this.send(shiftIn);
},

// testing shift-in reply
processShiftData: function (msg) {
var len = msg.length;
var data = msg.slice(3);
// decode to array of 8-bit values
var numBytes = Encoder7Bit.num7BitOutbytes(len - 3);
var value = Encoder7Bit.readBinary(numBytes, data);
console.log(value);
}
```