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}