Skip to content

Commit

Permalink
I2C: i2cWrite, i2cRead, i2cReadOnce
Browse files Browse the repository at this point in the history
  • Loading branch information
rwaldron committed Dec 18, 2014
1 parent 6e946fa commit 73deac7
Show file tree
Hide file tree
Showing 4 changed files with 494 additions and 33 deletions.
2 changes: 1 addition & 1 deletion gruntfile.js
Expand Up @@ -16,7 +16,7 @@ module.exports = function (grunt) {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
latedef: false,
newcap: true,
noarg: true,
sub: true,
Expand Down
272 changes: 259 additions & 13 deletions lib/firmata.js
Expand Up @@ -260,13 +260,15 @@ SYSEX_RESPONSE[ANALOG_MAPPING_RESPONSE] = function(board) {
*/

SYSEX_RESPONSE[I2C_REPLY] = function(board) {
var replyBuffer = [];
var slaveAddress = (board.currentBuffer[2] & 0x7F) | ((board.currentBuffer[3] & 0x7F) << 7);
var reply = [];
var address = (board.currentBuffer[2] & 0x7F) | ((board.currentBuffer[3] & 0x7F) << 7);
var register = (board.currentBuffer[4] & 0x7F) | ((board.currentBuffer[5] & 0x7F) << 7);

for (var i = 6, length = board.currentBuffer.length - 1; i < length; i += 2) {
replyBuffer.push(board.currentBuffer[i] | (board.currentBuffer[i + 1] << 7));
reply.push(board.currentBuffer[i] | (board.currentBuffer[i + 1] << 7));
}
board.emit("I2C-reply-" + slaveAddress, replyBuffer);

board.emit("I2C-reply-" + address + "-" + register, reply);
};

SYSEX_RESPONSE[ONEWIRE_DATA] = function(board) {
Expand Down Expand Up @@ -751,6 +753,31 @@ Board.prototype.sendI2CConfig = function(delay) {
delay = delay || 0;
this.sp.write(new Buffer([START_SYSEX, I2C_CONFIG, (delay & 0xFF), ((delay >> 8) & 0xFF), END_SYSEX]));
};

/**
* Enable I2C with an optional read delay. Must be called before
* an I2C Read or Write
*
* Supersedes sendI2CConfig
*
* @param {number} delay in microseconds to set for I2C Read
*/

Board.prototype.i2cConfig = function(delay) {
delay = delay || 0;

this.sp.write(
new Buffer([
START_SYSEX,
I2C_CONFIG,
delay & 0xFF, (delay >> 8) & 0xFF,
END_SYSEX
])
);

return this;
};

/**
* Asks the arduino to send an I2C request to a device
* @param {number} slaveAddress The address of the I2C device
Expand All @@ -760,30 +787,249 @@ Board.prototype.sendI2CConfig = function(delay) {
Board.prototype.sendI2CWriteRequest = function(slaveAddress, bytes) {
var data = [];
bytes = bytes || [];
data.push(START_SYSEX);
data.push(I2C_REQUEST);
data.push(slaveAddress);
data.push(this.I2C_MODES.WRITE << 3);

data.push(
START_SYSEX,
I2C_REQUEST,
slaveAddress,
this.I2C_MODES.WRITE << 3
);

for (var i = 0, length = bytes.length; i < length; i++) {
data.push(bytes[i] & 0x7F);
data.push((bytes[i] >> 7) & 0x7F);
data.push(
bytes[i] & 0x7F, (bytes[i] >> 7) & 0x7F
);
}

data.push(END_SYSEX);

this.sp.write(new Buffer(data));
};

/**
* Write data to a register
*
* @param {number} address The address of the I2C device.
* @param {array} cmdRegOrData An array of bytes
*
* Write a command to a register
*
* @param {number} address The address of the I2C device.
* @param {number} cmdRegOrData The register
* @param {array} inBytes An array of bytes
*
*/
Board.prototype.i2cWrite = function(address, registerOrData, inBytes) {
/**
* registerOrData:
* [... arbitrary bytes]
*
* or
*
* registerOrData, inBytes:
* command [, ...]
*
*/
var bytes;
var data = [
START_SYSEX,
I2C_REQUEST,
address,
this.I2C_MODES.WRITE << 3
];


// If i2cWrite was used for an i2cWriteReg call...
if (arguments.length === 3 &&
!Array.isArray(registerOrData) &&
!Array.isArray(inBytes)) {

return this.i2cWriteReg(address, registerOrData, inBytes);
}

// Fix arguments if called with Firmata.js API
if (arguments.length === 2) {
if (Array.isArray(registerOrData)) {
inBytes = registerOrData.slice();
registerOrData = inBytes.shift();
} else {
inBytes = [];
}
}

bytes = new Buffer([registerOrData].concat(inBytes));

for (var i = 0, length = bytes.length; i < length; i++) {
data.push(
bytes[i] & 0x7F, (bytes[i] >> 7) & 0x7F
);
}

data.push(END_SYSEX);

this.sp.write(new Buffer(data));

return this;
};

/**
* Write data to a register
*
* @param {number} address The address of the I2C device.
* @param {number} register The register.
* @param {number} byte The byte value to write.
*
*/

Board.prototype.i2cWriteReg = function(address, register, byte) {
this.sp.write(
new Buffer([
START_SYSEX,
I2C_REQUEST,
address,
this.I2C_MODES.WRITE << 3,
// register
register & 0x7F, (register >> 7) & 0x7F,
// byte
byte & 0x7F, (byte >> 7) & 0x7F,
END_SYSEX
])
);

return this;
};


/**
* Asks the arduino to request bytes from an I2C device
* @param {number} slaveAddress The address of the I2C device
* @param {number} numBytes The number of bytes to receive.
* @param {function} callback A function to call when we have received the bytes.
*/

Board.prototype.sendI2CReadRequest = function(slaveAddress, numBytes, callback) {
this.sp.write(new Buffer([START_SYSEX, I2C_REQUEST, slaveAddress, this.I2C_MODES.READ << 3, numBytes & 0x7F, (numBytes >> 7) & 0x7F, END_SYSEX]));
this.once("I2C-reply-" + slaveAddress, callback);
Board.prototype.sendI2CReadRequest = function(address, numBytes, callback) {
this.sp.write(
new Buffer([
START_SYSEX,
I2C_REQUEST,
address,
this.I2C_MODES.READ << 3,
numBytes & 0x7F, (numBytes >> 7) & 0x7F,
END_SYSEX
])
);
this.once("I2C-reply-" + address + "-0" , callback);
};

// TODO: Refactor i2cRead and i2cReadOnce
// to share most operations.

/**
* Initialize a continuous I2C read.
*
* @param {number} address The address of the I2C device
* @param {number} register Optionally set the register to read from.
* @param {number} numBytes The number of bytes to receive.
* @param {function} callback A function to call when we have received the bytes.
*/

Board.prototype.i2cRead = function(address, register, bytesToRead, callback) {

if (arguments.length === 3 &&
typeof register === "number" &&
typeof bytesToRead === "function") {
callback = bytesToRead;
bytesToRead = register;
register = null;
}

var event = "I2C-reply-" + address + "-";
var data = [
START_SYSEX,
I2C_REQUEST,
address,
this.I2C_MODES.CONTINUOUS_READ << 3,
];

if (register !== null) {
data.push(
register & 0x7F, (register >> 7) & 0x7F
);
} else {
register = 0;
}

event += register;

data.push(
bytesToRead & 0x7F, (bytesToRead >> 7) & 0x7F,
END_SYSEX
);

this.on(event, callback);

this.sp.write(new Buffer(data));

return this;
};

/**
* Perform a single I2C read
*
* Supersedes sendI2CReadRequest
*
* Read bytes from address
*
* @param {number} address The address of the I2C device
* @param {number} register Optionally set the register to read from.
* @param {number} numBytes The number of bytes to receive.
* @param {function} callback A function to call when we have received the bytes.
*
*/


Board.prototype.i2cReadOnce = function(address, register, bytesToRead, callback) {

if (arguments.length === 3 &&
typeof register === "number" &&
typeof bytesToRead === "function") {
callback = bytesToRead;
bytesToRead = register;
register = null;
}

var event = "I2C-reply-" + address + "-";
var data = [
START_SYSEX,
I2C_REQUEST,
address,
this.I2C_MODES.READ << 3,
];

if (register !== null) {
data.push(
register & 0x7F, (register >> 7) & 0x7F
);
} else {
register = 0;
}

event += register;

data.push(
bytesToRead & 0x7F, (bytesToRead >> 7) & 0x7F,
END_SYSEX
);

this.once(event, callback);

this.sp.write(new Buffer(data));

return this;
};

// CONTINUOUS_READ

/**
* Configure the passed pin as the controller in a 1-wire bus.
* Pass as enableParasiticPower true if you want the data pin to power the bus.
Expand Down
52 changes: 46 additions & 6 deletions readme.md
Expand Up @@ -53,7 +53,12 @@ If you run *firmata* from the command line it will prompt you for the usb port.
For example to get the analog pin 5 from the *Board.pins* attributes use:

`board.pins[board.analogPins[5]];`
##methods


## API

### Pin

`board.pinMode(pin,mode)`

Set a mode for a pin. pin is the number of the pin and the mode is on of the Board.MODES values.
Expand All @@ -74,25 +79,60 @@ If you run *firmata* from the command line it will prompt you for the usb port.

Read an input for an analog pin. Every time there is data on the pin the callback will be fired with a value argument.

### Servo

`board.servoWrite(pin,degree)`
Write a degree value to a servo pin.

`board.servoConfig(pin, min, max)`
Setup a servo with a specific min and max pulse (call instead of `pinMode`, which will provide default).

`board.sendI2CConfig(delay)`
Set I2C Config on the arduino
### I2C

`board.i2cConfig([delay])`
Configure and enable I2C, optionally set a delay (defaults to `0`). Required to enable I2C communication.

`board.i2cWrite(address, [...bytes])`
Write an arbitrary number of bytes. May not exceed 64 Bytes.

`board.i2cWrite(address, register, [...bytes])`
Write an arbitrary number of bytes to the specified register. May not exceed 64 Bytes.

`board.i2cWriteReg(address, register, byte)`
Write a byte value to a specific register.

`board.i2cRead(address, numberOfBytesToRead, handler(data))`
Read a specified number of bytes, continuously. `handler` receives an array of values, with a length corresponding to the number of read bytes.

`board.sendI2CWriteRequest(slaveAddress,[bytes])`
`board.i2cRead(address, register, numberOfBytesToRead, handler(data))`
Read a specified number of bytes from a register, continuously. `handler` receives an array of values, with a length corresponding to the number of read bytes.

`board.i2cReadOnce(address, numberOfBytesToRead, handler(data))`
Read a specified number of bytes, one time. `handler` receives an array of values, with a length corresponding to the number of read bytes.

`board.i2cReadOnce(address, register, numberOfBytesToRead, handler(data))`
Read a specified number of bytes from a register, one time. `handler` receives an array of values, with a length corresponding to the number of read bytes.


`board.sendI2CConfig(delay)` **Deprecated**
Set I2C Config on the arduino

`board.sendI2CWriteRequest(slaveAddress,[bytes])` **Deprecated**

Write an array of bytes to a an I2C device.

`board.sendI2CReadRequest(slaveAddress,numBytes,function(data))`
`board.sendI2CReadRequest(slaveAddress,numBytes,function(data))` **Deprecated**

Requests a number of bytes from a slave I2C device. When the bytes are received from the I2C device the callback is called with the byte array.


### Debug

`board.sendString("a string")`

Send an arbitrary string.

### One-Wire

`sendOneWireConfig(pin, enableParasiticPower)`

Configure the pin as the controller in a 1-wire bus. Set `enableParasiticPower` to `true` if you want the data pin to power the bus.
Expand Down

0 comments on commit 73deac7

Please sign in to comment.