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    
008    package edu.wpi.first.wpilibj;
009    
010    import edu.wpi.first.wpilibj.fpga.tAI;
011    import edu.wpi.first.wpilibj.communication.AICalibration;
012    import edu.wpi.first.wpilibj.communication.ModulePresence;
013    
014    /**
015     * Analog Module class.
016     * Each module can independently sample its channels at a configurable rate.
017     * There is a 64-bit hardware accumulator associated with channel 1 on each module.
018     * The accumulator is attached to the output of the oversample and average engine so that the center
019     * value can be specified in higher resolution resulting in less error.
020     */
021    public class AnalogModule extends Module {
022    
023        /**
024         * The time base used by the module
025         */
026        public static final int kTimebase = 40000000;
027        /**
028         * The default number of Oversample bits to use
029         */
030        public static final int kDefaultOversampleBits = 0;
031        /**
032         * The default number of averaging bits to use
033         */
034        public static final int kDefaultAverageBits = 7;
035        /**
036         * The default sample rate
037         */
038        public static final double kDefaultSampleRate = 50000.0;
039        private tAI m_module;
040        private boolean m_sampleRateSet;
041        private long m_accumulatorOffset;
042        private int m_numChannelsToActivate;
043        private final Object syncRoot = new Object();
044    
045        /**
046         * Get an instance of an Analog Module.
047         *
048         * Singleton analog module creation where a module is allocated on the first use
049         * and the same module is returned on subsequent uses.
050         *
051         * @param moduleNumber The index of the analog module to get (1 or 2).
052         * @return The AnalogModule.
053         */
054        public static synchronized AnalogModule getInstance(final int moduleNumber) {
055            checkAnalogModule(moduleNumber);
056            return (AnalogModule) getModule(ModulePresence.ModuleType.kAnalog, moduleNumber);
057        }
058    
059        /**
060         * Create a new instance of an analog module.
061         *
062         * Create an instance of the analog module object. Initialize all the parameters
063         * to reasonable values on start.
064         * Setting a global value on an analog module can be done only once unless subsequent
065         * values are set the previously set value.
066         * Analog modules are a singleton, so the constructor is never called outside of this class.
067         *
068         * @param moduleNumber The index of the analog module to create (1 or 2).
069         */
070        protected AnalogModule(final int moduleNumber) {
071            super(ModulePresence.ModuleType.kAnalog, moduleNumber);
072    
073            m_module = new tAI(moduleNumber - 1);
074            setNumChannelsToActivate(SensorBase.kAnalogChannels);
075            setSampleRate(AnalogModule.kDefaultSampleRate);
076    
077            for (int i = 0; i < SensorBase.kAnalogChannels; i++) {
078                m_module.writeScanList(i, i);
079                setAverageBits(i + 1, kDefaultAverageBits);
080                setOversampleBits(i + 1, kDefaultOversampleBits);
081            }
082        }
083    
084        /**
085         * Set the sample rate on the module.
086         *
087         * This is a global setting for the module and effects all channels.
088         *
089         * @param samplesPerSecond
090         *            The number of samples per channel per second.
091         */
092        public void setSampleRate(final double samplesPerSecond) {
093            // TODO: This will change when variable size scan lists are implemented.
094            // TODO: Need float comparison with epsilon.
095            // wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
096            m_sampleRateSet = true;
097    
098            // Compute the convert rate
099            final int ticksPerSample = (int) ((double)AnalogModule.kTimebase / samplesPerSecond);
100            int ticksPerConversion = ticksPerSample / getNumChannelsToActivate();
101            // ticksPerConversion must be at least 80
102            // wpi_assert(ticksPerConversion >= 80);
103            if (ticksPerConversion < 80) {
104                ticksPerConversion = 80;
105            }
106    
107            // Atomically set the scan size and the convert rate so that the sample
108            // rate is constant
109            m_module.writeConfig_ScanSize(getNumChannelsToActivate());
110            m_module.writeConfig_ConvertRate(ticksPerConversion);
111    
112            // Indicate that the scan size has been committed to hardware.
113            setNumChannelsToActivate(0);
114        }
115    
116        /**
117         * Get the current sample rate on the module.
118         *
119         * This assumes one entry in the scan list. This is a global setting for the
120         * module and effects all channels.
121         *
122         * @return Sample rate.
123         */
124        public double getSampleRate() {
125            final long ticksPerConversion = m_module.readLoopTiming();
126            final long ticksPerSample = ticksPerConversion * getNumActiveChannels();
127    
128            return (double)AnalogModule.kTimebase / (double)ticksPerSample;
129        }
130    
131        /**
132         * Return the number of channels on the module in use.
133         *
134         * @return Active channels.
135         */
136        private int getNumActiveChannels() {
137            final int scanSize = m_module.readConfig_ScanSize();
138            return scanSize == 0 ? 8 : scanSize;
139        }
140    
141        /**
142         * Get the number of active channels.
143         *
144         * This is an internal function to allow the atomic update of both the
145         * number of active channels and the sample rate.
146         *
147         * When the number of channels changes, use the new value.  Otherwise,
148         * return the curent value.
149         *
150         * @return Value to write to the active channels field.
151         */
152        private int getNumChannelsToActivate() {
153            if (m_numChannelsToActivate == 0) {
154                return getNumActiveChannels();
155            }
156            return m_numChannelsToActivate;
157        }
158    
159        /**
160         * Set the number of active channels.
161         *
162         * Store the number of active channels to set.  Don't actually commit to hardware
163         * until SetSampleRate().
164         *
165         * @param channels Number of active channels.
166         */
167        private void setNumChannelsToActivate(final int channels) {
168            m_numChannelsToActivate = channels;
169        }
170    
171        /**
172         * Set the number of averaging bits.
173         *
174         * This sets the number of averaging bits. The actual number of averaged
175         * samples is 2**bits. The averaging is done automatically in the FPGA.
176         *
177         * @param channel
178         *            Analog channel to configure.
179         * @param bits
180         *            Number of bits to average.
181         */
182        public void setAverageBits(final int channel, final int bits) {
183            m_module.writeAverageBits(channel - 1, bits);
184        }
185    
186        /**
187         * Get the number of averaging bits.
188         *
189         * This gets the number of averaging bits from the FPGA. The actual number
190         * of averaged samples is 2**bits. The averaging is done automatically in
191         * the FPGA.
192         *
193         * @param channel Channel to address.
194         * @return Bits to average.
195         */
196        public int getAverageBits(final int channel) {
197            return m_module.readAverageBits(channel - 1);
198        }
199    
200        /**
201         * Set the number of oversample bits.
202         *
203         * This sets the number of oversample bits. The actual number of oversampled values is 2**bits.
204         * Use oversampling to improve the resolution of your measurements at the expense of sampling rate.
205         * The oversampling is done automatically in the FPGA.
206         *
207         * @param channel Analog channel to configure.
208         * @param bits Number of bits to oversample.
209         */
210        public void setOversampleBits(final int channel, final int bits) {
211            m_module.writeOversampleBits(channel - 1, bits);
212        }
213    
214        /**
215         * Get the number of oversample bits.
216         *
217         * This gets the number of oversample bits from the FPGA. The actual number
218         * of oversampled values is 2**bits. The oversampling is done automatically
219         * in the FPGA.
220         *
221         * @param channel Channel to address.
222         * @return Bits to oversample.
223         */
224        public int getOversampleBits(final int channel) {
225            return m_module.readOversampleBits(channel - 1);
226        }
227    
228        /**
229         * Get the raw analog value.
230         *
231         * Get the analog value as it is returned from the D/A converter.
232         *
233         * @param channel Channel number to read.
234         * @return Raw value.
235         */
236        public int getValue(final int channel) {
237            int value;
238            SensorBase.checkAnalogChannel(channel);
239    
240            synchronized (syncRoot) {
241                tAI.writeReadSelect_Channel(channel - 1);
242                tAI.writeReadSelect_Module(m_moduleNumber - 1);
243                tAI.writeReadSelect_Averaged(false);
244    
245                tAI.strobeLatchOutput();
246                value = tAI.readOutput();
247            }
248    
249            return (short) value;
250        }
251    
252        /**
253         * Get the raw averaged and oversampled value.
254         *
255         * @param channel Channel number to read.
256         * @return The averaged and oversampled raw value.
257         */
258        public int getAverageValue(final int channel) {
259            int value;
260            SensorBase.checkAnalogChannel(channel);
261    
262            synchronized (syncRoot) {
263                tAI.writeReadSelect_Channel(channel - 1);
264                tAI.writeReadSelect_Module(m_moduleNumber - 1);
265                tAI.writeReadSelect_Averaged(true);
266    
267                tAI.strobeLatchOutput();
268                value = tAI.readOutput();
269            }
270    
271            return value;
272        }
273    
274        /**
275         * Convert a voltage to a raw value for a specified channel.
276         *
277         * This process depends on the calibration of each channel, so the channel
278         * must be specified.
279         *
280         * @todo This assumes raw values. Oversampling not supported as is.
281         *
282         * @param channel
283         *            The channel to convert for.
284         * @param voltage
285         *            The voltage to convert.
286         * @return The raw value for the channel.
287         */
288        public int voltsToValue(final int channel, final double voltage) {
289            // wpi_assert(voltage >= -10.0 && voltage <= 10.0);
290            final long LSBWeight = getLSBWeight(channel);
291            final int offset = getOffset(channel);
292            final int value = (int) ((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
293    
294            return value;
295        }
296    
297        /**
298         * Get the voltage.
299         *
300         * Return the voltage from the A/D converter.
301         *
302         * @param channel The channel to read.
303         * @return The scaled voltage from the channel.
304         */
305        public double getVoltage(final int channel) {
306            final int value = getValue(channel);
307            final long LSBWeight = getLSBWeight(channel);
308            final int offset = getOffset(channel);
309            final double voltage = (LSBWeight * 1.0e-9 * value) - (offset * 1.0e-9);
310    
311            return voltage;
312        }
313    
314        /**
315         * Get the averaged voltage.
316         *
317         * Return the averaged voltage from the A/D converter.
318         *
319         * @param channel The channel to read.
320         * @return The scaled averaged and oversampled voltage from the channel.
321         */
322        public double getAverageVoltage(final int channel) {
323            final int value = getAverageValue(channel);
324            final long LSBWeight = getLSBWeight(channel);
325            final int offset = getOffset(channel);
326            final int oversampleBits = getOversampleBits(channel);
327            final double voltage = ((LSBWeight * 1.0e-9 * value) / (double)(1 << oversampleBits)) - (offset * 1.0e-9);
328    
329            return voltage;
330        }
331    
332        /**
333         * Get the LSB Weight portion of the calibration for a channel.
334         *
335         * @param channel The channel to get calibration data for.
336         * @return LSB Weight calibration point.
337         */
338        public long getLSBWeight(final int channel) {
339            // TODO: add scaling to make this worth while.
340           return AICalibration.getLSBWeight(m_module.getSystemIndex(), channel - 1);
341        }
342    
343        /**
344         * Get the Offset portion of the calibration for a channel.
345         *
346         * @param channel The channel to get calibration data for.
347         * @return Offset calibration point.
348         */
349        public int getOffset(final int channel) {
350            // TODO: add scaling to make this worth while.
351            // TODO: actually use this function.
352           return AICalibration.getOffset(m_module.getSystemIndex(), channel - 1);
353        }
354    }