001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import java.nio.ByteBuffer;
011import java.nio.ByteOrder;
012
013import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
014import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
015import edu.wpi.first.wpilibj.hal.HAL;
016import edu.wpi.first.wpilibj.interfaces.Accelerometer;
017import edu.wpi.first.wpilibj.livewindow.LiveWindow;
018import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
019import edu.wpi.first.wpilibj.tables.ITable;
020
021/**
022 * ADXL345 I2C Accelerometer.
023 */
024@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
025public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindowSendable {
026
027  private static final byte kAddress = 0x1D;
028  private static final byte kPowerCtlRegister = 0x2D;
029  private static final byte kDataFormatRegister = 0x31;
030  private static final byte kDataRegister = 0x32;
031  private static final double kGsPerLSB = 0.00390625;
032  private static final byte kPowerCtl_Link = 0x20;
033  private static final byte kPowerCtl_AutoSleep = 0x10;
034  private static final byte kPowerCtl_Measure = 0x08;
035  private static final byte kPowerCtl_Sleep = 0x04;
036
037  private static final byte kDataFormat_SelfTest = (byte) 0x80;
038  private static final byte kDataFormat_SPI = 0x40;
039  private static final byte kDataFormat_IntInvert = 0x20;
040  private static final byte kDataFormat_FullRes = 0x08;
041  private static final byte kDataFormat_Justify = 0x04;
042
043  public enum Axes {
044    kX((byte) 0x00),
045    kY((byte) 0x02),
046    kZ((byte) 0x04);
047
048    /**
049     * The integer value representing this enumeration.
050     */
051    @SuppressWarnings("MemberName")
052    public final byte value;
053
054    private Axes(byte value) {
055      this.value = value;
056    }
057  }
058
059  @SuppressWarnings("MemberName")
060  public static class AllAxes {
061
062    public double XAxis;
063    public double YAxis;
064    public double ZAxis;
065  }
066
067  protected I2C m_i2c;
068
069  /**
070   * Constructs the ADXL345 Accelerometer with I2C address 0x1D.
071   *
072   * @param port  The I2C port the accelerometer is attached to
073   * @param range The range (+ or -) that the accelerometer will measure.
074   */
075  public ADXL345_I2C(I2C.Port port, Range range) {
076    this(port, range, kAddress);
077  }
078
079  /**
080   * Constructs the ADXL345 Accelerometer over I2C.
081   *
082   * @param port          The I2C port the accelerometer is attached to
083   * @param range         The range (+ or -) that the accelerometer will measure.
084   * @param deviceAddress I2C address of the accelerometer (0x1D or 0x53)
085   */
086  public ADXL345_I2C(I2C.Port port, Range range, int deviceAddress) {
087    m_i2c = new I2C(port, deviceAddress);
088
089    // Turn on the measurements
090    m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure);
091
092    setRange(range);
093
094    HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_I2C);
095    LiveWindow.addSensor("ADXL345_I2C", port.value, this);
096  }
097
098
099  @Override
100  public void setRange(Range range) {
101    final byte value;
102
103    switch (range) {
104      case k2G:
105        value = 0;
106        break;
107      case k4G:
108        value = 1;
109        break;
110      case k8G:
111        value = 2;
112        break;
113      case k16G:
114        value = 3;
115        break;
116      default:
117        throw new IllegalArgumentException(range + " unsupported range type");
118    }
119
120    // Specify the data format to read
121    m_i2c.write(kDataFormatRegister, kDataFormat_FullRes | value);
122  }
123
124  @Override
125  public double getX() {
126    return getAcceleration(Axes.kX);
127  }
128
129  @Override
130  public double getY() {
131    return getAcceleration(Axes.kY);
132  }
133
134  @Override
135  public double getZ() {
136    return getAcceleration(Axes.kZ);
137  }
138
139  /**
140   * Get the acceleration of one axis in Gs.
141   *
142   * @param axis The axis to read from.
143   * @return Acceleration of the ADXL345 in Gs.
144   */
145  public double getAcceleration(Axes axis) {
146    ByteBuffer rawAccel = ByteBuffer.allocateDirect(2);
147    m_i2c.read(kDataRegister + axis.value, 2, rawAccel);
148
149    // Sensor is little endian... swap bytes
150    rawAccel.order(ByteOrder.LITTLE_ENDIAN);
151    return rawAccel.getShort(0) * kGsPerLSB;
152  }
153
154  /**
155   * Get the acceleration of all axes in Gs.
156   *
157   * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs.
158   */
159  public AllAxes getAccelerations() {
160    AllAxes data = new AllAxes();
161    ByteBuffer rawData = ByteBuffer.allocateDirect(6);
162    m_i2c.read(kDataRegister, 6, rawData);
163
164    // Sensor is little endian... swap bytes
165    rawData.order(ByteOrder.LITTLE_ENDIAN);
166    data.XAxis = rawData.getShort(0) * kGsPerLSB;
167    data.YAxis = rawData.getShort(2) * kGsPerLSB;
168    data.ZAxis = rawData.getShort(4) * kGsPerLSB;
169    return data;
170  }
171
172  @Override
173  public String getSmartDashboardType() {
174    return "3AxisAccelerometer";
175  }
176
177  private ITable m_table;
178
179  @Override
180  public void initTable(ITable subtable) {
181    m_table = subtable;
182    updateTable();
183  }
184
185  @Override
186  public void updateTable() {
187    if (m_table != null) {
188      m_table.putNumber("X", getX());
189      m_table.putNumber("Y", getY());
190      m_table.putNumber("Z", getZ());
191    }
192  }
193
194  @Override
195  public ITable getTable() {
196    return m_table;
197  }
198
199  @Override
200  public void startLiveWindowMode() {
201  }
202
203  @Override
204  public void stopLiveWindowMode() {
205  }
206}