diff --git a/Main/lib/Adxl345/ADXL345.cpp b/Main/lib/Adxl345/ADXL345.cpp new file mode 100644 index 0000000..7890d4c --- /dev/null +++ b/Main/lib/Adxl345/ADXL345.cpp @@ -0,0 +1,1668 @@ +// I2Cdev library collection - ADXL345 I2C device class +// Based on Analog Devices ADXL345 datasheet rev. C, 5/2011 +// 7/31/2011 by Jeff Rowberg +// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib +// +// Changelog: +// 2011-07-31 - initial release + +/* ============================================ +I2Cdev device library code is placed under the MIT license +Copyright (c) 2011 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 "ADXL345.h" + +/** Default constructor, uses default I2C address. + * @see ADXL345_DEFAULT_ADDRESS + */ +ADXL345::ADXL345() { + devAddr = ADXL345_DEFAULT_ADDRESS; +} + +/** Specific address constructor. + * @param address I2C address + * @see ADXL345_DEFAULT_ADDRESS + * @see ADXL345_ADDRESS_ALT_LOW + * @see ADXL345_ADDRESS_ALT_HIGH + */ +ADXL345::ADXL345(uint8_t address) { + devAddr = address; +} + +/** Power on and prepare for general usage. + * This will activate the accelerometer, so be sure to adjust the power settings + * after you call this method if you want it to enter standby mode, or another + * less demanding mode of operation. + */ +void ADXL345::initialize() { + I2Cdev::writeByte(devAddr, ADXL345_RA_POWER_CTL, 0); // reset all power settings + setAutoSleepEnabled(true); + setMeasureEnabled(true); +} + +/** Verify the I2C connection. + * Make sure the device is connected and responds as expected. + * @return True if connection is valid, false otherwise + */ +bool ADXL345::testConnection() { + return getDeviceID() == 0xE5; +} + +// DEVID register + +/** Get Device ID. + * The DEVID register holds a fixed device ID code of 0xE5 (345 octal). + * @return Device ID (should be 0xE5, 229 dec, 345 oct) + * @see ADXL345_RA_DEVID + */ +uint8_t ADXL345::getDeviceID() { + I2Cdev::readByte(devAddr, ADXL345_RA_DEVID, buffer); + return buffer[0]; +} + +// THRESH_TAP register + +/** Get tap threshold. + * The THRESH_TAP register is eight bits and holds the threshold value for tap + * interrupts. The data format is unsigned, therefore, the magnitude of the tap + * event is compared with the value in THRESH_TAP for normal tap detection. The + * scale factor is 62.5 mg/LSB (that is, 0xFF = 16 g). A value of 0 may result + * in undesirable behavior if single tap/double tap interrupts are enabled. + * @return Tap threshold (scaled at 62.5 mg/LSB) + * @see ADXL345_RA_THRESH_TAP + */ +uint8_t ADXL345::getTapThreshold() { + I2Cdev::readByte(devAddr, ADXL345_RA_THRESH_TAP, buffer); + return buffer[0]; +} +/** Set tap threshold. + * @param threshold Tap magnitude threshold (scaled at 62.5 mg/LSB) + * @see ADXL345_RA_THRESH_TAP + * @see getTapThreshold() + */ +void ADXL345::setTapThreshold(uint8_t threshold) { + I2Cdev::writeByte(devAddr, ADXL345_RA_THRESH_TAP, threshold); +} + +// OFS* registers + +/** Get axis offsets. + * The OFSX, OFSY, and OFSZ registers are each eight bits and offer user-set + * offset adjustments in twos complement format with a scale factor of 15.6 + * mg/LSB (that is, 0x7F = 2 g). The value stored in the offset registers is + * automatically added to the acceleration data, and the resulting value is + * stored in the output data registers. For additional information regarding + * offset calibration and the use of the offset registers, refer to the Offset + * Calibration section of the datasheet. + * @param x X axis offset container + * @param y Y axis offset container + * @param z Z axis offset container + * @see ADXL345_RA_OFSX + * @see ADXL345_RA_OFSY + * @see ADXL345_RA_OFSZ + */ +void ADXL345::getOffset(int8_t* x, int8_t* y, int8_t* z) { + I2Cdev::readBytes(devAddr, ADXL345_RA_OFSX, 3, buffer); + *x = buffer[0]; + *y = buffer[1]; + *z = buffer[2]; +} +/** Set axis offsets. + * @param x X axis offset value + * @param y Y axis offset value + * @param z Z axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSX + * @see ADXL345_RA_OFSY + * @see ADXL345_RA_OFSZ + */ +void ADXL345::setOffset(int8_t x, int8_t y, int8_t z) { + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSX, x); + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSY, y); + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSZ, z); +} +/** Get X axis offset. + * @return X axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSX + */ +int8_t ADXL345::getOffsetX() { + I2Cdev::readByte(devAddr, ADXL345_RA_OFSX, buffer); + return buffer[0]; +} +/** Set X axis offset. + * @param x X axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSX + */ +void ADXL345::setOffsetX(int8_t x) { + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSX, x); +} +/** Get Y axis offset. + * @return Y axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSY + */ +int8_t ADXL345::getOffsetY() { + I2Cdev::readByte(devAddr, ADXL345_RA_OFSY, buffer); + return buffer[0]; +} +/** Set Y axis offset. + * @param y Y axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSY + */ +void ADXL345::setOffsetY(int8_t y) { + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSY, y); +} +/** Get Z axis offset. + * @return Z axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSZ + */ +int8_t ADXL345::getOffsetZ() { + I2Cdev::readByte(devAddr, ADXL345_RA_OFSZ, buffer); + return buffer[0]; +} +/** Set Z axis offset. + * @param z Z axis offset value + * @see getOffset() + * @see ADXL345_RA_OFSZ + */ +void ADXL345::setOffsetZ(int8_t z) { + I2Cdev::writeByte(devAddr, ADXL345_RA_OFSZ, z); +} + +// DUR register + +/** Get tap duration. + * The DUR register is eight bits and contains an unsigned time value + * representing the maximum time that an event must be above the THRESH_TAP + * threshold to qualify as a tap event. The scale factor is 625 us/LSB. A value + * of 0 disables the single tap/ double tap functions. + * @return Tap duration (scaled at 625 us/LSB) + * @see ADXL345_RA_DUR + */ +uint8_t ADXL345::getTapDuration() { + I2Cdev::readByte(devAddr, ADXL345_RA_DUR, buffer); + return buffer[0]; +} +/** Set tap duration. + * @param duration Tap duration (scaled at 625 us/LSB) + * @see getTapDuration() + * @see ADXL345_RA_DUR + */ +void ADXL345::setTapDuration(uint8_t duration) { + I2Cdev::writeByte(devAddr, ADXL345_RA_DUR, duration); +} + +// LATENT register + +/** Get tap duration. + * The latent register is eight bits and contains an unsigned time value + * representing the wait time from the detection of a tap event to the start of + * the time window (defined by the window register) during which a possible + * second tap event can be detected. The scale factor is 1.25 ms/LSB. A value of + * 0 disables the double tap function. + * @return Tap latency (scaled at 1.25 ms/LSB) + * @see ADXL345_RA_LATENT + */ +uint8_t ADXL345::getDoubleTapLatency() { + I2Cdev::readByte(devAddr, ADXL345_RA_LATENT, buffer); + return buffer[0]; +} +/** Set tap duration. + * @param latency Tap latency (scaled at 1.25 ms/LSB) + * @see getDoubleTapLatency() + * @see ADXL345_RA_LATENT + */ +void ADXL345::setDoubleTapLatency(uint8_t latency) { + I2Cdev::writeByte(devAddr, ADXL345_RA_LATENT, latency); +} + +// WINDOW register + +/** Get double tap window. + * The window register is eight bits and contains an unsigned time value + * representing the amount of time after the expiration of the latency time + * (determined by the latent register) during which a second valid tap can + * begin. The scale factor is 1.25 ms/LSB. A value of 0 disables the double tap + * function. + * @return Double tap window (scaled at 1.25 ms/LSB) + * @see ADXL345_RA_WINDOW + */ +uint8_t ADXL345::getDoubleTapWindow() { + I2Cdev::readByte(devAddr, ADXL345_RA_WINDOW, buffer); + return buffer[0]; +} +/** Set double tap window. + * @param window Double tap window (scaled at 1.25 ms/LSB) + * @see getDoubleTapWindow() + * @see ADXL345_RA_WINDOW + */ +void ADXL345::setDoubleTapWindow(uint8_t window) { + I2Cdev::writeByte(devAddr, ADXL345_RA_WINDOW, window); +} + +// THRESH_ACT register + +/** Get activity threshold. + * The THRESH_ACT register is eight bits and holds the threshold value for + * detecting activity. The data format is unsigned, so the magnitude of the + * activity event is compared with the value in the THRESH_ACT register. The + * scale factor is 62.5 mg/LSB. A value of 0 may result in undesirable behavior + * if the activity interrupt is enabled. + * @return Activity threshold (scaled at 62.5 mg/LSB) + * @see ADXL345_RA_THRESH_ACT + */ +uint8_t ADXL345::getActivityThreshold() { + I2Cdev::readByte(devAddr, ADXL345_RA_THRESH_ACT, buffer); + return buffer[0]; +} +/** Set activity threshold. + * @param threshold Activity threshold (scaled at 62.5 mg/LSB) + * @see getActivityThreshold() + * @see ADXL345_RA_THRESH_ACT + */ +void ADXL345::setActivityThreshold(uint8_t threshold) { + I2Cdev::writeByte(devAddr, ADXL345_RA_THRESH_ACT, threshold); +} + +// THRESH_INACT register + +/** Get inactivity threshold. + * The THRESH_INACT register is eight bits and holds the threshold value for + * detecting inactivity. The data format is unsigned, so the magnitude of the + * inactivity event is compared with the value in the THRESH_INACT register. The + * scale factor is 62.5 mg/LSB. A value of 0 may result in undesirable behavior + * if the inactivity interrupt is enabled. + * @return Inactivity threshold (scaled at 62.5 mg/LSB) + * @see ADXL345_RA_THRESH_INACT + */ +uint8_t ADXL345::getInactivityThreshold() { + I2Cdev::readByte(devAddr, ADXL345_RA_THRESH_INACT, buffer); + return buffer[0]; +} +/** Set inactivity threshold. + * @param threshold Inctivity threshold (scaled at 62.5 mg/LSB) + * @see getInctivityThreshold() + * @see ADXL345_RA_THRESH_INACT + */ +void ADXL345::setInactivityThreshold(uint8_t threshold) { + I2Cdev::writeByte(devAddr, ADXL345_RA_THRESH_INACT, threshold); +} + +// TIME_INACT register + +/** Set inactivity time. + * The TIME_INACT register is eight bits and contains an unsigned time value + * representing the amount of time that acceleration must be less than the value + * in the THRESH_INACT register for inactivity to be declared. The scale factor + * is 1 sec/LSB. Unlike the other interrupt functions, which use unfiltered data + * (see the Threshold sectionof the datasheet), the inactivity function uses + * filtered output data. At least one output sample must be generated for the + * inactivity interrupt to be triggered. This results in the function appearing + * unresponsive if the TIME_INACT register is set to a value less than the time + * constant of the output data rate. A value of 0 results in an interrupt when + * the output data is less than the value in the THRESH_INACT register. + * @return Inactivity time (scaled at 1 sec/LSB) + * @see ADXL345_RA_TIME_INACT + */ +uint8_t ADXL345::getInactivityTime() { + I2Cdev::readByte(devAddr, ADXL345_RA_TIME_INACT, buffer); + return buffer[0]; +} +/** Set inactivity time. + * @param time Inactivity time (scaled at 1 sec/LSB) + * @see getInctivityTime() + * @see ADXL345_RA_TIME_INACT + */ +void ADXL345::setInactivityTime(uint8_t time) { + I2Cdev::writeByte(devAddr, ADXL345_RA_TIME_INACT, time); +} + +// ACT_INACT_CTL register + +/** Get activity AC/DC coupling. + * A setting of 0 selects dc-coupled operation, and a setting of 1 enables + * ac-coupled operation. In dc-coupled operation, the current acceleration + * magnitude is compared directly with THRESH_ACT and THRESH_INACT to determine + * whether activity or inactivity is detected. + * + * In ac-coupled operation for activity detection, the acceleration value at the + * start of activity detection is taken as a reference value. New samples of + * acceleration are then compared to this reference value, and if the magnitude + * of the difference exceeds the THRESH_ACT value, the device triggers an + * activity interrupt. + * + * Similarly, in ac-coupled operation for inactivity detection, a reference + * value is used for comparison and is updated whenever the device exceeds the + * inactivity threshold. After the reference value is selected, the device + * compares the magnitude of the difference between the reference value and the + * current acceleration with THRESH_INACT. If the difference is less than the + * value in THRESH_INACT for the time in TIME_INACT, the device is considered + * inactive and the inactivity interrupt is triggered. + * + * @return Activity coupling (0 = DC, 1 = AC) + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_AC_BIT + */ +bool ADXL345::getActivityAC() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_AC_BIT, buffer); + return buffer[0]; +} +/** Set activity AC/DC coupling. + * @param enabled Activity AC/DC coupling (TRUE for AC, FALSE for DC) + * @see getActivityAC() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_AC_BIT + */ +void ADXL345::setActivityAC(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_AC_BIT, enabled); +} +/** Get X axis activity monitoring inclusion. + * For all "get[In]Activity*Enabled()" methods: a setting of 1 enables x-, y-, + * or z-axis participation in detecting activity or inactivity. A setting of 0 + * excludes the selected axis from participation. If all axes are excluded, the + * function is disabled. For activity detection, all participating axes are + * logically OR�ed, causing the activity function to trigger when any of the + * participating axes exceeds the threshold. For inactivity detection, all + * participating axes are logically AND�ed, causing the inactivity function to + * trigger only if all participating axes are below the threshold for the + * specified time. + * @return X axis activity monitoring enabled value + * @see getActivityAC() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_X_BIT + */ +bool ADXL345::getActivityXEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_X_BIT, buffer); + return buffer[0]; +} +/** Set X axis activity monitoring inclusion. + * @param enabled X axis activity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_X_BIT + */ +void ADXL345::setActivityXEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_X_BIT, enabled); +} +/** Get Y axis activity monitoring. + * @return Y axis activity monitoring enabled value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_Y_BIT + */ +bool ADXL345::getActivityYEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_Y_BIT, buffer); + return buffer[0]; +} +/** Set Y axis activity monitoring inclusion. + * @param enabled Y axis activity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_Y_BIT + */ +void ADXL345::setActivityYEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_Y_BIT, enabled); +} +/** Get Z axis activity monitoring. + * @return Z axis activity monitoring enabled value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_Z_BIT + */ +bool ADXL345::getActivityZEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_Z_BIT, buffer); + return buffer[0]; +} +/** Set Z axis activity monitoring inclusion. + * @param enabled Z axis activity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_ACT_Z_BIT + */ +void ADXL345::setActivityZEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_ACT_Z_BIT, enabled); +} +/** Get inactivity AC/DC coupling. + * @return Inctivity coupling (0 = DC, 1 = AC) + * @see getActivityAC() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_AC_BIT + */ +bool ADXL345::getInactivityAC() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_AC_BIT, buffer); + return buffer[0]; +} +/** Set inctivity AC/DC coupling. + * @param enabled Inactivity AC/DC coupling (TRUE for AC, FALSE for DC) + * @see getActivityAC() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_AC_BIT + */ +void ADXL345::setInactivityAC(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_AC_BIT, enabled); +} +/** Get X axis inactivity monitoring. + * @return Y axis inactivity monitoring enabled value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_X_BIT + */ +bool ADXL345::getInactivityXEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_X_BIT, buffer); + return buffer[0]; +} +/** Set X axis activity monitoring inclusion. + * @param enabled X axis inactivity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_X_BIT + */ +void ADXL345::setInactivityXEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_X_BIT, enabled); +} +/** Get Y axis inactivity monitoring. + * @return Y axis inactivity monitoring enabled value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_Y_BIT + */ +bool ADXL345::getInactivityYEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_Y_BIT, buffer); + return buffer[0]; +} +/** Set Y axis inactivity monitoring inclusion. + * @param enabled Y axis inactivity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_Y_BIT + */ +void ADXL345::setInactivityYEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_Y_BIT, enabled); +} +/** Get Z axis inactivity monitoring. + * @return Z axis inactivity monitoring enabled value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_Z_BIT + */ +bool ADXL345::getInactivityZEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_Z_BIT, buffer); + return buffer[0]; +} +/** Set Z axis inactivity monitoring inclusion. + * @param enabled Z axis activity monitoring inclusion value + * @see getActivityAC() + * @see getActivityXEnabled() + * @see ADXL345_RA_ACT_INACT_CTL + * @see ADXL345_AIC_INACT_Z_BIT + */ +void ADXL345::setInactivityZEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_ACT_INACT_CTL, ADXL345_AIC_INACT_Z_BIT, enabled); +} + +// THRESH_FF register + +/** Get freefall threshold value. + * The THRESH_FF register is eight bits and holds the threshold value, in + * unsigned format, for free-fall detection. The acceleration on all axes is + * compared with the value in THRESH_FF to determine if a free-fall event + * occurred. The scale factor is 62.5 mg/LSB. Note that a value of 0 mg may + * result in undesirable behavior if the free-fall interrupt is enabled. Values + * between 300 mg and 600 mg (0x05 to 0x09) are recommended. + * @return Freefall threshold value (scaled at 62.5 mg/LSB) + * @see ADXL345_RA_THRESH_FF + */ +uint8_t ADXL345::getFreefallThreshold() { + I2Cdev::readByte(devAddr, ADXL345_RA_THRESH_FF, buffer); + return buffer[0]; +} +/** Set freefall threshold value. + * @param threshold Freefall threshold value (scaled at 62.5 mg/LSB) + * @see getFreefallThreshold() + * @see ADXL345_RA_THRESH_FF + */ +void ADXL345::setFreefallThreshold(uint8_t threshold) { + I2Cdev::writeByte(devAddr, ADXL345_RA_THRESH_FF, threshold); +} + +// TIME_FF register + +/** Get freefall time value. + * The TIME_FF register is eight bits and stores an unsigned time value + * representing the minimum time that the value of all axes must be less than + * THRESH_FF to generate a free-fall interrupt. The scale factor is 5 ms/LSB. A + * value of 0 may result in undesirable behavior if the free-fall interrupt is + * enabled. Values between 100 ms and 350 ms (0x14 to 0x46) are recommended. + * @return Freefall time value (scaled at 5 ms/LSB) + * @see getFreefallThreshold() + * @see ADXL345_RA_TIME_FF + */ +uint8_t ADXL345::getFreefallTime() { + I2Cdev::readByte(devAddr, ADXL345_RA_TIME_FF, buffer); + return buffer[0]; +} +/** Set freefall time value. + * @param threshold Freefall time value (scaled at 5 ms/LSB) + * @see getFreefallTime() + * @see ADXL345_RA_TIME_FF + */ +void ADXL345::setFreefallTime(uint8_t time) { + I2Cdev::writeByte(devAddr, ADXL345_RA_TIME_FF, time); +} + +// TAP_AXES register + +/** Get double-tap fast-movement suppression. + * Setting the suppress bit suppresses double tap detection if acceleration + * greater than the value in THRESH_TAP is present between taps. See the Tap + * Detection section in the datasheet for more details. + * @return Double-tap fast-movement suppression value + * @see getTapThreshold() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_SUP_BIT + */ +bool ADXL345::getTapAxisSuppress() { + I2Cdev::readBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_SUP_BIT, buffer); + return buffer[0]; +} +/** Set double-tap fast-movement suppression. + * @param enabled Double-tap fast-movement suppression value + * @see getTapAxisSuppress() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_SUP_BIT + */ +void ADXL345::setTapAxisSuppress(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_SUP_BIT, enabled); +} +/** Get double-tap fast-movement suppression. + * A setting of 1 in the TAP_X enable bit enables x-axis participation in tap + * detection. A setting of 0 excludes the selected axis from participation in + * tap detection. + * @return Double-tap fast-movement suppression value + * @see getTapThreshold() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_X_BIT + */ +bool ADXL345::getTapAxisXEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_X_BIT, buffer); + return buffer[0]; +} +/** Set tap detection X axis inclusion. + * @param enabled X axis tap detection enabled value + * @see getTapAxisXEnabled() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_X_BIT + */ +void ADXL345::setTapAxisXEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_X_BIT, enabled); +} +/** Get tap detection Y axis inclusion. + * A setting of 1 in the TAP_Y enable bit enables y-axis participation in tap + * detection. A setting of 0 excludes the selected axis from participation in + * tap detection. + * @return Double-tap fast-movement suppression value + * @see getTapThreshold() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_Y_BIT + */ +bool ADXL345::getTapAxisYEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_Y_BIT, buffer); + return buffer[0]; +} +/** Set tap detection Y axis inclusion. + * @param enabled Y axis tap detection enabled value + * @see getTapAxisYEnabled() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_Y_BIT + */ +void ADXL345::setTapAxisYEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_Y_BIT, enabled); +} +/** Get tap detection Z axis inclusion. + * A setting of 1 in the TAP_Z enable bit enables z-axis participation in tap + * detection. A setting of 0 excludes the selected axis from participation in + * tap detection. + * @return Double-tap fast-movement suppression value + * @see getTapThreshold() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_Z_BIT + */ +bool ADXL345::getTapAxisZEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_Z_BIT, buffer); + return buffer[0]; +} +/** Set tap detection Z axis inclusion. + * @param enabled Z axis tap detection enabled value + * @see getTapAxisZEnabled() + * @see ADXL345_RA_TAP_AXES + * @see ADXL345_TAPAXIS_Z_BIT + */ +void ADXL345::setTapAxisZEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_TAP_AXES, ADXL345_TAPAXIS_Z_BIT, enabled); +} + +// ACT_TAP_STATUS register + +/** Get X axis activity source flag. + * These bits indicate the first axis involved in a tap or activity event. A + * setting of 1 corresponds to involvement in the event, and a setting of 0 + * corresponds to no involvement. When new data is available, these bits are not + * cleared but are overwritten by the new data. The ACT_TAP_STATUS register + * should be read before clearing the interrupt. Disabling an axis from + * participation clears the corresponding source bit when the next activity or + * single tap/double tap event occurs. + * @return X axis activity source flag + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_ACTX_BIT + */ +bool ADXL345::getActivitySourceX() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_ACTX_BIT, buffer); + return buffer[0]; +} +/** Get Y axis activity source flag. + * @return Y axis activity source flag + * @see getActivitySourceX() + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_ACTY_BIT + */ +bool ADXL345::getActivitySourceY() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_ACTY_BIT, buffer); + return buffer[0]; +} +/** Get Z axis activity source flag. + * @return Z axis activity source flag + * @see getActivitySourceX() + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_ACTZ_BIT + */ +bool ADXL345::getActivitySourceZ() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_ACTZ_BIT, buffer); + return buffer[0]; +} +/** Get sleep mode flag. + * A setting of 1 in the asleep bit indicates that the part is asleep, and a + * setting of 0 indicates that the part is not asleep. This bit toggles only if + * the device is configured for auto sleep. See the AUTO_SLEEP Bit section of + * the datasheet for more information on autosleep mode. + * @return Sleep mode enabled flag + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_ASLEEP_BIT + */ +bool ADXL345::getAsleep() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_ASLEEP_BIT, buffer); + return buffer[0]; +} +/** Get X axis tap source flag. + * @return X axis tap source flag + * @see getActivitySourceX() + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_TAPX_BIT + */ +bool ADXL345::getTapSourceX() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_TAPX_BIT, buffer); + return buffer[0]; +} +/** Get Y axis tap source flag. + * @return Y axis tap source flag + * @see getActivitySourceX() + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_TAPY_BIT + */ +bool ADXL345::getTapSourceY() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_TAPY_BIT, buffer); + return buffer[0]; +} +/** Get Z axis tap source flag. + * @return Z axis tap source flag + * @see getActivitySourceX() + * @see ADXL345_RA_ACT_TAP_STATUS + * @see ADXL345_TAPSTAT_TAPZ_BIT + */ +bool ADXL345::getTapSourceZ() { + I2Cdev::readBit(devAddr, ADXL345_RA_ACT_TAP_STATUS, ADXL345_TAPSTAT_TAPZ_BIT, buffer); + return buffer[0]; +} + +// BW_RATE register + +/** Get low power enabled status. + * A setting of 0 in the LOW_POWER bit selects normal operation, and a setting + * of 1 selects reduced power operation, which has somewhat higher noise (see + * the Power Modes section of the datasheet for details). + * @return Low power enabled status + * @see ADXL345_RA_BW_RATE + * @see ADXL345_BW_LOWPOWER_BIT + */ +bool ADXL345::getLowPowerEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_BW_RATE, ADXL345_BW_LOWPOWER_BIT, buffer); + return buffer[0]; +} +/** Set low power enabled status. + * @see getLowPowerEnabled() + * @param enabled Low power enable setting + * @see ADXL345_RA_BW_RATE + * @see ADXL345_BW_LOWPOWER_BIT + */ +void ADXL345::setLowPowerEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_BW_RATE, ADXL345_BW_LOWPOWER_BIT, enabled); +} +/** Get measurement data rate. + * These bits select the device bandwidth and output data rate (see Table 7 and + * Table 8 in the datasheet for details). The default value is 0x0A, which + * translates to a 100 Hz output data rate. An output data rate should be + * selected that is appropriate for the communication protocol and frequency + * selected. Selecting too high of an output data rate with a low communication + * speed results in samples being discarded. + * @return Data rate (0x0 - 0xF) + * @see ADXL345_RA_BW_RATE + * @see ADXL345_BW_RATE_BIT + * @see ADXL345_BW_RATE_LENGTH + */ +uint8_t ADXL345::getRate() { + I2Cdev::readBits(devAddr, ADXL345_RA_BW_RATE, ADXL345_BW_RATE_BIT, ADXL345_BW_RATE_LENGTH, buffer); + return buffer[0]; +} +/** Set measurement data rate. + * 0x7 = 12.5Hz + * 0x8 = 25Hz, increasing or decreasing by factors of 2, so: + * 0x9 = 50Hz + * 0xA = 100Hz + * @param rate New data rate (0x0 - 0xF) + * @see ADXL345_RATE_100 + * @see ADXL345_RA_BW_RATE + * @see ADXL345_BW_RATE_BIT + * @see ADXL345_BW_RATE_LENGTH + */ +void ADXL345::setRate(uint8_t rate) { + I2Cdev::writeBits(devAddr, ADXL345_RA_BW_RATE, ADXL345_BW_RATE_BIT, ADXL345_BW_RATE_LENGTH, rate); +} + +// POWER_CTL register + +/** Get activity/inactivity serial linkage status. + * A setting of 1 in the link bit with both the activity and inactivity + * functions enabled delays the start of the activity function until + * inactivity is detected. After activity is detected, inactivity detection + * begins, preventing the detection of activity. This bit serially links the + * activity and inactivity functions. When this bit is set to 0, the inactivity + * and activity functions are concurrent. Additional information can be found + * in the Link Mode section of the datasheet. + * + * When clearing the link bit, it is recommended that the part be placed into + * standby mode and then set back to measurement mode with a subsequent write. + * This is done to ensure that the device is properly biased if sleep mode is + * manually disabled; otherwise, the first few samples of data after the link + * bit is cleared may have additional noise, especially if the device was asleep + * when the bit was cleared. + * + * @return Link status + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_LINK_BIT + */ +bool ADXL345::getLinkEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_LINK_BIT, buffer); + return buffer[0]; +} +/** Set activity/inactivity serial linkage status. + * @param enabled New link status + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_LINK_BIT + */ +void ADXL345::setLinkEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_LINK_BIT, enabled); +} +/** Get auto-sleep enabled status. + * If the link bit is set, a setting of 1 in the AUTO_SLEEP bit enables the + * auto-sleep functionality. In this mode, the ADXL345 auto-matically switches + * to sleep mode if the inactivity function is enabled and inactivity is + * detected (that is, when acceleration is below the THRESH_INACT value for at + * least the time indicated by TIME_INACT). If activity is also enabled, the + * ADXL345 automatically wakes up from sleep after detecting activity and + * returns to operation at the output data rate set in the BW_RATE register. A + * setting of 0 in the AUTO_SLEEP bit disables automatic switching to sleep + * mode. See the description of the Sleep Bit in this section of the datasheet + * for more information on sleep mode. + * + * If the link bit is not set, the AUTO_SLEEP feature is disabled and setting + * the AUTO_SLEEP bit does not have an impact on device operation. Refer to the + * Link Bit section or the Link Mode section for more information on utilization + * of the link feature. + * + * When clearing the AUTO_SLEEP bit, it is recommended that the part be placed + * into standby mode and then set back to measure-ment mode with a subsequent + * write. This is done to ensure that the device is properly biased if sleep + * mode is manually disabled; otherwise, the first few samples of data after the + * AUTO_SLEEP bit is cleared may have additional noise, especially if the device + * was asleep when the bit was cleared. + * + * @return Auto-sleep enabled status + * @see getActivityThreshold() + * @see getInactivityThreshold() + * @see getInactivityTime() + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_AUTOSLEEP_BIT + */ +bool ADXL345::getAutoSleepEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_AUTOSLEEP_BIT, buffer); + return buffer[0]; +} +/** Set auto-sleep enabled status. + * @param enabled New auto-sleep status + * @see getAutoSleepEnabled() + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_AUTOSLEEP_BIT + */ +void ADXL345::setAutoSleepEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_AUTOSLEEP_BIT, enabled); +} +/** Get measurement enabled status. + * A setting of 0 in the measure bit places the part into standby mode, and a + * setting of 1 places the part into measurement mode. The ADXL345 powers up in + * standby mode with minimum power consumption. + * @return Measurement enabled status + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_MEASURE_BIT + */ +bool ADXL345::getMeasureEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_MEASURE_BIT, buffer); + return buffer[0]; +} +/** Set measurement enabled status. + * @param enabled Measurement enabled status + * @see getMeasureEnabled() + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_MEASURE_BIT + */ +void ADXL345::setMeasureEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_MEASURE_BIT, enabled); +} +/** Get sleep mode enabled status. + * A setting of 0 in the sleep bit puts the part into the normal mode of + * operation, and a setting of 1 places the part into sleep mode. Sleep mode + * suppresses DATA_READY, stops transmission of data to FIFO, and switches the + * sampling rate to one specified by the wakeup bits. In sleep mode, only the + * activity function can be used. When the DATA_READY interrupt is suppressed, + * the output data registers (Register 0x32 to Register 0x37) are still updated + * at the sampling rate set by the wakeup bits (D1:D0). + * + * When clearing the sleep bit, it is recommended that the part be placed into + * standby mode and then set back to measurement mode with a subsequent write. + * This is done to ensure that the device is properly biased if sleep mode is + * manually disabled; otherwise, the first few samples of data after the sleep + * bit is cleared may have additional noise, especially if the device was asleep + * when the bit was cleared. + * + * @return Sleep enabled status + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_SLEEP_BIT + */ +bool ADXL345::getSleepEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_SLEEP_BIT, buffer); + return buffer[0]; +} +/** Set sleep mode enabled status. + * @param Sleep mode enabled status + * @see getSleepEnabled() + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_SLEEP_BIT + */ +void ADXL345::setSleepEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_SLEEP_BIT, enabled); +} +/** Get wakeup frequency. + * These bits control the frequency of readings in sleep mode as described in + * Table 20 in the datasheet. (That is, 0 = 8Hz, 1 = 4Hz, 2 = 2Hz, 3 = 1Hz) + * @return Wakeup frequency (0x0 - 0x3, indicating 8/4/2/1Hz respectively) + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_SLEEP_BIT + */ +uint8_t ADXL345::getWakeupFrequency() { + I2Cdev::readBits(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_WAKEUP_BIT, ADXL345_PCTL_WAKEUP_LENGTH, buffer); + return buffer[0]; +} +/** Set wakeup frequency. + * @param frequency Wakeup frequency (0x0 - 0x3, indicating 8/4/2/1Hz respectively) + * @see getWakeupFrequency() + * @see ADXL345_RA_POWER_CTL + * @see ADXL345_PCTL_SLEEP_BIT + */ +void ADXL345::setWakeupFrequency(uint8_t frequency) { + I2Cdev::writeBits(devAddr, ADXL345_RA_POWER_CTL, ADXL345_PCTL_WAKEUP_BIT, ADXL345_PCTL_WAKEUP_LENGTH, frequency); +} + +// INT_ENABLE register + +/** Get DATA_READY interrupt enabled status. + * Setting bits in this register to a value of 1 enables their respective + * functions to generate interrupts, whereas a value of 0 prevents the functions + * from generating interrupts. The DATA_READY, watermark, and overrun bits + * enable only the interrupt output; the functions are always enabled. It is + * recommended that interrupts be configured before enabling their outputs. + * @return DATA_READY interrupt enabled status. + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_DATA_READY_BIT + */ +bool ADXL345::getIntDataReadyEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_DATA_READY_BIT, buffer); + return buffer[0]; +} +/** Set DATA_READY interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_DATA_READY_BIT + */ +void ADXL345::setIntDataReadyEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_DATA_READY_BIT, enabled); +} +/** Set SINGLE_TAP interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_SINGLE_TAP_BIT + */ +bool ADXL345::getIntSingleTapEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_SINGLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Set SINGLE_TAP interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_SINGLE_TAP_BIT + */ +void ADXL345::setIntSingleTapEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_SINGLE_TAP_BIT, enabled); +} +/** Get DOUBLE_TAP interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_DOUBLE_TAP_BIT + */ +bool ADXL345::getIntDoubleTapEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_DOUBLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Set DOUBLE_TAP interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_DOUBLE_TAP_BIT + */ +void ADXL345::setIntDoubleTapEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_DOUBLE_TAP_BIT, enabled); +} +/** Set ACTIVITY interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_ACTIVITY_BIT + */ +bool ADXL345::getIntActivityEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_ACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Set ACTIVITY interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_ACTIVITY_BIT + */ +void ADXL345::setIntActivityEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_ACTIVITY_BIT, enabled); +} +/** Get INACTIVITY interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_INACTIVITY_BIT + */ +bool ADXL345::getIntInactivityEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_INACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Set INACTIVITY interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_INACTIVITY_BIT + */ +void ADXL345::setIntInactivityEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_INACTIVITY_BIT, enabled); +} +/** Get FREE_FALL interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_FREE_FALL_BIT + */ +bool ADXL345::getIntFreefallEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_FREE_FALL_BIT, buffer); + return buffer[0]; +} +/** Set FREE_FALL interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_FREE_FALL_BIT + */ +void ADXL345::setIntFreefallEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_FREE_FALL_BIT, enabled); +} +/** Get WATERMARK interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_WATERMARK_BIT + */ +bool ADXL345::getIntWatermarkEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_WATERMARK_BIT, buffer); + return buffer[0]; +} +/** Set WATERMARK interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_WATERMARK_BIT + */ +void ADXL345::setIntWatermarkEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_WATERMARK_BIT, enabled); +} +/** Get OVERRUN interrupt enabled status. + * @return Interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_OVERRUN_BIT + */ +bool ADXL345::getIntOverrunEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_OVERRUN_BIT, buffer); + return buffer[0]; +} +/** Set OVERRUN interrupt enabled status. + * @param enabled New interrupt enabled status + * @see getIntDataReadyEnabled() + * @see ADXL345_RA_INT_ENABLE + * @see ADXL345_INT_OVERRUN_BIT + */ +void ADXL345::setIntOverrunEnabled(bool enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_ENABLE, ADXL345_INT_OVERRUN_BIT, enabled); +} + +// INT_MAP register + +/** Get DATA_READY interrupt pin. + * Any bits set to 0 in this register send their respective interrupts to the + * INT1 pin, whereas bits set to 1 send their respective interrupts to the INT2 + * pin. All selected interrupts for a given pin are OR'ed. + * @return Interrupt pin setting + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_DATA_READY_BIT + */ +uint8_t ADXL345::getIntDataReadyPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_DATA_READY_BIT, buffer); + return buffer[0]; +} +/** Set DATA_READY interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_DATA_READY_BIT + */ +void ADXL345::setIntDataReadyPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_DATA_READY_BIT, pin); +} +/** Get SINGLE_TAP interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_SINGLE_TAP_BIT + */ +uint8_t ADXL345::getIntSingleTapPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_SINGLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Set SINGLE_TAP interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_SINGLE_TAP_BIT + */ +void ADXL345::setIntSingleTapPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_SINGLE_TAP_BIT, pin); +} +/** Get DOUBLE_TAP interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_DOUBLE_TAP_BIT + */ +uint8_t ADXL345::getIntDoubleTapPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_DOUBLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Set DOUBLE_TAP interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_DOUBLE_TAP_BIT + */ +void ADXL345::setIntDoubleTapPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_DOUBLE_TAP_BIT, pin); +} +/** Get ACTIVITY interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_ACTIVITY_BIT + */ +uint8_t ADXL345::getIntActivityPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_ACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Set ACTIVITY interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_ACTIVITY_BIT + */ +void ADXL345::setIntActivityPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_ACTIVITY_BIT, pin); +} +/** Get INACTIVITY interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_INACTIVITY_BIT + */ +uint8_t ADXL345::getIntInactivityPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_INACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Set INACTIVITY interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_INACTIVITY_BIT + */ +void ADXL345::setIntInactivityPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_INACTIVITY_BIT, pin); +} +/** Get FREE_FALL interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_FREE_FALL_BIT + */ +uint8_t ADXL345::getIntFreefallPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_FREE_FALL_BIT, buffer); + return buffer[0]; +} +/** Set FREE_FALL interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_FREE_FALL_BIT + */ +void ADXL345::setIntFreefallPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_FREE_FALL_BIT, pin); +} +/** Get WATERMARK interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_WATERMARK_BIT + */ +uint8_t ADXL345::getIntWatermarkPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_WATERMARK_BIT, buffer); + return buffer[0]; +} +/** Set WATERMARK interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_WATERMARK_BIT + */ +void ADXL345::setIntWatermarkPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_WATERMARK_BIT, pin); +} +/** Get OVERRUN interrupt pin. + * @return Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_OVERRUN_BIT + */ +uint8_t ADXL345::getIntOverrunPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_OVERRUN_BIT, buffer); + return buffer[0]; +} +/** Set OVERRUN interrupt pin. + * @param pin Interrupt pin setting + * @see getIntDataReadyPin() + * @see ADXL345_RA_INT_MAP + * @see ADXL345_INT_OVERRUN_BIT + */ +void ADXL345::setIntOverrunPin(uint8_t pin) { + I2Cdev::writeBit(devAddr, ADXL345_RA_INT_MAP, ADXL345_INT_OVERRUN_BIT, pin); +} + +// INT_SOURCE register + +/** Get DATA_READY interrupt source flag. + * Bits set to 1 in this register indicate that their respective functions have + * triggered an event, whereas a value of 0 indicates that the corresponding + * event has not occurred. The DATA_READY, watermark, and overrun bits are + * always set if the corresponding events occur, regardless of the INT_ENABLE + * register settings, and are cleared by reading data from the DATAX, DATAY, and + * DATAZ registers. The DATA_READY and watermark bits may require multiple + * reads, as indicated in the FIFO mode descriptions in the FIFO section. Other + * bits, and the corresponding interrupts, are cleared by reading the INT_SOURCE + * register. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_DATA_READY_BIT + */ +uint8_t ADXL345::getIntDataReadySource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_DATA_READY_BIT, buffer); + return buffer[0]; +} +/** Get SINGLE_TAP interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_SINGLE_TAP_BIT + */ +uint8_t ADXL345::getIntSingleTapSource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_SINGLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Get DOUBLE_TAP interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_DOUBLE_TAP_BIT + */ +uint8_t ADXL345::getIntDoubleTapSource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_DOUBLE_TAP_BIT, buffer); + return buffer[0]; +} +/** Get ACTIVITY interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_ACTIVITY_BIT + */ +uint8_t ADXL345::getIntActivitySource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_ACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Get INACTIVITY interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_INACTIVITY_BIT + */ +uint8_t ADXL345::getIntInactivitySource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_INACTIVITY_BIT, buffer); + return buffer[0]; +} +/** Get FREE_FALL interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_FREE_FALL_BIT + */ +uint8_t ADXL345::getIntFreefallSource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_FREE_FALL_BIT, buffer); + return buffer[0]; +} +/** Get WATERMARK interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_WATERMARK_BIT + */ +uint8_t ADXL345::getIntWatermarkSource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_WATERMARK_BIT, buffer); + return buffer[0]; +} +/** Get OVERRUN interrupt source flag. + * @return Interrupt source flag + * @see ADXL345_RA_INT_SOURCE + * @see ADXL345_INT_OVERRUN_BIT + */ +uint8_t ADXL345::getIntOverrunSource() { + I2Cdev::readBit(devAddr, ADXL345_RA_INT_SOURCE, ADXL345_INT_OVERRUN_BIT, buffer); + return buffer[0]; +} + +// DATA_FORMAT register + +/** Get self-test force enabled. + * A setting of 1 in the SELF_TEST bit applies a self-test force to the sensor, + * causing a shift in the output data. A value of 0 disables the self-test + * force. + * @return Self-test force enabled setting + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_SELFTEST_BIT + */ +uint8_t ADXL345::getSelfTestEnabled() { + I2Cdev::readBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_SELFTEST_BIT, buffer); + return buffer[0]; +} +/** Set self-test force enabled. + * @param enabled New self-test force enabled setting + * @see getSelfTestEnabled() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_SELFTEST_BIT + */ +void ADXL345::setSelfTestEnabled(uint8_t enabled) { + I2Cdev::writeBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_SELFTEST_BIT, enabled); +} +/** Get SPI mode setting. + * A value of 1 in the SPI bit sets the device to 3-wire SPI mode, and a value + * of 0 sets the device to 4-wire SPI mode. + * @return SPI mode setting + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_SELFTEST_BIT + */ +uint8_t ADXL345::getSPIMode() { + I2Cdev::readBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_SPIMODE_BIT, buffer); + return buffer[0]; +} +/** Set SPI mode setting. + * @param mode New SPI mode setting + * @see getSPIMode() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_SELFTEST_BIT + */ +void ADXL345::setSPIMode(uint8_t mode) { + I2Cdev::writeBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_SPIMODE_BIT, mode); +} +/** Get interrupt mode setting. + * A value of 0 in the INT_INVERT bit sets the interrupts to active high, and a + * value of 1 sets the interrupts to active low. + * @return Interrupt mode setting + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_INTMODE_BIT + */ +uint8_t ADXL345::getInterruptMode() { + I2Cdev::readBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_INTMODE_BIT, buffer); + return buffer[0]; +} +/** Set interrupt mode setting. + * @param mode New interrupt mode setting + * @see getInterruptMode() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_INTMODE_BIT + */ +void ADXL345::setInterruptMode(uint8_t mode) { + I2Cdev::writeBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_INTMODE_BIT, mode); +} +/** Get full resolution mode setting. + * When this bit is set to a value of 1, the device is in full resolution mode, + * where the output resolution increases with the g range set by the range bits + * to maintain a 4 mg/LSB scale factor. When the FULL_RES bit is set to 0, the + * device is in 10-bit mode, and the range bits determine the maximum g range + * and scale factor. + * @return Full resolution enabled setting + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_FULL_RES_BIT + */ +uint8_t ADXL345::getFullResolution() { + I2Cdev::readBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_FULL_RES_BIT, buffer); + return buffer[0]; +} +/** Set full resolution mode setting. + * @param resolution New full resolution enabled setting + * @see getFullResolution() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_FULL_RES_BIT + */ +void ADXL345::setFullResolution(uint8_t resolution) { + I2Cdev::writeBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_FULL_RES_BIT, resolution); +} +/** Get data justification mode setting. + * A setting of 1 in the justify bit selects left-justified (MSB) mode, and a + * setting of 0 selects right-justified mode with sign extension. + * @return Data justification mode + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_JUSTIFY_BIT + */ +uint8_t ADXL345::getDataJustification() { + I2Cdev::readBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_JUSTIFY_BIT, buffer); + return buffer[0]; +} +/** Set data justification mode setting. + * @param justification New data justification mode + * @see getDataJustification() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_JUSTIFY_BIT + */ +void ADXL345::setDataJustification(uint8_t justification) { + I2Cdev::writeBit(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_JUSTIFY_BIT, justification); +} +/** Get data range setting. + * These bits set the g range as described in Table 21. (That is, 0x0 - 0x3 to + * indicate 2g/4g/8g/16g respectively) + * @return Range value (0x0 - 0x3 for 2g/4g/8g/16g) + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_RANGE_BIT + * @see ADXL345_FORMAT_RANGE_LENGTH + */ +uint8_t ADXL345::getRange() { + I2Cdev::readBits(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_RANGE_BIT, ADXL345_FORMAT_RANGE_LENGTH, buffer); + return buffer[0]; +} +/** Set data range setting. + * @param range Range value (0x0 - 0x3 for 2g/4g/8g/16g) + * @see getRange() + * @see ADXL345_RA_DATA_FORMAT + * @see ADXL345_FORMAT_RANGE_BIT + * @see ADXL345_FORMAT_RANGE_LENGTH + */ +void ADXL345::setRange(uint8_t range) { + I2Cdev::writeBits(devAddr, ADXL345_RA_DATA_FORMAT, ADXL345_FORMAT_RANGE_BIT, ADXL345_FORMAT_RANGE_LENGTH, range); +} + +// DATA* registers + +/** Get 3-axis accleration measurements. + * These six bytes (Register 0x32 to Register 0x37) are eight bits each and hold + * the output data for each axis. Register 0x32 and Register 0x33 hold the + * output data for the x-axis, Register 0x34 and Register 0x35 hold the output + * data for the y-axis, and Register 0x36 and Register 0x37 hold the output data + * for the z-axis. The output data is twos complement, with DATAx0 as the least + * significant byte and DATAx1 as the most significant byte, where x represent + * X, Y, or Z. The DATA_FORMAT register (Address 0x31) controls the format of + * the data. It is recommended that a multiple-byte read of all registers be + * performed to prevent a change in data between reads of sequential registers. + * + * The DATA_FORMAT register controls the presentation of data to Register 0x32 + * through Register 0x37. All data, except that for the +/-16 g range, must be + * clipped to avoid rollover. + * + * @param x 16-bit signed integer container for X-axis acceleration + * @param y 16-bit signed integer container for Y-axis acceleration + * @param z 16-bit signed integer container for Z-axis acceleration + * @see ADXL345_RA_DATAX0 + */ +void ADXL345::getAcceleration(int16_t* x, int16_t* y, int16_t* z) { + I2Cdev::readBytes(devAddr, ADXL345_RA_DATAX0, 6, buffer); + *x = (((int16_t)buffer[1]) << 8) | buffer[0]; + *y = (((int16_t)buffer[3]) << 8) | buffer[2]; + *z = (((int16_t)buffer[5]) << 8) | buffer[4]; +} +/** Get X-axis accleration measurement. + * @return 16-bit signed X-axis acceleration value + * @see ADXL345_RA_DATAX0 + */ +int16_t ADXL345::getAccelerationX() { + I2Cdev::readBytes(devAddr, ADXL345_RA_DATAX0, 2, buffer); + return (((int16_t)buffer[1]) << 8) | buffer[0]; +} +/** Get Y-axis accleration measurement. + * @return 16-bit signed Y-axis acceleration value + * @see ADXL345_RA_DATAY0 + */ +int16_t ADXL345::getAccelerationY() { + I2Cdev::readBytes(devAddr, ADXL345_RA_DATAY0, 2, buffer); + return (((int16_t)buffer[1]) << 8) | buffer[0]; +} +/** Get Z-axis accleration measurement. + * @return 16-bit signed Z-axis acceleration value + * @see ADXL345_RA_DATAZ0 + */ +int16_t ADXL345::getAccelerationZ() { + I2Cdev::readBytes(devAddr, ADXL345_RA_DATAZ0, 2, buffer); + return (((int16_t)buffer[1]) << 8) | buffer[0]; +} + +// FIFO_CTL register + +/** Get FIFO mode. + * These bits set the FIFO mode, as described in Table 22. That is: + * + * 0x0 = Bypass (FIFO is bypassed.) + * + * 0x1 = FIFO (FIFO collects up to 32 values and then stops collecting data, + * collecting new data only when FIFO is not full.) + * + * 0x2 = Stream (FIFO holds the last 32 data values. When FIFO is full, the + * oldest data is overwritten with newer data.) + * + * 0x3 = Trigger (When triggered by the trigger bit, FIFO holds the last data + * samples before the trigger event and then continues to collect data + * until full. New data is collected only when FIFO is not full.) + * + * @return Curent FIFO mode + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_MODE_BIT + * @see ADXL345_FIFO_MODE_LENGTH + */ +uint8_t ADXL345::getFIFOMode() { + I2Cdev::readBits(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_MODE_BIT, ADXL345_FIFO_MODE_LENGTH, buffer); + return buffer[0]; +} +/** Set FIFO mode. + * @param mode New FIFO mode + * @see getFIFOMode() + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_MODE_BIT + * @see ADXL345_FIFO_MODE_LENGTH + */ +void ADXL345::setFIFOMode(uint8_t mode) { + I2Cdev::writeBits(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_MODE_BIT, ADXL345_FIFO_MODE_LENGTH, mode); +} +/** Get FIFO trigger interrupt setting. + * A value of 0 in the trigger bit links the trigger event of trigger mode to + * INT1, and a value of 1 links the trigger event to INT2. + * @return Current FIFO trigger interrupt setting + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_TRIGGER_BIT + */ +uint8_t ADXL345::getFIFOTriggerInterruptPin() { + I2Cdev::readBit(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_TRIGGER_BIT, buffer); + return buffer[0]; +} +/** Set FIFO trigger interrupt pin setting. + * @param interrupt New FIFO trigger interrupt pin setting + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_TRIGGER_BIT + */ +void ADXL345::setFIFOTriggerInterruptPin(uint8_t interrupt) { + I2Cdev::writeBit(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_TRIGGER_BIT, interrupt); +} +/** Get FIFO samples setting. + * The function of these bits depends on the FIFO mode selected (see Table 23). + * Entering a value of 0 in the samples bits immediately sets the watermark + * status bit in the INT_SOURCE register, regardless of which FIFO mode is + * selected. Undesirable operation may occur if a value of 0 is used for the + * samples bits when trigger mode is used. + * + * MODE | EFFECT + * --------+------------------------------------------------------------------- + * Bypass | None. + * FIFO | FIFO entries needed to trigger a watermark interrupt. + * Stream | FIFO entries needed to trigger a watermark interrupt. + * Trigger | Samples are retained in the FIFO buffer before a trigger event. + * + * @return Current FIFO samples setting + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_SAMPLES_BIT + * @see ADXL345_FIFO_SAMPLES_LENGTH + */ +uint8_t ADXL345::getFIFOSamples() { + I2Cdev::readBits(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_SAMPLES_BIT, ADXL345_FIFO_SAMPLES_LENGTH, buffer); + return buffer[0]; +} +/** Set FIFO samples setting. + * @param size New FIFO samples setting (impact depends on FIFO mode setting) + * @see getFIFOSamples() + * @see getFIFOMode() + * @see ADXL345_RA_FIFO_CTL + * @see ADXL345_FIFO_SAMPLES_BIT + * @see ADXL345_FIFO_SAMPLES_LENGTH + */ +void ADXL345::setFIFOSamples(uint8_t size) { + I2Cdev::writeBits(devAddr, ADXL345_RA_FIFO_CTL, ADXL345_FIFO_SAMPLES_BIT, ADXL345_FIFO_SAMPLES_LENGTH, size); +} + +// FIFO_STATUS register + +/** Get FIFO trigger occurred status. + * A 1 in the FIFO_TRIG bit corresponds to a trigger event occurring, and a 0 + * means that a FIFO trigger event has not occurred. + * @return FIFO trigger occurred status + * @see ADXL345_RA_FIFO_STATUS + * @see ADXL345_FIFOSTAT_TRIGGER_BIT + */ +bool ADXL345::getFIFOTriggerOccurred() { + I2Cdev::readBit(devAddr, ADXL345_RA_FIFO_STATUS, ADXL345_FIFOSTAT_TRIGGER_BIT, buffer); + return buffer[0]; +} +/** Get FIFO length. + * These bits report how many data values are stored in FIFO. Access to collect + * the data from FIFO is provided through the DATAX, DATAY, and DATAZ registers. + * FIFO reads must be done in burst or multiple-byte mode because each FIFO + * level is cleared after any read (single- or multiple-byte) of FIFO. FIFO + * stores a maximum of 32 entries, which equates to a maximum of 33 entries + * available at any given time because an additional entry is available at the + * output filter of the I2Cdev:: + * @return Current FIFO length + * @see ADXL345_RA_FIFO_STATUS + * @see ADXL345_FIFOSTAT_LENGTH_BIT + * @see ADXL345_FIFOSTAT_LENGTH_LENGTH + */ +uint8_t ADXL345::getFIFOLength() { + I2Cdev::readBits(devAddr, ADXL345_RA_FIFO_STATUS, ADXL345_FIFOSTAT_LENGTH_BIT, ADXL345_FIFOSTAT_LENGTH_LENGTH, buffer); + return buffer[0]; +} diff --git a/Main/lib/Adxl345/ADXL345.h b/Main/lib/Adxl345/ADXL345.h new file mode 100644 index 0000000..b610caf --- /dev/null +++ b/Main/lib/Adxl345/ADXL345.h @@ -0,0 +1,361 @@ +// I2Cdev library collection - ADXL345 I2C device class header file +// Based on Analog Devices ADXL345 datasheet rev. C, 5/2011 +// 7/31/2011 by Jeff Rowberg +// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib +// +// Changelog: +// 2011-07-31 - initial release + +/* ============================================ +I2Cdev device library code is placed under the MIT license +Copyright (c) 2011 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. +=============================================== +*/ + +#ifndef _ADXL345_H_ +#define _ADXL345_H_ + +#include "I2Cdev.h" + +#define ADXL345_ADDRESS_ALT_LOW 0x53 // alt address pin low (GND) +#define ADXL345_ADDRESS_ALT_HIGH 0x1D // alt address pin high (VCC) +#define ADXL345_DEFAULT_ADDRESS ADXL345_ADDRESS_ALT_LOW + +#define ADXL345_RA_DEVID 0x00 +#define ADXL345_RA_RESERVED1 0x01 +#define ADXL345_RA_THRESH_TAP 0x1D +#define ADXL345_RA_OFSX 0x1E +#define ADXL345_RA_OFSY 0x1F +#define ADXL345_RA_OFSZ 0x20 +#define ADXL345_RA_DUR 0x21 +#define ADXL345_RA_LATENT 0x22 +#define ADXL345_RA_WINDOW 0x23 +#define ADXL345_RA_THRESH_ACT 0x24 +#define ADXL345_RA_THRESH_INACT 0x25 +#define ADXL345_RA_TIME_INACT 0x26 +#define ADXL345_RA_ACT_INACT_CTL 0x27 +#define ADXL345_RA_THRESH_FF 0x28 +#define ADXL345_RA_TIME_FF 0x29 +#define ADXL345_RA_TAP_AXES 0x2A +#define ADXL345_RA_ACT_TAP_STATUS 0x2B +#define ADXL345_RA_BW_RATE 0x2C +#define ADXL345_RA_POWER_CTL 0x2D +#define ADXL345_RA_INT_ENABLE 0x2E +#define ADXL345_RA_INT_MAP 0x2F +#define ADXL345_RA_INT_SOURCE 0x30 +#define ADXL345_RA_DATA_FORMAT 0x31 +#define ADXL345_RA_DATAX0 0x32 +#define ADXL345_RA_DATAX1 0x33 +#define ADXL345_RA_DATAY0 0x34 +#define ADXL345_RA_DATAY1 0x35 +#define ADXL345_RA_DATAZ0 0x36 +#define ADXL345_RA_DATAZ1 0x37 +#define ADXL345_RA_FIFO_CTL 0x38 +#define ADXL345_RA_FIFO_STATUS 0x39 + +#define ADXL345_AIC_ACT_AC_BIT 7 +#define ADXL345_AIC_ACT_X_BIT 6 +#define ADXL345_AIC_ACT_Y_BIT 5 +#define ADXL345_AIC_ACT_Z_BIT 4 +#define ADXL345_AIC_INACT_AC_BIT 3 +#define ADXL345_AIC_INACT_X_BIT 2 +#define ADXL345_AIC_INACT_Y_BIT 1 +#define ADXL345_AIC_INACT_Z_BIT 0 + +#define ADXL345_TAPAXIS_SUP_BIT 3 +#define ADXL345_TAPAXIS_X_BIT 2 +#define ADXL345_TAPAXIS_Y_BIT 1 +#define ADXL345_TAPAXIS_Z_BIT 0 + +#define ADXL345_TAPSTAT_ACTX_BIT 6 +#define ADXL345_TAPSTAT_ACTY_BIT 5 +#define ADXL345_TAPSTAT_ACTZ_BIT 4 +#define ADXL345_TAPSTAT_ASLEEP_BIT 3 +#define ADXL345_TAPSTAT_TAPX_BIT 2 +#define ADXL345_TAPSTAT_TAPY_BIT 1 +#define ADXL345_TAPSTAT_TAPZ_BIT 0 + +#define ADXL345_BW_LOWPOWER_BIT 4 +#define ADXL345_BW_RATE_BIT 3 +#define ADXL345_BW_RATE_LENGTH 4 + +#define ADXL345_RATE_3200 0b1111 +#define ADXL345_RATE_1600 0b1110 +#define ADXL345_RATE_800 0b1101 +#define ADXL345_RATE_400 0b1100 +#define ADXL345_RATE_200 0b1011 +#define ADXL345_RATE_100 0b1010 +#define ADXL345_RATE_50 0b1001 +#define ADXL345_RATE_25 0b1000 +#define ADXL345_RATE_12P5 0b0111 +#define ADXL345_RATE_6P25 0b0110 +#define ADXL345_RATE_3P13 0b0101 +#define ADXL345_RATE_1P56 0b0100 +#define ADXL345_RATE_0P78 0b0011 +#define ADXL345_RATE_0P39 0b0010 +#define ADXL345_RATE_0P20 0b0001 +#define ADXL345_RATE_0P10 0b0000 + +#define ADXL345_PCTL_LINK_BIT 5 +#define ADXL345_PCTL_AUTOSLEEP_BIT 4 +#define ADXL345_PCTL_MEASURE_BIT 3 +#define ADXL345_PCTL_SLEEP_BIT 2 +#define ADXL345_PCTL_WAKEUP_BIT 1 +#define ADXL345_PCTL_WAKEUP_LENGTH 2 + +#define ADXL345_WAKEUP_8HZ 0b00 +#define ADXL345_WAKEUP_4HZ 0b01 +#define ADXL345_WAKEUP_2HZ 0b10 +#define ADXL345_WAKEUP_1HZ 0b11 + +#define ADXL345_INT_DATA_READY_BIT 7 +#define ADXL345_INT_SINGLE_TAP_BIT 6 +#define ADXL345_INT_DOUBLE_TAP_BIT 5 +#define ADXL345_INT_ACTIVITY_BIT 4 +#define ADXL345_INT_INACTIVITY_BIT 3 +#define ADXL345_INT_FREE_FALL_BIT 2 +#define ADXL345_INT_WATERMARK_BIT 1 +#define ADXL345_INT_OVERRUN_BIT 0 + +#define ADXL345_FORMAT_SELFTEST_BIT 7 +#define ADXL345_FORMAT_SPIMODE_BIT 6 +#define ADXL345_FORMAT_INTMODE_BIT 5 +#define ADXL345_FORMAT_FULL_RES_BIT 3 +#define ADXL345_FORMAT_JUSTIFY_BIT 2 +#define ADXL345_FORMAT_RANGE_BIT 1 +#define ADXL345_FORMAT_RANGE_LENGTH 2 + +#define ADXL345_RANGE_2G 0b00 +#define ADXL345_RANGE_4G 0b01 +#define ADXL345_RANGE_8G 0b10 +#define ADXL345_RANGE_16G 0b11 + +#define ADXL345_FIFO_MODE_BIT 7 +#define ADXL345_FIFO_MODE_LENGTH 2 +#define ADXL345_FIFO_TRIGGER_BIT 5 +#define ADXL345_FIFO_SAMPLES_BIT 4 +#define ADXL345_FIFO_SAMPLES_LENGTH 5 + +#define ADXL345_FIFO_MODE_BYPASS 0b00 +#define ADXL345_FIFO_MODE_FIFO 0b01 +#define ADXL345_FIFO_MODE_STREAM 0b10 +#define ADXL345_FIFO_MODE_TRIGGER 0b11 + +#define ADXL345_FIFOSTAT_TRIGGER_BIT 7 +#define ADXL345_FIFOSTAT_LENGTH_BIT 5 +#define ADXL345_FIFOSTAT_LENGTH_LENGTH 6 + +class ADXL345 { + public: + ADXL345(); + ADXL345(uint8_t address); + + void initialize(); + bool testConnection(); + + // DEVID register + uint8_t getDeviceID(); + + // THRESH_TAP register + uint8_t getTapThreshold(); + void setTapThreshold(uint8_t threshold); + + // OFS* registers + void getOffset(int8_t* x, int8_t* y, int8_t* z); + void setOffset(int8_t x, int8_t y, int8_t z); + int8_t getOffsetX(); + void setOffsetX(int8_t x); + int8_t getOffsetY(); + void setOffsetY(int8_t y); + int8_t getOffsetZ(); + void setOffsetZ(int8_t z); + + // DUR register + uint8_t getTapDuration(); + void setTapDuration(uint8_t duration); + + // LATENT register + uint8_t getDoubleTapLatency(); + void setDoubleTapLatency(uint8_t latency); + + // WINDOW register + uint8_t getDoubleTapWindow(); + void setDoubleTapWindow(uint8_t window); + + // THRESH_ACT register + uint8_t getActivityThreshold(); + void setActivityThreshold(uint8_t threshold); + + // THRESH_INACT register + uint8_t getInactivityThreshold(); + void setInactivityThreshold(uint8_t threshold); + + // TIME_INACT register + uint8_t getInactivityTime(); + void setInactivityTime(uint8_t time); + + // ACT_INACT_CTL register + bool getActivityAC(); + void setActivityAC(bool enabled); + bool getActivityXEnabled(); + void setActivityXEnabled(bool enabled); + bool getActivityYEnabled(); + void setActivityYEnabled(bool enabled); + bool getActivityZEnabled(); + void setActivityZEnabled(bool enabled); + bool getInactivityAC(); + void setInactivityAC(bool enabled); + bool getInactivityXEnabled(); + void setInactivityXEnabled(bool enabled); + bool getInactivityYEnabled(); + void setInactivityYEnabled(bool enabled); + bool getInactivityZEnabled(); + void setInactivityZEnabled(bool enabled); + + // THRESH_FF register + uint8_t getFreefallThreshold(); + void setFreefallThreshold(uint8_t threshold); + + // TIME_FF register + uint8_t getFreefallTime(); + void setFreefallTime(uint8_t time); + + // TAP_AXES register + bool getTapAxisSuppress(); + void setTapAxisSuppress(bool enabled); + bool getTapAxisXEnabled(); + void setTapAxisXEnabled(bool enabled); + bool getTapAxisYEnabled(); + void setTapAxisYEnabled(bool enabled); + bool getTapAxisZEnabled(); + void setTapAxisZEnabled(bool enabled); + + // ACT_TAP_STATUS register + bool getActivitySourceX(); + bool getActivitySourceY(); + bool getActivitySourceZ(); + bool getAsleep(); + bool getTapSourceX(); + bool getTapSourceY(); + bool getTapSourceZ(); + + // BW_RATE register + bool getLowPowerEnabled(); + void setLowPowerEnabled(bool enabled); + uint8_t getRate(); + void setRate(uint8_t rate); + + // POWER_CTL register + bool getLinkEnabled(); + void setLinkEnabled(bool enabled); + bool getAutoSleepEnabled(); + void setAutoSleepEnabled(bool enabled); + bool getMeasureEnabled(); + void setMeasureEnabled(bool enabled); + bool getSleepEnabled(); + void setSleepEnabled(bool enabled); + uint8_t getWakeupFrequency(); + void setWakeupFrequency(uint8_t frequency); + + // INT_ENABLE register + bool getIntDataReadyEnabled(); + void setIntDataReadyEnabled(bool enabled); + bool getIntSingleTapEnabled(); + void setIntSingleTapEnabled(bool enabled); + bool getIntDoubleTapEnabled(); + void setIntDoubleTapEnabled(bool enabled); + bool getIntActivityEnabled(); + void setIntActivityEnabled(bool enabled); + bool getIntInactivityEnabled(); + void setIntInactivityEnabled(bool enabled); + bool getIntFreefallEnabled(); + void setIntFreefallEnabled(bool enabled); + bool getIntWatermarkEnabled(); + void setIntWatermarkEnabled(bool enabled); + bool getIntOverrunEnabled(); + void setIntOverrunEnabled(bool enabled); + + // INT_MAP register + uint8_t getIntDataReadyPin(); + void setIntDataReadyPin(uint8_t pin); + uint8_t getIntSingleTapPin(); + void setIntSingleTapPin(uint8_t pin); + uint8_t getIntDoubleTapPin(); + void setIntDoubleTapPin(uint8_t pin); + uint8_t getIntActivityPin(); + void setIntActivityPin(uint8_t pin); + uint8_t getIntInactivityPin(); + void setIntInactivityPin(uint8_t pin); + uint8_t getIntFreefallPin(); + void setIntFreefallPin(uint8_t pin); + uint8_t getIntWatermarkPin(); + void setIntWatermarkPin(uint8_t pin); + uint8_t getIntOverrunPin(); + void setIntOverrunPin(uint8_t pin); + + // INT_SOURCE register + uint8_t getIntDataReadySource(); + uint8_t getIntSingleTapSource(); + uint8_t getIntDoubleTapSource(); + uint8_t getIntActivitySource(); + uint8_t getIntInactivitySource(); + uint8_t getIntFreefallSource(); + uint8_t getIntWatermarkSource(); + uint8_t getIntOverrunSource(); + + // DATA_FORMAT register + uint8_t getSelfTestEnabled(); + void setSelfTestEnabled(uint8_t enabled); + uint8_t getSPIMode(); + void setSPIMode(uint8_t mode); + uint8_t getInterruptMode(); + void setInterruptMode(uint8_t mode); + uint8_t getFullResolution(); + void setFullResolution(uint8_t resolution); + uint8_t getDataJustification(); + void setDataJustification(uint8_t justification); + uint8_t getRange(); + void setRange(uint8_t range); + + // DATA* registers + void getAcceleration(int16_t* x, int16_t* y, int16_t* z); + int16_t getAccelerationX(); + int16_t getAccelerationY(); + int16_t getAccelerationZ(); + + // FIFO_CTL register + uint8_t getFIFOMode(); + void setFIFOMode(uint8_t mode); + uint8_t getFIFOTriggerInterruptPin(); + void setFIFOTriggerInterruptPin(uint8_t interrupt); + uint8_t getFIFOSamples(); + void setFIFOSamples(uint8_t size); + + // FIFO_STATUS register + bool getFIFOTriggerOccurred(); + uint8_t getFIFOLength(); + + private: + uint8_t devAddr; + uint8_t buffer[6]; +}; + +#endif /* _ADXL345_H_ */ diff --git a/Main/lib/I2Cdev/I2Cdev.cpp b/Main/lib/I2Cdev/I2Cdev.cpp new file mode 100644 index 0000000..892274b --- /dev/null +++ b/Main/lib/I2Cdev/I2Cdev.cpp @@ -0,0 +1,1488 @@ +// I2Cdev library collection - Main I2C device class +// Abstracts bit and byte I2C R/W functions into a convenient class +// 2013-06-05 by Jeff Rowberg +// +// Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument +// 2020-01-20 - hardija : complete support for Teensy 3.x +// 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 +// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications +// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan) +// 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) 2013 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 || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE + + #ifdef I2CDEV_IMPLEMENTATION_WARNINGS + #if ARDUINO < 100 + #warning Using outdated Arduino IDE with Wire library is functionally limiting. + #warning Arduino IDE v1.6.5+ 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.6.5+ 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.6.5+ 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 + // 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, void *wireObj) { + uint8_t b; + uint8_t count = readByte(devAddr, regAddr, &b, timeout, wireObj); + *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, void *wireObj) { + uint16_t b; + uint8_t count = readWord(devAddr, regAddr, &b, timeout, wireObj); + *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, void *wireObj) { + // 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, wireObj)) != 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, void *wireObj) { + // 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, wireObj)) != 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, void *wireObj) { + return readBytes(devAddr, regAddr, 1, data, timeout, wireObj); +} + +/** 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, void *wireObj) { + return readWords(devAddr, regAddr, 1, data, timeout, wireObj); +} + +/** 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, void *wireObj) { + #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 || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; + + #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 I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in + // smaller chunks instead of all at once + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->receive(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + } + + useWire->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 I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in + // smaller chunks instead of all at once + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + } + + useWire->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 I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in + // smaller chunks instead of all at once + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + } + } + #endif + + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + + // Fastwire library + // no loop required for fastwire + uint8_t status = Fastwire::readBuf(devAddr << 1, 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 (-1 indicates failure) + */ +int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout, void *wireObj) { + #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 || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; + + #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 I2CDEVLIB_WIRE_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, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + + bool msb = true; // starts with MSB, then LSB + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + if (msb) { + // first byte is bits 15-8 (MSb=15) + data[count] = useWire->receive() << 8; + } else { + // second byte is bits 7-0 (LSb=0) + data[count] |= useWire->receive(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + count++; + } + msb = !msb; + } + + useWire->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 I2CDEVLIB_WIRE_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, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + + bool msb = true; // starts with MSB, then LSB + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + if (msb) { + // first byte is bits 15-8 (MSb=15) + data[count] = useWire->read() << 8; + } else { + // second byte is bits 7-0 (LSb=0) + data[count] |= useWire->read(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + count++; + } + msb = !msb; + } + + useWire->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 I2CDEVLIB_WIRE_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, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + + bool msb = true; // starts with MSB, then LSB + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + if (msb) { + // first byte is bits 15-8 (MSb=15) + data[count] = useWire->read() << 8; + } else { + // second byte is bits 7-0 (LSb=0) + data[count] |= useWire->read(); + #ifdef I2CDEV_SERIAL_DEBUG + Serial.print(data[count], HEX); + if (count + 1 < length) Serial.print(" "); + #endif + count++; + } + msb = !msb; + } + + useWire->endTransmission(); + } + #endif + + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + + // Fastwire library + // no loop required for fastwire + uint8_t intermediate[(uint8_t)length*2]; + uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, 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, void *wireObj) { + uint8_t b; + readByte(devAddr, regAddr, &b, I2Cdev::readTimeout, wireObj); + b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); + return writeByte(devAddr, regAddr, b, wireObj); +} + +/** 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, void *wireObj) { + uint16_t w; + readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj); + w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum)); + return writeWord(devAddr, regAddr, w, wireObj); +} + +/** 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, void *wireObj) { + // 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, I2Cdev::readTimeout, wireObj) != 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, wireObj); + } 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, void *wireObj) { + // 010 value to write + // fedcba9876543210 bit numbers + // xxx args: bitStart=12, length=3 + // 0001110000000000 mask word + // 1010111110010110 original value (sample) + // 1010001110010110 original & ~mask + // 1010101110010110 masked | value + uint16_t w; + if (readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj) != 0) { + uint16_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, wireObj); + } 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, void *wireObj) { + return writeBytes(devAddr, regAddr, 1, &data, wireObj); +} + +/** 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, void *wireObj) { + return writeWords(devAddr, regAddr, 1, &data, wireObj); +} + +/** 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, void *wireObj) { + #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 || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) + useWire->beginTransmission(devAddr); + useWire->send((uint8_t) regAddr); // send address + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->beginTransmission(devAddr); + useWire->write((uint8_t) regAddr); // send address + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::beginTransmission(devAddr); + Fastwire::write(regAddr); + #endif + for (uint8_t i = 0; i < length; i++) { + #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) + useWire->send((uint8_t) data[i]); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->write((uint8_t) data[i]); + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::write((uint8_t) data[i]); + #endif + } + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) + useWire->endTransmission(); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + status = useWire->endTransmission(); + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::stop(); + //status = Fastwire::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, void *wireObj) { + #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 || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) + useWire->beginTransmission(devAddr); + useWire->send(regAddr); // send address + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->beginTransmission(devAddr); + useWire->write(regAddr); // send address + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::beginTransmission(devAddr); + Fastwire::write(regAddr); + #endif + for (uint8_t i = 0; i < length; i++) { + #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) + useWire->send((uint8_t)(data[i] >> 8)); // send MSB + useWire->send((uint8_t)data[i]); // send LSB + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->write((uint8_t)(data[i] >> 8)); // send MSB + useWire->write((uint8_t)data[i]); // send LSB + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::write((uint8_t)(data[i] >> 8)); // send MSB + status = Fastwire::write((uint8_t)data[i]); // send LSB + if (status != 0) break; + #endif + } + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) + useWire->endTransmission(); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + status = useWire->endTransmission(); + #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) + Fastwire::stop(); + //status = Fastwire::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 + // I2C library + ////////////////////// + // Copyright(C) 2012 + // Francesco Ferrara + // ferrara[at]libero[point]it + ////////////////////// + + /* + FastWire + - 0.24 added stop + - 0.23 added reset + + This is a library to help faster programs to read I2C devices. + Copyright(C) 2012 Francesco Ferrara + occhiobello at gmail dot com + [used by Jeff Rowberg for I2Cdevlib with permission] + */ + + 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 = F_CPU / 2000 / khz - 8; // change the I2C clock rate + TWCR = 1 << TWEN; // enable twi module, no interrupt + } + + // added by Jeff Rowberg 2013-05-07: + // Arduino Wire-style "beginTransmission" function + // (takes 7-bit device address like the Wire method, NOT 8-bit: 0x68, not 0xD0/0xD1) + byte Fastwire::beginTransmission(byte device) { + 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; + + //Serial.print(device, HEX); + //Serial.print(" "); + TWDR = device << 1; // 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; + return 0; + } + + byte Fastwire::writeBuf(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 1; + twst = TWSR & 0xF8; + if (twst != TW_START && twst != TW_REP_START) return 2; + + //Serial.print(device, HEX); + //Serial.print(" "); + 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; + + //Serial.print(address, HEX); + //Serial.print(" "); + 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; + + for (byte i = 0; i < num; i++) { + //Serial.print(data[i], HEX); + //Serial.print(" "); + TWDR = data[i]; // 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; + } + //Serial.print("\n"); + + return 0; + } + + byte Fastwire::write(byte value) { + byte twst; + //Serial.println(value, HEX); + TWDR = value; // send data + TWCR = (1 << TWINT) | (1 << TWEN); + if (!waitInt()) return 1; + twst = TWSR & 0xF8; + if (twst != TW_MT_DATA_ACK) return 2; + 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; + + //Serial.print(device, HEX); + //Serial.print(" "); + 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; + + //Serial.print(address, HEX); + //Serial.print(" "); + 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; + + //Serial.print(device, HEX); + //Serial.print(" "); + 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; + //Serial.print(data[i], HEX); + //Serial.print(" "); + } + //Serial.print("\n"); + stop(); + + return 0; + } + + void Fastwire::reset() { + TWCR = 0; + } + + byte Fastwire::stop() { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + if (!waitInt()) return 1; + return 0; + } +#endif + +#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE + // NBWire implementation based heavily on code by Gene Knight + // 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 = (1 << TWEN) | (1 << TWIE) | (1 << 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 = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << 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 = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); + } else { + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT); + } + } + + void twi_stop(void) { + // send stop condition + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWSTO); + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while (TWCR & (1 << TWSTO)) { + continue; + } + + // update twi state + twi_state = TWI_READY; + } + + void twi_releaseBus(void) { + // release bus + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << 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 diff --git a/Main/lib/I2Cdev/I2Cdev.h b/Main/lib/I2Cdev/I2Cdev.h new file mode 100644 index 0000000..5b59c56 --- /dev/null +++ b/Main/lib/I2Cdev/I2Cdev.h @@ -0,0 +1,311 @@ +// I2Cdev library collection - Main I2C device class header file +// Abstracts bit and byte I2C R/W functions into a convenient class +// 2013-06-05 by Jeff Rowberg +// +// Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument +// 2020-01-20 - hardija : complete support for Teensy 3.x +// 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 +// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications +// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan) +// 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) 2013 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. +=============================================== +*/ + +#ifndef _I2CDEV_H_ +#define _I2CDEV_H_ + +// ----------------------------------------------------------------------------- +// Enable deprecated pgmspace typedefs in avr-libc +// ----------------------------------------------------------------------------- +#define __PROG_TYPES_COMPAT__ + +// ----------------------------------------------------------------------------- +// I2C interface implementation setting +// ----------------------------------------------------------------------------- +#ifndef I2CDEV_IMPLEMENTATION +#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE +//#define I2CDEV_IMPLEMENTATION I2CDEV_TEENSY_3X_WIRE +//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE +//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE +#endif // I2CDEV_IMPLEMENTATION + +// comment this out if you are using a non-optimal IDE/implementation setting +// but want the compiler to shut up about it +#define I2CDEV_IMPLEMENTATION_WARNINGS + +// ----------------------------------------------------------------------------- +// I2C interface implementation options +// ----------------------------------------------------------------------------- +#define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino +#define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project + // ^^^ NBWire implementation is still buggy w/some interrupts! +#define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project +#define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library +#define I2CDEV_BUILTIN_SBWIRE 5 // I2C object from Shuning (Steve) Bian's SBWire Library at https://github.com/freespace/SBWire +#define I2CDEV_TEENSY_3X_WIRE 6 // Teensy 3.x support using i2c_t3 library + +// ----------------------------------------------------------------------------- +// Arduino-style "Serial.print" debug constant (uncomment to enable) +// ----------------------------------------------------------------------------- +//#define I2CDEV_SERIAL_DEBUG + +#ifdef ARDUINO + #if ARDUINO < 100 + #include "WProgram.h" + #else + #include "Arduino.h" + #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE + #include + #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + #include + #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY + #include + #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE + #include "SBWire.h" + #endif +#endif + +#ifdef SPARK + #include "application.h" + #define ARDUINO 101 + #define BUFFER_LENGTH 32 +#endif + +#ifndef I2CDEVLIB_WIRE_BUFFER_LENGTH + #if defined(I2C_BUFFER_LENGTH) + // Arduino ESP32 core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH I2C_BUFFER_LENGTH + #elif defined(BUFFER_LENGTH) + // Arduino AVR core Wire and many others use this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH BUFFER_LENGTH + #elif defined(SERIAL_BUFFER_SIZE) + // Arduino SAMD core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH SERIAL_BUFFER_SIZE + #else + // should be a safe fallback, though possibly inefficient + #define I2CDEVLIB_WIRE_BUFFER_LENGTH 32 + #endif +#endif + +// 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];") +#define I2CDEV_DEFAULT_READ_TIMEOUT 1000 + +class I2Cdev { + public: + I2Cdev(); + + static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + + static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj=0); + static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj=0); + static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj=0); + static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj=0); + static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj=0); + static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj=0); + static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, void *wireObj=0); + static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, void *wireObj=0); + + static uint16_t readTimeout; +}; + +#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE + ////////////////////// + // FastWire 0.24 + // This is a library to help faster programs to read I2C devices. + // Copyright(C) 2012 + // Francesco Ferrara + ////////////////////// + + /* Master */ + #define TW_START 0x08 + #define TW_REP_START 0x10 + + /* Master Transmitter */ + #define TW_MT_SLA_ACK 0x18 + #define TW_MT_SLA_NACK 0x20 + #define TW_MT_DATA_ACK 0x28 + #define TW_MT_DATA_NACK 0x30 + #define TW_MT_ARB_LOST 0x38 + + /* Master Receiver */ + #define TW_MR_ARB_LOST 0x38 + #define TW_MR_SLA_ACK 0x40 + #define TW_MR_SLA_NACK 0x48 + #define TW_MR_DATA_ACK 0x50 + #define TW_MR_DATA_NACK 0x58 + + #define TW_OK 0 + #define TW_ERROR 1 + + class Fastwire { + private: + static boolean waitInt(); + + public: + static void setup(int khz, boolean pullup); + static byte beginTransmission(byte device); + static byte write(byte value); + static byte writeBuf(byte device, byte address, byte *data, byte num); + static byte readBuf(byte device, byte address, byte *data, byte num); + static void reset(); + static byte stop(); + }; +#endif + +#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE + // NBWire implementation based heavily on code by Gene Knight + // 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 + + #define NBWIRE_BUFFER_LENGTH 32 + + class TwoWire { + private: + static uint8_t rxBuffer[]; + static uint8_t rxBufferIndex; + static uint8_t rxBufferLength; + + static uint8_t txAddress; + static uint8_t txBuffer[]; + static uint8_t txBufferIndex; + static uint8_t txBufferLength; + + // static uint8_t transmitting; + static void (*user_onRequest)(void); + static void (*user_onReceive)(int); + static void onRequestService(void); + static void onReceiveService(uint8_t*, int); + + public: + TwoWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void beginTransmission(uint8_t); + //void beginTransmission(int); + uint8_t endTransmission(uint16_t timeout=0); + void nbendTransmission(void (*function)(int)) ; + uint8_t requestFrom(uint8_t, int, uint16_t timeout=0); + //uint8_t requestFrom(int, int); + void nbrequestFrom(uint8_t, int, void (*function)(int)); + void send(uint8_t); + void send(uint8_t*, uint8_t); + //void send(int); + void send(char*); + uint8_t available(void); + uint8_t receive(void); + void onReceive(void (*)(int)); + void onRequest(void (*)(void)); + }; + + #define TWI_READY 0 + #define TWI_MRX 1 + #define TWI_MTX 2 + #define TWI_SRX 3 + #define TWI_STX 4 + + #define TW_WRITE 0 + #define TW_READ 1 + + #define TW_MT_SLA_NACK 0x20 + #define TW_MT_DATA_NACK 0x30 + + #define CPU_FREQ 16000000L + #define TWI_FREQ 100000L + #define TWI_BUFFER_LENGTH 32 + + /* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */ + + #define TW_STATUS_MASK ((1 << TWS7)|(1 << TWS6)|(1 << TWS5)|(1 << TWS4)|(1 << TWS3)) + #define TW_STATUS (TWSR & TW_STATUS_MASK) + #define TW_START 0x08 + #define TW_REP_START 0x10 + #define TW_MT_SLA_ACK 0x18 + #define TW_MT_SLA_NACK 0x20 + #define TW_MT_DATA_ACK 0x28 + #define TW_MT_DATA_NACK 0x30 + #define TW_MT_ARB_LOST 0x38 + #define TW_MR_ARB_LOST 0x38 + #define TW_MR_SLA_ACK 0x40 + #define TW_MR_SLA_NACK 0x48 + #define TW_MR_DATA_ACK 0x50 + #define TW_MR_DATA_NACK 0x58 + #define TW_ST_SLA_ACK 0xA8 + #define TW_ST_ARB_LOST_SLA_ACK 0xB0 + #define TW_ST_DATA_ACK 0xB8 + #define TW_ST_DATA_NACK 0xC0 + #define TW_ST_LAST_DATA 0xC8 + #define TW_SR_SLA_ACK 0x60 + #define TW_SR_ARB_LOST_SLA_ACK 0x68 + #define TW_SR_GCALL_ACK 0x70 + #define TW_SR_ARB_LOST_GCALL_ACK 0x78 + #define TW_SR_DATA_ACK 0x80 + #define TW_SR_DATA_NACK 0x88 + #define TW_SR_GCALL_DATA_ACK 0x90 + #define TW_SR_GCALL_DATA_NACK 0x98 + #define TW_SR_STOP 0xA0 + #define TW_NO_INFO 0xF8 + #define TW_BUS_ERROR 0x00 + + //#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr)) + //#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr)) + + #ifndef sbi // set bit + #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit)) + #endif // sbi + + #ifndef cbi // clear bit + #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit)) + #endif // cbi + + extern TwoWire Wire; + +#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE + +#endif /* _I2CDEV_H_ */ diff --git a/Main/lib/I2Cdev/keywords.txt b/Main/lib/I2Cdev/keywords.txt new file mode 100644 index 0000000..4132a06 --- /dev/null +++ b/Main/lib/I2Cdev/keywords.txt @@ -0,0 +1,38 @@ +####################################### +# Syntax Coloring Map For I2Cdev +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +I2Cdev KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +readBit KEYWORD2 +readBitW KEYWORD2 +readBits KEYWORD2 +readBitsW KEYWORD2 +readByte KEYWORD2 +readBytes KEYWORD2 +readWord KEYWORD2 +readWords KEYWORD2 +writeBit KEYWORD2 +writeBitW KEYWORD2 +writeBits KEYWORD2 +writeBitsW KEYWORD2 +writeByte KEYWORD2 +writeBytes KEYWORD2 +writeWord KEYWORD2 +writeWords KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/Main/lib/I2Cdev/library.json b/Main/lib/I2Cdev/library.json new file mode 100644 index 0000000..5c5eab8 --- /dev/null +++ b/Main/lib/I2Cdev/library.json @@ -0,0 +1,18 @@ +{ + "name": "I2Cdevlib-Core", + "keywords": "i2cdevlib, i2c", + "description": "The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices.", + "include": "Arduino/I2Cdev", + "repository": + { + "type": "git", + "url": "https://github.com/jrowberg/i2cdevlib.git" + }, + "frameworks": "arduino", + "platforms": "*", + "dependencies": [ + { + "name": "Wire" + } + ] +} diff --git a/Main/src/main.cpp b/Main/src/main.cpp index 1d598d2..4a16883 100644 --- a/Main/src/main.cpp +++ b/Main/src/main.cpp @@ -10,6 +10,9 @@ #include #include #include // forked from https://github.com/markrad/esp32-ADXL355 +#include +#include +#include #include #include "config.h" #include "secrets.h" // MQTT and Sensor information @@ -86,7 +89,7 @@ double time_since_NTP; double device_t; // -------------------------------------------------------------------------------------------- -// ADXL Accelerometer +// ADXL355 Accelerometer void IRAM_ATTR isr_adxl(); int32_t Adxl355SampleRate = 31; // Reporting Sample Rate [31,125] int8_t CHIP_SELECT_PIN_ADXL = 15; @@ -105,6 +108,10 @@ int QUE_len = LTA_len + STA_len; bool STALTAMODE = false; double TrueSampleRate; +// ADXL 345 Accelerometer +ADXL345 adxl345; +bool adxl345_flag = true; + // -------------------------------------------------------------------------------------------- // Variables to hold accelerometer data // 10 second FIFO queue for STA / LTA algorithm @@ -1349,7 +1356,19 @@ void setup() client.setServer(MQTT_HOST, MQTT_PORT); client.setCallback(messageReceived); + Wire.begin(); + adxl345.initialize(); + if (adxl345.testConnection()) + { + DEBUG("ADXL345 connection SUCCESSFUL!\n") + adxl345_flag = true; + adxl345.setRange(ADXL345_RANGE_2G); // sets +/- 2g range + } + else + { + adxl345_flag = false; + Serial.println("ADXL345 not connected!\n"); #if OPENEEW_SAMPLE_RATE_125 odr_lpf = Adxl355::ODR_LPF::ODR_125_AND_31_25; #endif @@ -1365,6 +1384,7 @@ void setup() spi1 = new SPIClass(HSPI); adxl355.initSPI(*spi1); StartADXL355(); + } ledcSetup(channel, freq, resolution); ledcAttachPin(io, channel); @@ -1401,16 +1421,35 @@ void loop() if (fifoFull) { fifoFull = false; - adxstatus = adxl355.getStatus(); - - if (adxstatus & Adxl355::STATUS_VALUES::FIFO_FULL) + if (!adxl345_flag) + { + adxstatus = adxl355.getStatus(); + } + + if ( (adxstatus & Adxl355::STATUS_VALUES::FIFO_FULL) || adxl345.getFIFOTriggerOccurred() ) { // Keep track of the heap in case heap fragmentation returns // Serial.println( xPortGetFreeHeapSize() ); - int numEntriesFifo = adxl355.readFifoEntries((long *)fifoOut); - // numEntriesFifo = numEntriesFifo-1; - + int numEntriesFifo; + if (!adxl345_flag) + { + numEntriesFifo = adxl355.readFifoEntries((long *)fifoOut); + } // numEntriesFifo = numEntriesFifo-1; + else + { + numEntriesFifo = adxl345.getFIFOLength(); + int16_t x_accel, y_accel, z_accel; + for (int i = 0; i < 32; i++) + { + adxl345.getAcceleration(&x_accel, &y_accel, &z_accel); + fifoOut[i][0] = x_accel; + fifoOut[i][1] = y_accel; + fifoOut[i][2] = z_accel; + } + DEBUG("Got adxl345 acceleration\n"); + } + if (numEntriesFifo != -1) { // Declare one AccelReading structure for this iteration of loop() diff --git a/Main/src/secrets.h b/Main/src/secrets.h index 4805cca..0e1108f 100644 --- a/Main/src/secrets.h +++ b/Main/src/secrets.h @@ -3,8 +3,8 @@ // ========= Add Station Infomation for this sensor =========================================== // This needs to be done for every sensor you flash char user[40] = "AMEIRA"; // add user code,eg JBIEBER -char network[2] = "GR"; // add 2 digit network code, eg GR -char station[5] = "GR002"; // add 5 digit station code, eg ST001 +char network[] = "GR"; // add 2 digit network code, eg GR +char station[] = "GR002"; // add 5 digit station code, eg ST001 // ========================== add your MQTT credentials =======================================