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 SPI Accelerometer. 023 */ 024@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"}) 025public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindowSendable { 026 private static final int kPowerCtlRegister = 0x2D; 027 private static final int kDataFormatRegister = 0x31; 028 private static final int kDataRegister = 0x32; 029 private static final double kGsPerLSB = 0.00390625; 030 031 private static final int kAddress_Read = 0x80; 032 private static final int kAddress_MultiByte = 0x40; 033 034 private static final int kPowerCtl_Link = 0x20; 035 private static final int kPowerCtl_AutoSleep = 0x10; 036 private static final int kPowerCtl_Measure = 0x08; 037 private static final int kPowerCtl_Sleep = 0x04; 038 039 private static final int kDataFormat_SelfTest = 0x80; 040 private static final int kDataFormat_SPI = 0x40; 041 private static final int kDataFormat_IntInvert = 0x20; 042 private static final int kDataFormat_FullRes = 0x08; 043 private static final int kDataFormat_Justify = 0x04; 044 045 public enum Axes { 046 kX((byte) 0x00), 047 kY((byte) 0x02), 048 kZ((byte) 0x04); 049 050 /** 051 * The integer value representing this enumeration. 052 */ 053 @SuppressWarnings("MemberName") 054 public final byte value; 055 056 private Axes(byte value) { 057 this.value = value; 058 } 059 } 060 061 @SuppressWarnings("MemberName") 062 public static class AllAxes { 063 064 public double XAxis; 065 public double YAxis; 066 public double ZAxis; 067 } 068 069 protected SPI m_spi; 070 071 /** 072 * Constructor. 073 * 074 * @param port The SPI port that the accelerometer is connected to 075 * @param range The range (+ or -) that the accelerometer will measure. 076 */ 077 public ADXL345_SPI(SPI.Port port, Range range) { 078 m_spi = new SPI(port); 079 init(range); 080 LiveWindow.addSensor("ADXL345_SPI", port.value, this); 081 } 082 083 public void free() { 084 m_spi.free(); 085 } 086 087 /** 088 * Set SPI bus parameters, bring device out of sleep and set format. 089 * 090 * @param range The range (+ or -) that the accelerometer will measure. 091 */ 092 private void init(Range range) { 093 m_spi.setClockRate(500000); 094 m_spi.setMSBFirst(); 095 m_spi.setSampleDataOnFalling(); 096 m_spi.setClockActiveLow(); 097 m_spi.setChipSelectActiveHigh(); 098 099 // Turn on the measurements 100 byte[] commands = new byte[2]; 101 commands[0] = kPowerCtlRegister; 102 commands[1] = kPowerCtl_Measure; 103 m_spi.write(commands, 2); 104 105 setRange(range); 106 107 HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_SPI); 108 } 109 110 @Override 111 public void setRange(Range range) { 112 final byte value; 113 114 switch (range) { 115 case k2G: 116 value = 0; 117 break; 118 case k4G: 119 value = 1; 120 break; 121 case k8G: 122 value = 2; 123 break; 124 case k16G: 125 value = 3; 126 break; 127 default: 128 throw new IllegalArgumentException(range + " unsupported"); 129 } 130 131 // Specify the data format to read 132 byte[] commands = new byte[]{kDataFormatRegister, (byte) (kDataFormat_FullRes | value)}; 133 m_spi.write(commands, commands.length); 134 } 135 136 @Override 137 public double getX() { 138 return getAcceleration(Axes.kX); 139 } 140 141 @Override 142 public double getY() { 143 return getAcceleration(Axes.kY); 144 } 145 146 @Override 147 public double getZ() { 148 return getAcceleration(Axes.kZ); 149 } 150 151 /** 152 * Get the acceleration of one axis in Gs. 153 * 154 * @param axis The axis to read from. 155 * @return Acceleration of the ADXL345 in Gs. 156 */ 157 public double getAcceleration(ADXL345_SPI.Axes axis) { 158 ByteBuffer transferBuffer = ByteBuffer.allocateDirect(3); 159 transferBuffer.put(0, 160 (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value)); 161 m_spi.transaction(transferBuffer, transferBuffer, 3); 162 // Sensor is little endian 163 transferBuffer.order(ByteOrder.LITTLE_ENDIAN); 164 165 return transferBuffer.getShort(1) * kGsPerLSB; 166 } 167 168 /** 169 * Get the acceleration of all axes in Gs. 170 * 171 * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs. 172 */ 173 public ADXL345_SPI.AllAxes getAccelerations() { 174 ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes(); 175 if (m_spi != null) { 176 ByteBuffer dataBuffer = ByteBuffer.allocateDirect(7); 177 // Select the data address. 178 dataBuffer.put(0, (byte) (kAddress_Read | kAddress_MultiByte | kDataRegister)); 179 m_spi.transaction(dataBuffer, dataBuffer, 7); 180 // Sensor is little endian... swap bytes 181 dataBuffer.order(ByteOrder.LITTLE_ENDIAN); 182 183 data.XAxis = dataBuffer.getShort(1) * kGsPerLSB; 184 data.YAxis = dataBuffer.getShort(3) * kGsPerLSB; 185 data.ZAxis = dataBuffer.getShort(5) * kGsPerLSB; 186 } 187 return data; 188 } 189 190 @Override 191 public String getSmartDashboardType() { 192 return "3AxisAccelerometer"; 193 } 194 195 private ITable m_table; 196 197 @Override 198 public void initTable(ITable subtable) { 199 m_table = subtable; 200 updateTable(); 201 } 202 203 @Override 204 public void updateTable() { 205 if (m_table != null) { 206 m_table.putNumber("X", getX()); 207 m_table.putNumber("Y", getY()); 208 m_table.putNumber("Z", getZ()); 209 } 210 } 211 212 @Override 213 public ITable getTable() { 214 return m_table; 215 } 216 217 @Override 218 public void startLiveWindowMode() { 219 } 220 221 @Override 222 public void stopLiveWindowMode() { 223 } 224}