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    /*----------------------------------------------------------------------------*/
007    package edu.wpi.first.wpilibj;
008    
009    
010    /**
011     *
012     * @author dtjones
013     * @author mwills
014     */
015    public class ADXL345_SPI extends SensorBase {
016        private static final int kPowerCtlRegister = 0x2D;
017        private static final int kDataFormatRegister = 0x31;
018        private static final int kDataRegister = 0x32;
019        private static final double kGsPerLSB = 0.00390625;
020        
021        private static final int kAddress_Read = 0x80;
022        private static final int kAddress_MultiByte = 0x40;
023        
024        private static final int kPowerCtl_Link=0x20;
025        private static final int kPowerCtl_AutoSleep=0x10;
026        private static final int kPowerCtl_Measure=0x08;
027        private static final int kPowerCtl_Sleep=0x04;
028        
029        private static final int kDataFormat_SelfTest=0x80;
030        private static final int kDataFormat_SPI=0x40;
031        private static final int kDataFormat_IntInvert=0x20;
032        private static final int kDataFormat_FullRes=0x08;
033        private static final int kDataFormat_Justify=0x04;
034            
035            
036        public static class DataFormat_Range {
037    
038            /**
039             * The integer value representing this enumeration
040             */
041            public final byte value;
042            static final byte k2G_val = 0x00;
043            static final byte k4G_val = 0x01;
044            static final byte k8G_val = 0x02;
045            static final byte k16G_val = 0x03;
046            public static final ADXL345_SPI.DataFormat_Range k2G = new ADXL345_SPI.DataFormat_Range(k2G_val);
047            public static final ADXL345_SPI.DataFormat_Range k4G = new ADXL345_SPI.DataFormat_Range(k4G_val);
048            public static final ADXL345_SPI.DataFormat_Range k8G = new ADXL345_SPI.DataFormat_Range(k8G_val);
049            public static final ADXL345_SPI.DataFormat_Range k16G = new ADXL345_SPI.DataFormat_Range(k16G_val);
050    
051            private DataFormat_Range(byte value) {
052                this.value = value;
053            }
054        }
055    
056        public static class Axes {
057    
058            /**
059             * The integer value representing this enumeration
060             */
061            public final byte value;
062            static final byte kX_val = 0x00;
063            static final byte kY_val = 0x02;
064            static final byte kZ_val = 0x04;
065            public static final ADXL345_SPI.Axes kX = new ADXL345_SPI.Axes(kX_val);
066            public static final ADXL345_SPI.Axes kY = new ADXL345_SPI.Axes(kY_val);
067            public static final ADXL345_SPI.Axes kZ = new ADXL345_SPI.Axes(kZ_val);
068    
069            private Axes(byte value) {
070                this.value = value;
071            }
072        }
073    
074        public static class AllAxes {
075    
076            public double XAxis;
077            public double YAxis;
078            public double ZAxis;
079        }
080        
081        private SPIDevice spi;
082        
083        /**
084         * Constructor. Use this when the device is the first/only device on the bus
085         *
086         * @param clk The clock channel
087         * @param mosi The mosi (output) channel
088         * @param miso The miso (input) channel
089         * @param cs The chip select channel
090         * @param range The range (+ or -) that the accelerometer will measure.
091         */
092        public ADXL345_SPI(DigitalOutput clk, DigitalOutput mosi, DigitalInput miso, DigitalOutput cs, ADXL345_SPI.DataFormat_Range range) {
093            spi = new SPIDevice(clk, mosi, miso, cs, SPIDevice.CS_ACTIVE_HIGH);
094            init(range);
095        }
096        
097        /**
098         * Constructor. Use this when the device is the first/only device on the bus
099         *
100         * @param slot The module of the digital IO for the device
101         * @param clkChannel The channel number for the clk channel
102         * @param mosiChannel The channel number for the mosi (output) channel
103         * @param misoChannel The channel number for the miso (input) channel
104         * @param csChannel The channel number for the chip select channel
105         * @param range The range (+ or -) that the accelerometer will measure.
106         */
107        public ADXL345_SPI(int slot, int clkChannel, int mosiChannel, int misoChannel, int csChannel, ADXL345_SPI.DataFormat_Range range) {
108            spi = new SPIDevice(slot, clkChannel, mosiChannel, misoChannel, csChannel, SPIDevice.CS_ACTIVE_HIGH);
109            init(range);
110        }
111    
112        /**
113         * Constructor. Use this constructor only if another SPI device has already
114         * been constructed with the clk, mosi and miso pins defined.
115         *
116         * @param cs the chip select line for the SPI bus
117         * @param range The range (+ or -) that the accelerometer will measure.
118         */
119        public ADXL345_SPI(DigitalOutput cs, ADXL345_SPI.DataFormat_Range range) {
120            spi = new SPIDevice(cs, SPIDevice.CS_ACTIVE_HIGH);
121            init(range);
122        }
123        
124        /**
125         * Constructor. Use this constructor only if another SPI device has already
126         * been constructed with the clk, mosi and miso pins defined.
127         *
128         * @param slot The module of the digital output for the device's chip select pin
129         * @param csChannel The channel for the digital output for the device's chip select pin
130         * @param range The range (+ or -) that the accelerometer will measure.
131         */
132        public ADXL345_SPI(int slot, int csChannel, ADXL345_SPI.DataFormat_Range range) {
133            spi = new SPIDevice(slot, csChannel, SPIDevice.CS_ACTIVE_HIGH);
134            init(range);
135        }
136        
137        public void free(){
138            spi.free();
139        }
140        
141        /**
142         * Set SPI bus parameters, bring device out of sleep and set format
143         * 
144         * @param range The range (+ or -) that the accelerometer will measure.
145         */
146        private void init(ADXL345_SPI.DataFormat_Range range){
147            spi.setBitOrder(SPIDevice.BIT_ORDER_MSB_FIRST);
148            spi.setClockPolarity(SPIDevice.CLOCK_POLARITY_ACTIVE_LOW);
149            spi.setDataOnTrailing(SPIDevice.DATA_ON_LEADING_EDGE);
150    
151            // Turn on the measurements
152            spi.transfer((kPowerCtlRegister << 8) | kPowerCtl_Measure, 16);
153            // Specify the data format to read
154            spi.transfer((kDataFormatRegister << 8) | kDataFormat_FullRes | range.value, 16);
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            long rawAccelLong = spi.transfer( ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value) << 16, 24);
165            return accelFromBytes(rawAccelLong);
166        }
167    
168        private double accelFromBytes(long value) {
169            // Sensor is little endian... swap bytes
170            short rawAccel = (short) (value&0xFF);
171            rawAccel <<= 8;
172            rawAccel |= ((value>>8)&0xFF);
173            return rawAccel * kGsPerLSB;
174        }
175    
176        /**
177         * Get the acceleration of all axes in Gs.
178         *
179         * @return Acceleration measured on all axes of the ADXL345 in Gs.
180         */
181        public ADXL345_SPI.AllAxes getAccelerations() {
182            ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
183            long[] rawData = spi.transfer(new long[]{kAddress_Read | kAddress_MultiByte | kDataRegister, 0, 0, 0}, new int[]{8, 16, 16, 16});
184    
185            data.XAxis = accelFromBytes(rawData[1]);
186            data.YAxis = accelFromBytes(rawData[2]);
187            data.ZAxis = accelFromBytes(rawData[3]);
188            return data;
189        }
190    }