summaryrefslogtreecommitdiff
path: root/libraries/I2Cdev/I2Cdev.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/I2Cdev/I2Cdev.cpp')
-rw-r--r--libraries/I2Cdev/I2Cdev.cpp1373
1 files changed, 1373 insertions, 0 deletions
diff --git a/libraries/I2Cdev/I2Cdev.cpp b/libraries/I2Cdev/I2Cdev.cpp
new file mode 100644
index 0000000..92032be
--- /dev/null
+++ b/libraries/I2Cdev/I2Cdev.cpp
@@ -0,0 +1,1373 @@
+// I2Cdev library collection - Main I2C device class
+// Abstracts bit and byte I2C R/W functions into a convenient class
+// 6/9/2012 by Jeff Rowberg <jeff@rowberg.net>
+//
+// Changelog:
+// 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
+// - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
+// 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
+// 2011-10-03 - added automatic Arduino version detection for ease of use
+// 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
+// 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
+// 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
+// 2011-08-02 - added support for 16-bit registers
+// - fixed incorrect Doxygen comments on some methods
+// - added timeout value for read operations (thanks mem @ Arduino forums)
+// 2011-07-30 - changed read/write function structures to return success or byte counts
+// - made all methods static for multi-device memory savings
+// 2011-07-28 - initial release
+
+/* ============================================
+I2Cdev device library code is placed under the MIT license
+Copyright (c) 2012 Jeff Rowberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+===============================================
+*/
+
+#include "I2Cdev.h"
+
+#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
+
+ #ifdef I2CDEV_IMPLEMENTATION_WARNINGS
+ #if ARDUINO < 100
+ #warning Using outdated Arduino IDE with Wire library is functionally limiting.
+ #warning Arduino IDE v1.0.1+ with I2Cdev Fastwire implementation is recommended.
+ #warning This I2Cdev implementation does not support:
+ #warning - Repeated starts conditions
+ #warning - Timeout detection (some Wire requests block forever)
+ #elif ARDUINO == 100
+ #warning Using outdated Arduino IDE with Wire library is functionally limiting.
+ #warning Arduino IDE v1.0.1+ with I2Cdev Fastwire implementation is recommended.
+ #warning This I2Cdev implementation does not support:
+ #warning - Repeated starts conditions
+ #warning - Timeout detection (some Wire requests block forever)
+ #elif ARDUINO > 100
+ /*
+ #warning Using current Arduino IDE with Wire library is functionally limiting.
+ #warning Arduino IDE v1.0.1+ with I2CDEV_BUILTIN_FASTWIRE implementation is recommended.
+ #warning This I2Cdev implementation does not support:
+ #warning - Timeout detection (some Wire requests block forever)
+ */
+ #endif
+ #endif
+
+#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
+
+ #error The I2CDEV_BUILTIN_FASTWIRE implementation is known to be broken right now. Patience, Iago!
+
+#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
+
+ #ifdef I2CDEV_IMPLEMENTATION_WARNINGS
+ #warning Using I2CDEV_BUILTIN_NBWIRE implementation may adversely affect interrupt detection.
+ #warning This I2Cdev implementation does not support:
+ #warning - Repeated starts conditions
+ #endif
+
+ // NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
+ // Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
+ // Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
+ TwoWire Wire;
+
+#endif
+
+/** Default constructor.
+ */
+I2Cdev::I2Cdev() {
+}
+
+/** Read a single bit from an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param bitNum Bit position to read (0-7)
+ * @param data Container for single bit value
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (true = success)
+ */
+int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout) {
+ uint8_t b;
+ uint8_t count = readByte(devAddr, regAddr, &b, timeout);
+ *data = b & (1 << bitNum);
+ return count;
+}
+
+/** Read a single bit from a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param bitNum Bit position to read (0-15)
+ * @param data Container for single bit value
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (true = success)
+ */
+int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout) {
+ uint16_t b;
+ uint8_t count = readWord(devAddr, regAddr, &b, timeout);
+ *data = b & (1 << bitNum);
+ return count;
+}
+
+/** Read multiple bits from an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param bitStart First bit position to read (0-7)
+ * @param length Number of bits to read (not more than 8)
+ * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05)
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (true = success)
+ */
+int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) {
+ // 01101001 read byte
+ // 76543210 bit numbers
+ // xxx args: bitStart=4, length=3
+ // 010 masked
+ // -> 010 shifted
+ uint8_t count, b;
+ if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) {
+ uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
+ b &= mask;
+ b >>= (bitStart - length + 1);
+ *data = b;
+ }
+ return count;
+}
+
+/** Read multiple bits from a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param bitStart First bit position to read (0-15)
+ * @param length Number of bits to read (not more than 16)
+ * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05)
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (1 = success, 0 = failure, -1 = timeout)
+ */
+int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout) {
+ // 1101011001101001 read byte
+ // fedcba9876543210 bit numbers
+ // xxx args: bitStart=12, length=3
+ // 010 masked
+ // -> 010 shifted
+ uint8_t count;
+ uint16_t w;
+ if ((count = readWord(devAddr, regAddr, &w, timeout)) != 0) {
+ uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1);
+ w &= mask;
+ w >>= (bitStart - length + 1);
+ *data = w;
+ }
+ return count;
+}
+
+/** Read single byte from an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param data Container for byte value read from device
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (true = success)
+ */
+int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout) {
+ return readBytes(devAddr, regAddr, 1, data, timeout);
+}
+
+/** Read single word from a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to read from
+ * @param data Container for word value read from device
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Status of read operation (true = success)
+ */
+int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout) {
+ return readWords(devAddr, regAddr, 1, data, timeout);
+}
+
+/** Read multiple bytes from an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr First register regAddr to read from
+ * @param length Number of bytes to read
+ * @param data Buffer to store read data in
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Number of bytes read (-1 indicates failure)
+ */
+int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) {
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print("I2C (0x");
+ Serial.print(devAddr, HEX);
+ Serial.print(") reading ");
+ Serial.print(length, DEC);
+ Serial.print(" bytes from 0x");
+ Serial.print(regAddr, HEX);
+ Serial.print("...");
+ #endif
+
+ int8_t count = 0;
+ uint32_t t1 = millis();
+
+ #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE)
+
+ #if (ARDUINO < 100)
+ // Arduino v00xx (before v1.0), Wire library
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.send(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
+
+ for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
+ data[count] = Wire.receive();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ }
+
+ Wire.endTransmission();
+ }
+ #elif (ARDUINO == 100)
+ // Arduino v1.0.0, Wire library
+ // Adds standardized write() and read() stream methods instead of send() and receive()
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.write(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
+
+ for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
+ data[count] = Wire.read();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ }
+
+ Wire.endTransmission();
+ }
+ #elif (ARDUINO > 100)
+ // Arduino v1.0.1+, Wire library
+ // Adds official support for repeated start condition, yay!
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.write(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
+
+ for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
+ data[count] = Wire.read();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ }
+
+ Wire.endTransmission();
+ }
+ #endif
+
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
+ // Fastwire library (STILL UNDER DEVELOPMENT, NON-FUNCTIONAL!)
+
+ // no loop required for fastwire
+ uint8_t status = Fastwire::readBuf(devAddr, regAddr, data, length);
+ if (status == 0) {
+ count = length; // success
+ } else {
+ count = -1; // error
+ }
+
+ #endif
+
+ // check for timeout
+ if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout
+
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(". Done (");
+ Serial.print(count, DEC);
+ Serial.println(" read).");
+ #endif
+
+ return count;
+}
+
+/** Read multiple words from a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr First register regAddr to read from
+ * @param length Number of words to read
+ * @param data Buffer to store read data in
+ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
+ * @return Number of words read (0 indicates failure)
+ */
+int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout) {
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print("I2C (0x");
+ Serial.print(devAddr, HEX);
+ Serial.print(") reading ");
+ Serial.print(length, DEC);
+ Serial.print(" words from 0x");
+ Serial.print(regAddr, HEX);
+ Serial.print("...");
+ #endif
+
+ int8_t count = 0;
+ uint32_t t1 = millis();
+
+ #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE)
+
+ #if (ARDUINO < 100)
+ // Arduino v00xx (before v1.0), Wire library
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.send(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
+
+ bool msb = true; // starts with MSB, then LSB
+ for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
+ if (msb) {
+ // first byte is bits 15-8 (MSb=15)
+ data[count] = Wire.receive() << 8;
+ } else {
+ // second byte is bits 7-0 (LSb=0)
+ data[count] |= Wire.receive();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ count++;
+ }
+ msb = !msb;
+ }
+
+ Wire.endTransmission();
+ }
+ #elif (ARDUINO == 100)
+ // Arduino v1.0.0, Wire library
+ // Adds standardized write() and read() stream methods instead of send() and receive()
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.write(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
+
+ bool msb = true; // starts with MSB, then LSB
+ for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
+ if (msb) {
+ // first byte is bits 15-8 (MSb=15)
+ data[count] = Wire.read() << 8;
+ } else {
+ // second byte is bits 7-0 (LSb=0)
+ data[count] |= Wire.read();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ count++;
+ }
+ msb = !msb;
+ }
+
+ Wire.endTransmission();
+ }
+ #elif (ARDUINO > 100)
+ // Arduino v1.0.1+, Wire library
+ // Adds official support for repeated start condition, yay!
+
+ // I2C/TWI subsystem uses internal buffer that breaks with large data requests
+ // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
+ // smaller chunks instead of all at once
+ for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
+ Wire.beginTransmission(devAddr);
+ Wire.write(regAddr);
+ Wire.endTransmission();
+ Wire.beginTransmission(devAddr);
+ Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
+
+ bool msb = true; // starts with MSB, then LSB
+ for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
+ if (msb) {
+ // first byte is bits 15-8 (MSb=15)
+ data[count] = Wire.read() << 8;
+ } else {
+ // second byte is bits 7-0 (LSb=0)
+ data[count] |= Wire.read();
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[count], HEX);
+ if (count + 1 < length) Serial.print(" ");
+ #endif
+ count++;
+ }
+ msb = !msb;
+ }
+
+ Wire.endTransmission();
+ }
+ #endif
+
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
+ // Fastwire library (STILL UNDER DEVELOPMENT, NON-FUNCTIONAL!)
+
+ // no loop required for fastwire
+ uint16_t intermediate[(uint8_t)length];
+ uint8_t status = Fastwire::readBuf(devAddr, regAddr, (uint8_t *)intermediate, (uint8_t)(length * 2));
+ if (status == 0) {
+ count = length; // success
+ for (uint8_t i = 0; i < length; i++) {
+ data[i] = (intermediate[2*i] << 8) | intermediate[2*i + 1];
+ }
+ } else {
+ count = -1; // error
+ }
+
+ #endif
+
+ if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout
+
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(". Done (");
+ Serial.print(count, DEC);
+ Serial.println(" read).");
+ #endif
+
+ return count;
+}
+
+/** write a single bit in an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to write to
+ * @param bitNum Bit position to write (0-7)
+ * @param value New bit value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data) {
+ uint8_t b;
+ readByte(devAddr, regAddr, &b);
+ b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
+ return writeByte(devAddr, regAddr, b);
+}
+
+/** write a single bit in a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to write to
+ * @param bitNum Bit position to write (0-15)
+ * @param value New bit value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data) {
+ uint16_t w;
+ readWord(devAddr, regAddr, &w);
+ w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum));
+ return writeWord(devAddr, regAddr, w);
+}
+
+/** Write multiple bits in an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to write to
+ * @param bitStart First bit position to write (0-7)
+ * @param length Number of bits to write (not more than 8)
+ * @param data Right-aligned value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
+ // 010 value to write
+ // 76543210 bit numbers
+ // xxx args: bitStart=4, length=3
+ // 00011100 mask byte
+ // 10101111 original value (sample)
+ // 10100011 original & ~mask
+ // 10101011 masked | value
+ uint8_t b;
+ if (readByte(devAddr, regAddr, &b) != 0) {
+ uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
+ data <<= (bitStart - length + 1); // shift data into correct position
+ data &= mask; // zero all non-important bits in data
+ b &= ~(mask); // zero all important bits in existing byte
+ b |= data; // combine data with existing byte
+ return writeByte(devAddr, regAddr, b);
+ } else {
+ return false;
+ }
+}
+
+/** Write multiple bits in a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register regAddr to write to
+ * @param bitStart First bit position to write (0-15)
+ * @param length Number of bits to write (not more than 16)
+ * @param data Right-aligned value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data) {
+ // 010 value to write
+ // fedcba9876543210 bit numbers
+ // xxx args: bitStart=12, length=3
+ // 0001110000000000 mask byte
+ // 1010111110010110 original value (sample)
+ // 1010001110010110 original & ~mask
+ // 1010101110010110 masked | value
+ uint16_t w;
+ if (readWord(devAddr, regAddr, &w) != 0) {
+ uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
+ data <<= (bitStart - length + 1); // shift data into correct position
+ data &= mask; // zero all non-important bits in data
+ w &= ~(mask); // zero all important bits in existing word
+ w |= data; // combine data with existing word
+ return writeWord(devAddr, regAddr, w);
+ } else {
+ return false;
+ }
+}
+
+/** Write single byte to an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register address to write to
+ * @param data New byte value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) {
+ return writeBytes(devAddr, regAddr, 1, &data);
+}
+
+/** Write single word to a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr Register address to write to
+ * @param data New word value to write
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) {
+ return writeWords(devAddr, regAddr, 1, &data);
+}
+
+/** Write multiple bytes to an 8-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr First register address to write to
+ * @param length Number of bytes to write
+ * @param data Buffer to copy new data from
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data) {
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print("I2C (0x");
+ Serial.print(devAddr, HEX);
+ Serial.print(") writing ");
+ Serial.print(length, DEC);
+ Serial.print(" bytes to 0x");
+ Serial.print(regAddr, HEX);
+ Serial.print("...");
+ #endif
+ uint8_t status = 0;
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.beginTransmission(devAddr);
+ Wire.send((uint8_t) regAddr); // send address
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ Wire.beginTransmission(devAddr);
+ Wire.write((uint8_t) regAddr); // send address
+ #endif
+ for (uint8_t i = 0; i < length; i++) {
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.send((uint8_t) data[i]);
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ Wire.write((uint8_t) data[i]);
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
+ status = Fastwire::write(devAddr, regAddr, data[i]);
+ Serial.println(status);
+ #endif
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[i], HEX);
+ if (i + 1 < length) Serial.print(" ");
+ #endif
+ }
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.endTransmission();
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ status = Wire.endTransmission();
+ #endif
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.println(". Done.");
+ #endif
+ return status == 0;
+}
+
+/** Write multiple words to a 16-bit device register.
+ * @param devAddr I2C slave device address
+ * @param regAddr First register address to write to
+ * @param length Number of words to write
+ * @param data Buffer to copy new data from
+ * @return Status of operation (true = success)
+ */
+bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data) {
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print("I2C (0x");
+ Serial.print(devAddr, HEX);
+ Serial.print(") writing ");
+ Serial.print(length, DEC);
+ Serial.print(" words to 0x");
+ Serial.print(regAddr, HEX);
+ Serial.print("...");
+ #endif
+ uint8_t status = 0;
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.beginTransmission(devAddr);
+ Wire.send(regAddr); // send address
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ Wire.beginTransmission(devAddr);
+ Wire.write(regAddr); // send address
+ #endif
+ for (uint8_t i = 0; i < length * 2; i++) {
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.send((uint8_t)(data[i++] >> 8)); // send MSB
+ Wire.send((uint8_t)data[i]); // send LSB
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ Wire.write((uint8_t)(data[i++] >> 8)); // send MSB
+ Wire.write((uint8_t)data[i]); // send LSB
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
+ status = Fastwire::write(devAddr, regAddr, (uint8_t)(data[i++] >> 8));
+ status = Fastwire::write(devAddr, regAddr + 1, (uint8_t)data[i]);
+ #endif
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.print(data[i], HEX);
+ if (i + 1 < length) Serial.print(" ");
+ #endif
+ }
+ #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
+ Wire.endTransmission();
+ #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100)
+ status = Wire.endTransmission();
+ #endif
+ #ifdef I2CDEV_SERIAL_DEBUG
+ Serial.println(". Done.");
+ #endif
+ return status == 0;
+}
+
+/** Default timeout value for read operations.
+ * Set this to 0 to disable timeout detection.
+ */
+uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT;
+
+#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
+ /*
+ FastWire 0.2
+ This is a library to help faster programs to read I2C devices.
+ Copyright(C) 2011 Francesco Ferrara
+ occhiobello at gmail dot com
+ */
+
+ boolean Fastwire::waitInt() {
+ int l = 250;
+ while (!(TWCR & (1 << TWINT)) && l-- > 0);
+ return l > 0;
+ }
+
+ void Fastwire::setup(int khz, boolean pullup) {
+ TWCR = 0;
+ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
+ // activate internal pull-ups for twi (PORTC bits 4 & 5)
+ // as per note from atmega8 manual pg167
+ if (pullup) PORTC |= ((1 << 4) | (1 << 5));
+ else PORTC &= ~((1 << 4) | (1 << 5));
+ #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+ // activate internal pull-ups for twi (PORTC bits 0 & 1)
+ if (pullup) PORTC |= ((1 << 0) | (1 << 1));
+ else PORTC &= ~((1 << 0) | (1 << 1));
+ #else
+ // activate internal pull-ups for twi (PORTD bits 0 & 1)
+ // as per note from atmega128 manual pg204
+ if (pullup) PORTD |= ((1 << 0) | (1 << 1));
+ else PORTD &= ~((1 << 0) | (1 << 1));
+ #endif
+
+ TWSR = 0; // no prescaler => prescaler = 1
+ TWBR = ((16000L / khz) - 16) / 2; // change the I2C clock rate
+ TWCR = 1 << TWEN; // enable twi module, no interrupt
+ }
+
+ byte Fastwire::write(byte device, byte address, byte value) {
+ byte twst, retry;
+
+ retry = 2;
+ do {
+ TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
+ if (!waitInt()) return 1;
+ twst = TWSR & 0xF8;
+ if (twst != TW_START && twst != TW_REP_START) return 2;
+
+ TWDR = device & 0xFE; // send device address without read bit (1)
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 3;
+ twst = TWSR & 0xF8;
+ } while (twst == TW_MT_SLA_NACK && retry-- > 0);
+ if (twst != TW_MT_SLA_ACK) return 4;
+
+ TWDR = address; // send data to the previously addressed device
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 5;
+ twst = TWSR & 0xF8;
+ if (twst != TW_MT_DATA_ACK) return 6;
+
+ TWDR = value; // send data to the previously addressed device
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 7;
+ twst = TWSR & 0xF8;
+ if (twst != TW_MT_DATA_ACK) return 8;
+
+ return 0;
+ }
+
+ byte Fastwire::readBuf(byte device, byte address, byte *data, byte num) {
+ byte twst, retry;
+
+ retry = 2;
+ do {
+ TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
+ if (!waitInt()) return 16;
+ twst = TWSR & 0xF8;
+ if (twst != TW_START && twst != TW_REP_START) return 17;
+
+ TWDR = device & 0xfe; // send device address to write
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 18;
+ twst = TWSR & 0xF8;
+ } while (twst == TW_MT_SLA_NACK && retry-- > 0);
+ if (twst != TW_MT_SLA_ACK) return 19;
+
+ TWDR = address; // send data to the previously addressed device
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 20;
+ twst = TWSR & 0xF8;
+ if (twst != TW_MT_DATA_ACK) return 21;
+
+ /***/
+
+ retry = 2;
+ do {
+ TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
+ if (!waitInt()) return 22;
+ twst = TWSR & 0xF8;
+ if (twst != TW_START && twst != TW_REP_START) return 23;
+
+ TWDR = device | 0x01; // send device address with the read bit (1)
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ if (!waitInt()) return 24;
+ twst = TWSR & 0xF8;
+ } while (twst == TW_MR_SLA_NACK && retry-- > 0);
+ if (twst != TW_MR_SLA_ACK) return 25;
+
+ for(uint8_t i = 0; i < num; i++) {
+ if (i == num - 1)
+ TWCR = (1 << TWINT) | (1 << TWEN);
+ else
+ TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
+ if (!waitInt()) return 26;
+ twst = TWSR & 0xF8;
+ if (twst != TW_MR_DATA_ACK && twst != TW_MR_DATA_NACK) return twst;
+ data[i] = TWDR;
+ }
+
+ return 0;
+ }
+#endif
+
+#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
+ // NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
+ // Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
+ // Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
+
+ /*
+ call this version 1.0
+
+ Offhand, the only funky part that I can think of is in nbrequestFrom, where the buffer
+ length and index are set *before* the data is actually read. The problem is that these
+ are variables local to the TwoWire object, and by the time we actually have read the
+ data, and know what the length actually is, we have no simple access to the object's
+ variables. The actual bytes read *is* given to the callback function, though.
+
+ The ISR code for a slave receiver is commented out. I don't have that setup, and can't
+ verify it at this time. Save it for 2.0!
+
+ The handling of the read and write processes here is much like in the demo sketch code:
+ the process is broken down into sequential functions, where each registers the next as a
+ callback, essentially.
+
+ For example, for the Read process, twi_read00 just returns if TWI is not yet in a
+ ready state. When there's another interrupt, and the interface *is* ready, then it
+ sets up the read, starts it, and registers twi_read01 as the function to call after
+ the *next* interrupt. twi_read01, then, just returns if the interface is still in a
+ "reading" state. When the reading is done, it copies the information to the buffer,
+ cleans up, and calls the user-requested callback function with the actual number of
+ bytes read.
+
+ The writing is similar.
+
+ Questions, comments and problems can go to Gene@Telobot.com.
+
+ Thumbs Up!
+ Gene Knight
+
+ */
+
+ uint8_t TwoWire::rxBuffer[NBWIRE_BUFFER_LENGTH];
+ uint8_t TwoWire::rxBufferIndex = 0;
+ uint8_t TwoWire::rxBufferLength = 0;
+
+ uint8_t TwoWire::txAddress = 0;
+ uint8_t TwoWire::txBuffer[NBWIRE_BUFFER_LENGTH];
+ uint8_t TwoWire::txBufferIndex = 0;
+ uint8_t TwoWire::txBufferLength = 0;
+
+ //uint8_t TwoWire::transmitting = 0;
+ void (*TwoWire::user_onRequest)(void);
+ void (*TwoWire::user_onReceive)(int);
+
+ static volatile uint8_t twi_transmitting;
+ static volatile uint8_t twi_state;
+ static uint8_t twi_slarw;
+ static volatile uint8_t twi_error;
+ static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
+ static volatile uint8_t twi_masterBufferIndex;
+ static uint8_t twi_masterBufferLength;
+ static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
+ static volatile uint8_t twi_rxBufferIndex;
+ //static volatile uint8_t twi_Interrupt_Continue_Command;
+ static volatile uint8_t twi_Return_Value;
+ static volatile uint8_t twi_Done;
+ void (*twi_cbendTransmissionDone)(int);
+ void (*twi_cbreadFromDone)(int);
+
+ void twi_init() {
+ // initialize state
+ twi_state = TWI_READY;
+
+ // activate internal pull-ups for twi
+ // as per note from atmega8 manual pg167
+ sbi(PORTC, 4);
+ sbi(PORTC, 5);
+
+ // initialize twi prescaler and bit rate
+ cbi(TWSR, TWPS0); // TWI Status Register - Prescaler bits
+ cbi(TWSR, TWPS1);
+
+ /* twi bit rate formula from atmega128 manual pg 204
+ SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
+ note: TWBR should be 10 or higher for master mode
+ It is 72 for a 16mhz Wiring board with 100kHz TWI */
+
+ TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; // bitrate register
+ // enable twi module, acks, and twi interrupt
+
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
+
+ /* TWEN - TWI Enable Bit
+ TWIE - TWI Interrupt Enable
+ TWEA - TWI Enable Acknowledge Bit
+ TWINT - TWI Interrupt Flag
+ TWSTA - TWI Start Condition
+ */
+ }
+
+ typedef struct {
+ uint8_t address;
+ uint8_t* data;
+ uint8_t length;
+ uint8_t wait;
+ uint8_t i;
+ } twi_Write_Vars;
+
+ twi_Write_Vars *ptwv = 0;
+ static void (*fNextInterruptFunction)(void) = 0;
+
+ void twi_Finish(byte bRetVal) {
+ if (ptwv) {
+ free(ptwv);
+ ptwv = 0;
+ }
+ twi_Done = 0xFF;
+ twi_Return_Value = bRetVal;
+ fNextInterruptFunction = 0;
+ }
+
+ uint8_t twii_WaitForDone(uint16_t timeout) {
+ uint32_t endMillis = millis() + timeout;
+ while (!twi_Done && (timeout == 0 || millis() < endMillis)) continue;
+ return twi_Return_Value;
+ }
+
+ void twii_SetState(uint8_t ucState) {
+ twi_state = ucState;
+ }
+
+ void twii_SetError(uint8_t ucError) {
+ twi_error = ucError ;
+ }
+
+ void twii_InitBuffer(uint8_t ucPos, uint8_t ucLength) {
+ twi_masterBufferIndex = 0;
+ twi_masterBufferLength = ucLength;
+ }
+
+ void twii_CopyToBuf(uint8_t* pData, uint8_t ucLength) {
+ uint8_t i;
+ for (i = 0; i < ucLength; ++i) {
+ twi_masterBuffer[i] = pData[i];
+ }
+ }
+
+ void twii_CopyFromBuf(uint8_t *pData, uint8_t ucLength) {
+ uint8_t i;
+ for (i = 0; i < ucLength; ++i) {
+ pData[i] = twi_masterBuffer[i];
+ }
+ }
+
+ void twii_SetSlaRW(uint8_t ucSlaRW) {
+ twi_slarw = ucSlaRW;
+ }
+
+ void twii_SetStart() {
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ }
+
+ void twi_write01() {
+ if (TWI_MTX == twi_state) return; // blocking test
+ twi_transmitting = 0 ;
+ if (twi_error == 0xFF)
+ twi_Finish (0); // success
+ else if (twi_error == TW_MT_SLA_NACK)
+ twi_Finish (2); // error: address send, nack received
+ else if (twi_error == TW_MT_DATA_NACK)
+ twi_Finish (3); // error: data send, nack received
+ else
+ twi_Finish (4); // other twi error
+ if (twi_cbendTransmissionDone) return twi_cbendTransmissionDone(twi_Return_Value);
+ return;
+ }
+
+
+ void twi_write00() {
+ if (TWI_READY != twi_state) return; // blocking test
+ if (TWI_BUFFER_LENGTH < ptwv -> length) {
+ twi_Finish(1); // end write with error 1
+ return;
+ }
+ twi_Done = 0x00; // show as working
+ twii_SetState(TWI_MTX); // to transmitting
+ twii_SetError(0xFF); // to No Error
+ twii_InitBuffer(0, ptwv -> length); // pointer and length
+ twii_CopyToBuf(ptwv -> data, ptwv -> length); // get the data
+ twii_SetSlaRW((ptwv -> address << 1) | TW_WRITE); // write command
+ twii_SetStart(); // start the cycle
+ fNextInterruptFunction = twi_write01; // next routine
+ return twi_write01();
+ }
+
+ void twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) {
+ uint8_t i;
+ ptwv = (twi_Write_Vars *)malloc(sizeof(twi_Write_Vars));
+ ptwv -> address = address;
+ ptwv -> data = data;
+ ptwv -> length = length;
+ ptwv -> wait = wait;
+ fNextInterruptFunction = twi_write00;
+ return twi_write00();
+ }
+
+ void twi_read01() {
+ if (TWI_MRX == twi_state) return; // blocking test
+ if (twi_masterBufferIndex < ptwv -> length) ptwv -> length = twi_masterBufferIndex;
+ twii_CopyFromBuf(ptwv -> data, ptwv -> length);
+ twi_Finish(ptwv -> length);
+ if (twi_cbreadFromDone) return twi_cbreadFromDone(twi_Return_Value);
+ return;
+ }
+
+ void twi_read00() {
+ if (TWI_READY != twi_state) return; // blocking test
+ if (TWI_BUFFER_LENGTH < ptwv -> length) twi_Finish(0); // error return
+ twi_Done = 0x00; // show as working
+ twii_SetState(TWI_MRX); // reading
+ twii_SetError(0xFF); // reset error
+ twii_InitBuffer(0, ptwv -> length - 1); // init to one less than length
+ twii_SetSlaRW((ptwv -> address << 1) | TW_READ); // read command
+ twii_SetStart(); // start cycle
+ fNextInterruptFunction = twi_read01;
+ return twi_read01();
+ }
+
+ void twi_readFrom(uint8_t address, uint8_t* data, uint8_t length) {
+ uint8_t i;
+
+ ptwv = (twi_Write_Vars *)malloc(sizeof(twi_Write_Vars));
+ ptwv -> address = address;
+ ptwv -> data = data;
+ ptwv -> length = length;
+ fNextInterruptFunction = twi_read00;
+ return twi_read00();
+ }
+
+ void twi_reply(uint8_t ack) {
+ // transmit master read ready signal, with or without ack
+ if (ack){
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
+ } else {
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
+ }
+ }
+
+ void twi_stop(void) {
+ // send stop condition
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
+
+ // wait for stop condition to be exectued on bus
+ // TWINT is not set after a stop condition!
+ while (TWCR & _BV(TWSTO)) {
+ continue;
+ }
+
+ // update twi state
+ twi_state = TWI_READY;
+ }
+
+ void twi_releaseBus(void) {
+ // release bus
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
+
+ // update twi state
+ twi_state = TWI_READY;
+ }
+
+ SIGNAL(TWI_vect) {
+ switch (TW_STATUS) {
+ // All Master
+ case TW_START: // sent start condition
+ case TW_REP_START: // sent repeated start condition
+ // copy device address and r/w bit to output register and ack
+ TWDR = twi_slarw;
+ twi_reply(1);
+ break;
+
+ // Master Transmitter
+ case TW_MT_SLA_ACK: // slave receiver acked address
+ case TW_MT_DATA_ACK: // slave receiver acked data
+ // if there is data to send, send it, otherwise stop
+ if (twi_masterBufferIndex < twi_masterBufferLength) {
+ // copy data to output register and ack
+ TWDR = twi_masterBuffer[twi_masterBufferIndex++];
+ twi_reply(1);
+ } else {
+ twi_stop();
+ }
+ break;
+
+ case TW_MT_SLA_NACK: // address sent, nack received
+ twi_error = TW_MT_SLA_NACK;
+ twi_stop();
+ break;
+
+ case TW_MT_DATA_NACK: // data sent, nack received
+ twi_error = TW_MT_DATA_NACK;
+ twi_stop();
+ break;
+
+ case TW_MT_ARB_LOST: // lost bus arbitration
+ twi_error = TW_MT_ARB_LOST;
+ twi_releaseBus();
+ break;
+
+ // Master Receiver
+ case TW_MR_DATA_ACK: // data received, ack sent
+ // put byte into buffer
+ twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
+
+ case TW_MR_SLA_ACK: // address sent, ack received
+ // ack if more bytes are expected, otherwise nack
+ if (twi_masterBufferIndex < twi_masterBufferLength) {
+ twi_reply(1);
+ } else {
+ twi_reply(0);
+ }
+ break;
+
+ case TW_MR_DATA_NACK: // data received, nack sent
+ // put final byte into buffer
+ twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
+
+ case TW_MR_SLA_NACK: // address sent, nack received
+ twi_stop();
+ break;
+
+ // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
+
+ // Slave Receiver (NOT IMPLEMENTED YET)
+ /*
+ case TW_SR_SLA_ACK: // addressed, returned ack
+ case TW_SR_GCALL_ACK: // addressed generally, returned ack
+ case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
+ case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
+ // enter slave receiver mode
+ twi_state = TWI_SRX;
+
+ // indicate that rx buffer can be overwritten and ack
+ twi_rxBufferIndex = 0;
+ twi_reply(1);
+ break;
+
+ case TW_SR_DATA_ACK: // data received, returned ack
+ case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
+ // if there is still room in the rx buffer
+ if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) {
+ // put byte in buffer and ack
+ twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
+ twi_reply(1);
+ } else {
+ // otherwise nack
+ twi_reply(0);
+ }
+ break;
+
+ case TW_SR_STOP: // stop or repeated start condition received
+ // put a null char after data if there's room
+ if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) {
+ twi_rxBuffer[twi_rxBufferIndex] = 0;
+ }
+
+ // sends ack and stops interface for clock stretching
+ twi_stop();
+
+ // callback to user defined callback
+ twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
+
+ // since we submit rx buffer to "wire" library, we can reset it
+ twi_rxBufferIndex = 0;
+
+ // ack future responses and leave slave receiver state
+ twi_releaseBus();
+ break;
+
+ case TW_SR_DATA_NACK: // data received, returned nack
+ case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
+ // nack back at master
+ twi_reply(0);
+ break;
+
+ // Slave Transmitter
+ case TW_ST_SLA_ACK: // addressed, returned ack
+ case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
+ // enter slave transmitter mode
+ twi_state = TWI_STX;
+
+ // ready the tx buffer index for iteration
+ twi_txBufferIndex = 0;
+
+ // set tx buffer length to be zero, to verify if user changes it
+ twi_txBufferLength = 0;
+
+ // request for txBuffer to be filled and length to be set
+ // note: user must call twi_transmit(bytes, length) to do this
+ twi_onSlaveTransmit();
+
+ // if they didn't change buffer & length, initialize it
+ if (0 == twi_txBufferLength) {
+ twi_txBufferLength = 1;
+ twi_txBuffer[0] = 0x00;
+ }
+
+ // transmit first byte from buffer, fall through
+
+ case TW_ST_DATA_ACK: // byte sent, ack returned
+ // copy data to output register
+ TWDR = twi_txBuffer[twi_txBufferIndex++];
+
+ // if there is more to send, ack, otherwise nack
+ if (twi_txBufferIndex < twi_txBufferLength) {
+ twi_reply(1);
+ } else {
+ twi_reply(0);
+ }
+ break;
+
+ case TW_ST_DATA_NACK: // received nack, we are done
+ case TW_ST_LAST_DATA: // received ack, but we are done already!
+ // ack future responses
+ twi_reply(1);
+ // leave slave receiver state
+ twi_state = TWI_READY;
+ break;
+ */
+
+ // all
+ case TW_NO_INFO: // no state information
+ break;
+
+ case TW_BUS_ERROR: // bus error, illegal stop/start
+ twi_error = TW_BUS_ERROR;
+ twi_stop();
+ break;
+ }
+
+ if (fNextInterruptFunction) return fNextInterruptFunction();
+ }
+
+ TwoWire::TwoWire() { }
+
+ void TwoWire::begin(void) {
+ rxBufferIndex = 0;
+ rxBufferLength = 0;
+
+ txBufferIndex = 0;
+ txBufferLength = 0;
+
+ twi_init();
+ }
+
+ void TwoWire::beginTransmission(uint8_t address) {
+ //beginTransmission((uint8_t)address);
+
+ // indicate that we are transmitting
+ twi_transmitting = 1;
+
+ // set address of targeted slave
+ txAddress = address;
+
+ // reset tx buffer iterator vars
+ txBufferIndex = 0;
+ txBufferLength = 0;
+ }
+
+ uint8_t TwoWire::endTransmission(uint16_t timeout) {
+ // transmit buffer (blocking)
+ //int8_t ret =
+ twi_cbendTransmissionDone = NULL;
+ twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
+ int8_t ret = twii_WaitForDone(timeout);
+
+ // reset tx buffer iterator vars
+ txBufferIndex = 0;
+ txBufferLength = 0;
+
+ // indicate that we are done transmitting
+ // twi_transmitting = 0;
+ return ret;
+ }
+
+ void TwoWire::nbendTransmission(void (*function)(int)) {
+ twi_cbendTransmissionDone = function;
+ twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
+ return;
+ }
+
+ void TwoWire::send(uint8_t data) {
+ if (twi_transmitting) {
+ // in master transmitter mode
+ // don't bother if buffer is full
+ if (txBufferLength >= NBWIRE_BUFFER_LENGTH) {
+ return;
+ }
+
+ // put byte in tx buffer
+ txBuffer[txBufferIndex] = data;
+ ++txBufferIndex;
+
+ // update amount in buffer
+ txBufferLength = txBufferIndex;
+ } else {
+ // in slave send mode
+ // reply to master
+ //twi_transmit(&data, 1);
+ }
+ }
+
+ uint8_t TwoWire::receive(void) {
+ // default to returning null char
+ // for people using with char strings
+ uint8_t value = 0;
+
+ // get each successive byte on each call
+ if (rxBufferIndex < rxBufferLength) {
+ value = rxBuffer[rxBufferIndex];
+ ++rxBufferIndex;
+ }
+
+ return value;
+ }
+
+ uint8_t TwoWire::requestFrom(uint8_t address, int quantity, uint16_t timeout) {
+ // clamp to buffer length
+ if (quantity > NBWIRE_BUFFER_LENGTH) {
+ quantity = NBWIRE_BUFFER_LENGTH;
+ }
+
+ // perform blocking read into buffer
+ twi_cbreadFromDone = NULL;
+ twi_readFrom(address, rxBuffer, quantity);
+ uint8_t read = twii_WaitForDone(timeout);
+
+ // set rx buffer iterator vars
+ rxBufferIndex = 0;
+ rxBufferLength = read;
+
+ return read;
+ }
+
+ void TwoWire::nbrequestFrom(uint8_t address, int quantity, void (*function)(int)) {
+ // clamp to buffer length
+ if (quantity > NBWIRE_BUFFER_LENGTH) {
+ quantity = NBWIRE_BUFFER_LENGTH;
+ }
+
+ // perform blocking read into buffer
+ twi_cbreadFromDone = function;
+ twi_readFrom(address, rxBuffer, quantity);
+ //uint8_t read = twii_WaitForDone();
+
+ // set rx buffer iterator vars
+ //rxBufferIndex = 0;
+ //rxBufferLength = read;
+
+ rxBufferIndex = 0;
+ rxBufferLength = quantity; // this is a hack
+
+ return; //read;
+ }
+
+ uint8_t TwoWire::available(void) {
+ return rxBufferLength - rxBufferIndex;
+ }
+
+#endif