001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2008-2012. 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/*----------------------------------------------------------------------------*/ 007package edu.wpi.first.wpilibj; 008 009import java.nio.ByteOrder; 010import java.nio.ByteBuffer; 011 012import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tInstances; 013import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType; 014import edu.wpi.first.wpilibj.communication.UsageReporting; 015import edu.wpi.first.wpilibj.interfaces.Accelerometer; 016import edu.wpi.first.wpilibj.livewindow.LiveWindow; 017import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable; 018import edu.wpi.first.wpilibj.tables.ITable; 019 020/** 021 * 022 * @author dtjones 023 * @author mwills 024 */ 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 static class Axes { 046 047 /** 048 * The integer value representing this enumeration 049 */ 050 public final byte value; 051 static final byte kX_val = 0x00; 052 static final byte kY_val = 0x02; 053 static final byte kZ_val = 0x04; 054 public static final ADXL345_SPI.Axes kX = new ADXL345_SPI.Axes(kX_val); 055 public static final ADXL345_SPI.Axes kY = new ADXL345_SPI.Axes(kY_val); 056 public static final ADXL345_SPI.Axes kZ = new ADXL345_SPI.Axes(kZ_val); 057 058 private Axes(byte value) { 059 this.value = value; 060 } 061 } 062 063 public static class AllAxes { 064 065 public double XAxis; 066 public double YAxis; 067 public double ZAxis; 068 } 069 070 private SPI m_spi; 071 072 /** 073 * Constructor. 074 * 075 * @param port The SPI port that the accelerometer is connected to 076 * @param range The range (+ or -) that the accelerometer will measure. 077 */ 078 public ADXL345_SPI(SPI.Port port, Range range) { 079 m_spi = new SPI(port); 080 init(range); 081 LiveWindow.addSensor("ADXL345_SPI", port.getValue(), this); 082 } 083 084 public void free(){ 085 m_spi.free(); 086 } 087 088 /** 089 * Set SPI bus parameters, bring device out of sleep and set format 090 * 091 * @param range The range (+ or -) that the accelerometer will measure. 092 */ 093 private void init(Range range){ 094 m_spi.setClockRate(500000); 095 m_spi.setMSBFirst(); 096 m_spi.setSampleDataOnFalling(); 097 m_spi.setClockActiveLow(); 098 m_spi.setChipSelectActiveHigh(); 099 100 // Turn on the measurements 101 byte[] commands = new byte[2]; 102 commands[0] = kPowerCtlRegister; 103 commands[1] = kPowerCtl_Measure; 104 m_spi.write(commands, 2); 105 106 setRange(range); 107 108 UsageReporting.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_SPI); 109 } 110 111 /** {inheritdoc} */ 112 @Override 113 public void setRange(Range range) { 114 byte value = 0; 115 116 switch(range) { 117 case k2G: 118 value = 0; 119 break; 120 case k4G: 121 value = 1; 122 break; 123 case k8G: 124 value = 2; 125 break; 126 case k16G: 127 value = 3; 128 break; 129 } 130 131 // Specify the data format to read 132 byte[] commands = new byte[]{ 133 kDataFormatRegister, 134 (byte)(kDataFormat_FullRes | value) 135 }; 136 m_spi.write(commands, commands.length); 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public double getX() { 142 return getAcceleration(Axes.kX); 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public double getY() { 148 return getAcceleration(Axes.kY); 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 public double getZ() { 154 return getAcceleration(Axes.kZ); 155 } 156 157 /** 158 * Get the acceleration of one axis in Gs. 159 * 160 * @param axis The axis to read from. 161 * @return Acceleration of the ADXL345 in Gs. 162 */ 163 public double getAcceleration(ADXL345_SPI.Axes axis) { 164 byte[] transferBuffer = new byte[3]; 165 transferBuffer[0] = (byte)((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value); 166 m_spi.transaction(transferBuffer, transferBuffer, 3); 167 ByteBuffer rawAccel = ByteBuffer.wrap(transferBuffer, 1, 2); 168 //Sensor is little endian 169 rawAccel.order(ByteOrder.LITTLE_ENDIAN); 170 171 return rawAccel.getShort() * kGsPerLSB; 172 } 173 174 /** 175 * Get the acceleration of all axes in Gs. 176 * 177 * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs. 178 */ 179 public ADXL345_SPI.AllAxes getAccelerations() { 180 ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes(); 181 byte dataBuffer[] = new byte[7]; 182 if (m_spi != null) 183 { 184 // Select the data address. 185 dataBuffer[0] = (byte)(kAddress_Read | kAddress_MultiByte | kDataRegister); 186 m_spi.transaction(dataBuffer, dataBuffer, 7); 187 ByteBuffer rawData = ByteBuffer.wrap(dataBuffer, 1, 6); 188 //Sensor is little endian... swap bytes 189 rawData.order(ByteOrder.LITTLE_ENDIAN); 190 191 data.XAxis = rawData.getShort() * kGsPerLSB; 192 data.YAxis = rawData.getShort() * kGsPerLSB; 193 data.ZAxis = rawData.getShort() * kGsPerLSB; 194 } 195 return data; 196 } 197 198 public String getSmartDashboardType(){ 199 return "3AxisAccelerometer"; 200 } 201 202 private ITable m_table; 203 204 /** {@inheritDoc} */ 205 public void initTable(ITable subtable) { 206 m_table = subtable; 207 updateTable(); 208 } 209 210 /** {@inheritDoc} */ 211 public void updateTable() { 212 if (m_table != null) { 213 m_table.putNumber("X", getX()); 214 m_table.putNumber("Y", getY()); 215 m_table.putNumber("Z", getZ()); 216 } 217 } 218 219 /** {@inheritDoc} */ 220 public ITable getTable(){ 221 return m_table; 222 } 223 224 public void startLiveWindowMode() {} 225 public void stopLiveWindowMode() {} 226}