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 import edu.wpi.first.wpilibj.communication.UsageReporting;
010 import edu.wpi.first.wpilibj.fpga.tAccumulator;
011 import edu.wpi.first.wpilibj.livewindow.LiveWindow;
012 import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
013 import edu.wpi.first.wpilibj.tables.ITable;
014 import edu.wpi.first.wpilibj.util.AllocationException;
015 import edu.wpi.first.wpilibj.util.CheckedAllocationException;
016
017 /**
018 * Analog channel class.
019 *
020 * Each analog channel is read from hardware as a 12-bit number representing -10V to 10V.
021 *
022 * Connected to each analog channel is an averaging and oversampling engine. This engine accumulates
023 * the specified ( by setAverageBits() and setOversampleBits() ) number of samples before returning a new
024 * value. This is not a sliding window average. The only difference between the oversampled samples and
025 * the averaged samples is that the oversampled samples are simply accumulated effectively increasing the
026 * resolution, while the averaged samples are divided by the number of samples to retain the resolution,
027 * but get more stable values.
028 */
029 public class AnalogChannel extends SensorBase implements PIDSource, LiveWindowSendable {
030
031 private static final int kAccumulatorSlot = 1;
032 private static Resource channels = new Resource(kAnalogModules * kAnalogChannels);
033 private int m_channel;
034 private int m_moduleNumber;
035 private AnalogModule m_module;
036 private static final int[] kAccumulatorChannels = {
037 1, 2
038 };
039 private tAccumulator m_accumulator;
040 private long m_accumulatorOffset;
041 private boolean m_shouldUseVoltageForPID;
042
043 /**
044 * Construct an analog channel on the default module.
045 *
046 * @param channel The channel number to represent.
047 */
048 public AnalogChannel(final int channel) {
049 this(getDefaultAnalogModule(), channel);
050 }
051
052 /**
053 * Construct an analog channel on a specified module.
054 *
055 * @param moduleNumber The digital module to use (1 or 2).
056 * @param channel The channel number to represent.
057 */
058 public AnalogChannel(final int moduleNumber, final int channel) {
059 m_shouldUseVoltageForPID = false;
060 checkAnalogModule(moduleNumber);
061 checkAnalogChannel(channel);
062 m_channel = channel;
063 m_moduleNumber = moduleNumber;
064 m_module = AnalogModule.getInstance(moduleNumber);
065 try {
066 channels.allocate((moduleNumber - 1) * kAnalogChannels + m_channel - 1);
067 } catch (CheckedAllocationException e) {
068 throw new AllocationException(
069 "Analog channel " + m_channel + " on module " + m_moduleNumber + " is already allocated");
070 }
071 if (channel == 1 || channel == 2) {
072 m_accumulator = new tAccumulator((byte) (channel - 1));
073 m_accumulatorOffset = 0;
074 } else {
075 m_accumulator = null;
076 }
077
078 LiveWindow.addSensor("Analog", moduleNumber, channel, this);
079 UsageReporting.report(UsageReporting.kResourceType_AnalogChannel, channel, m_moduleNumber-1);
080 }
081
082 /**
083 * Channel destructor.
084 */
085 public void free() {
086 channels.free(((m_moduleNumber - 1) * kAnalogChannels + m_channel - 1));
087 m_channel = 0;
088 m_moduleNumber = 0;
089 // m_accumulator.Release();
090 m_accumulator = null;
091 m_accumulatorOffset = 0;
092 }
093
094 /**
095 * Get the analog module that this channel is on.
096 * @return The AnalogModule that this channel is on.
097 */
098 public AnalogModule getModule() {
099 return m_module;
100 }
101
102 /**
103 * Get a sample straight from this channel on the module.
104 * The sample is a 12-bit value representing the -10V to 10V range of the A/D converter in the module.
105 * The units are in A/D converter codes. Use GetVoltage() to get the analog value in calibrated units.
106 * @return A sample straight from this channel on the module.
107 */
108 public int getValue() {
109 return m_module.getValue(m_channel);
110 }
111
112 /**
113 * Get a sample from the output of the oversample and average engine for this channel.
114 * The sample is 12-bit + the value configured in SetOversampleBits().
115 * The value configured in setAverageBits() will cause this value to be averaged 2**bits number of samples.
116 * This is not a sliding window. The sample will not change until 2**(OversamplBits + AverageBits) samples
117 * have been acquired from the module on this channel.
118 * Use getAverageVoltage() to get the analog value in calibrated units.
119 * @return A sample from the oversample and average engine for this channel.
120 */
121 public int getAverageValue() {
122 return m_module.getAverageValue(m_channel);
123
124 }
125
126 /**
127 * Get a scaled sample straight from this channel on the module.
128 * The value is scaled to units of Volts using the calibrated scaling data from getLSBWeight() and getOffset().
129 * @return A scaled sample straight from this channel on the module.
130 */
131 public double getVoltage() {
132 return m_module.getVoltage(m_channel);
133 }
134
135 /**
136 * Get a scaled sample from the output of the oversample and average engine for this channel.
137 * The value is scaled to units of Volts using the calibrated scaling data from getLSBWeight() and getOffset().
138 * Using oversampling will cause this value to be higher resolution, but it will update more slowly.
139 * Using averaging will cause this value to be more stable, but it will update more slowly.
140 * @return A scaled sample from the output of the oversample and average engine for this channel.
141 */
142 public double getAverageVoltage() {
143 return m_module.getAverageVoltage(m_channel);
144 }
145
146 /**
147 * Get the factory scaling least significant bit weight constant.
148 * The least significant bit weight constant for the channel that was calibrated in
149 * manufacturing and stored in an eeprom in the module.
150 *
151 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
152 *
153 * @return Least significant bit weight.
154 */
155 public long getLSBWeight() {
156 return m_module.getLSBWeight(m_channel);
157 }
158
159 /**
160 * Get the factory scaling offset constant.
161 * The offset constant for the channel that was calibrated in manufacturing and stored
162 * in an eeprom in the module.
163 *
164 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
165 *
166 * @return Offset constant.
167 */
168 public int getOffset() {
169 return m_module.getOffset(m_channel);
170 }
171
172 /**
173 * Get the channel number.
174 * @return The channel number.
175 */
176 public int getChannel() {
177 return m_channel;
178 }
179
180 /**
181 * Gets the number of the analog module this channel is on.
182 * @return The module number of the analog module this channel is on.
183 */
184 public int getModuleNumber() {
185 return m_module.getModuleNumber();
186 }
187
188 /**
189 * Set the number of averaging bits.
190 * This sets the number of averaging bits. The actual number of averaged samples is 2**bits.
191 * The averaging is done automatically in the FPGA.
192 *
193 * @param bits The number of averaging bits.
194 */
195 public void setAverageBits(final int bits) {
196 m_module.setAverageBits(m_channel, bits);
197 }
198
199 /**
200 * Get the number of averaging bits.
201 * This gets the number of averaging bits from the FPGA. The actual number of averaged samples is 2**bits.
202 * The averaging is done automatically in the FPGA.
203 *
204 * @return The number of averaging bits.
205 */
206 public int getAverageBits() {
207 return m_module.getAverageBits(m_channel);
208 }
209
210 /**
211 * Set the number of oversample bits.
212 * This sets the number of oversample bits. The actual number of oversampled values is
213 * 2**bits. The oversampling is done automatically in the FPGA.
214 *
215 * @param bits The number of oversample bits.
216 */
217 public void setOversampleBits(final int bits) {
218 m_module.setOversampleBits(m_channel, bits);
219 }
220
221 /**
222 * Get the number of oversample bits.
223 * This gets the number of oversample bits from the FPGA. The actual number of oversampled values is
224 * 2**bits. The oversampling is done automatically in the FPGA.
225 *
226 * @return The number of oversample bits.
227 */
228 public int getOversampleBits() {
229 return m_module.getOversampleBits(m_channel);
230 }
231
232 /**
233 * Initialize the accumulator.
234 */
235 public void initAccumulator() {
236 if (!isAccumulatorChannel()) {
237 throw new AllocationException(
238 "Accumulators are only available on slot " +
239 kAccumulatorSlot + " on channels " + kAccumulatorChannels[0] + "," + kAccumulatorChannels[1]);
240 }
241 m_accumulatorOffset = 0;
242 setAccumulatorCenter(0);
243 resetAccumulator();
244 }
245
246 /**
247 * Set an inital value for the accumulator.
248 *
249 * This will be added to all values returned to the user.
250 * @param initialValue The value that the accumulator should start from when reset.
251 */
252 public void setAccumulatorInitialValue(long initialValue) {
253 m_accumulatorOffset = initialValue;
254 }
255
256 /**
257 * Resets the accumulator to the initial value.
258 */
259 public void resetAccumulator() {
260 m_accumulator.strobeReset();
261 }
262
263 /**
264 * Set the center value of the accumulator.
265 *
266 * The center value is subtracted from each A/D value before it is added to the accumulator. This
267 * is used for the center value of devices like gyros and accelerometers to make integration work
268 * and to take the device offset into account when integrating.
269 *
270 * This center value is based on the output of the oversampled and averaged source from channel 1.
271 * Because of this, any non-zero oversample bits will affect the size of the value for this field.
272 */
273 public void setAccumulatorCenter(int center) {
274 m_accumulator.writeCenter(center);
275 }
276
277 /**
278 * Set the accumulator's deadband.
279 */
280 public void setAccumulatorDeadband(int deadband) {
281 m_accumulator.writeDeadband(deadband);
282 }
283
284 /**
285 * Read the accumulated value.
286 *
287 * Read the value that has been accumulating on channel 1.
288 * The accumulator is attached after the oversample and average engine.
289 *
290 * @return The 64-bit value accumulated since the last Reset().
291 */
292 public long getAccumulatorValue() {
293 long value = m_accumulator.readOutput_Value() + m_accumulatorOffset;
294 return value;
295 }
296
297 /**
298 * Read the number of accumulated values.
299 *
300 * Read the count of the accumulated values since the accumulator was last Reset().
301 *
302 * @return The number of times samples from the channel were accumulated.
303 */
304 public long getAccumulatorCount() {
305 long count = m_accumulator.readOutput_Count();
306 return count;
307 }
308
309 /**
310 * Read the accumulated value and the number of accumulated values atomically.
311 *
312 * This function reads the value and count from the FPGA atomically.
313 * This can be used for averaging.
314 *
315 * @param result AccumulatorResult object to store the results in.
316 */
317 public void getAccumulatorOutput(AccumulatorResult result) {
318 if (result == null) {
319 System.out.println("Null result in getAccumulatorOutput");
320 }
321 if (m_accumulator == null) {
322 System.out.println("Null m_accumulator in getAccumulatorOutput");
323 }
324 result.value = m_accumulator.readOutput_Value() + m_accumulatorOffset;
325 result.count = m_accumulator.readOutput_Count();
326 }
327
328 /**
329 * Is the channel attached to an accumulator.
330 *
331 * @return The analog channel is attached to an accumulator.
332 */
333 public boolean isAccumulatorChannel() {
334 if (m_module.getModuleNumber() != kAccumulatorSlot) {
335 return false;
336 }
337 for (int i = 0; i < kAccumulatorChannels.length; i++) {
338 if (m_channel == kAccumulatorChannels[i]) {
339 return true;
340 }
341 }
342 return false;
343 }
344
345 /**
346 * Set whether to use voltage of value for PIDGet
347 * This method determines whether PIDGet uses average voltage or value for
348 * PID controllers for a particular channel. This is to preserve compatibility
349 * with existing programs and is likely to change in favor of voltage for
350 * RoboRIO.
351 * @param m_shouldUseVoltageForPID True if voltage should be used for PIDGet. The
352 * default is to use the value as it has been since the creation of the library.
353 */
354 public void setVoltageForPID(boolean shouldUseVoltageForPID) {
355 m_shouldUseVoltageForPID = shouldUseVoltageForPID;
356 }
357
358 /**
359 * Get the average value for use with PIDController.
360 * This can be changed to use average voltage by calling setVoltageForPID().
361 * @return the average value
362 */
363 public double pidGet() {
364 if (m_shouldUseVoltageForPID) {
365 return getAverageVoltage();
366 }
367 else {
368 return getAverageValue();
369 }
370 }
371
372 /*
373 * Live Window code, only does anything if live window is activated.
374 */
375 public String getSmartDashboardType(){
376 return "Analog Input";
377 }
378 private ITable m_table;
379
380 /**
381 * {@inheritDoc}
382 */
383 public void initTable(ITable subtable) {
384 m_table = subtable;
385 updateTable();
386 }
387
388 /**
389 * {@inheritDoc}
390 */
391 public void updateTable() {
392 if (m_table != null) {
393 m_table.putNumber("Value", getAverageVoltage());
394 }
395 }
396
397 /**
398 * {@inheritDoc}
399 */
400 public ITable getTable(){
401 return m_table;
402 }
403
404 /**
405 * Analog Channels don't have to do anything special when entering the LiveWindow.
406 * {@inheritDoc}
407 */
408 public void startLiveWindowMode() {}
409
410 /**
411 * Analog Channels don't have to do anything special when exiting the LiveWindow.
412 * {@inheritDoc}
413 */
414 public void stopLiveWindowMode() {}
415 }