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.tEncoder;
011 import edu.wpi.first.wpilibj.livewindow.LiveWindow;
012 import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
013 import edu.wpi.first.wpilibj.parsing.ISensor;
014 import edu.wpi.first.wpilibj.tables.ITable;
015 import edu.wpi.first.wpilibj.util.AllocationException;
016 import edu.wpi.first.wpilibj.util.BoundaryException;
017 import edu.wpi.first.wpilibj.util.CheckedAllocationException;
018
019 /**
020 * Class to read quad encoders.
021 * Quadrature encoders are devices that count shaft rotation and can sense direction. The output of
022 * the QuadEncoder class is an integer that can count either up or down, and can go negative for
023 * reverse direction counting. When creating QuadEncoders, a direction is supplied that changes the
024 * sense of the output to make code more readable if the encoder is mounted such that forward movement
025 * generates negative values. Quadrature encoders have two digital outputs, an A Channel and a B Channel
026 * that are out of phase with each other to allow the FPGA to do direction sensing.
027 */
028 public class Encoder extends SensorBase implements CounterBase, PIDSource, ISensor, LiveWindowSendable {
029
030 static Resource quadEncoders = new Resource(tEncoder.kNumSystems);
031 /**
032 * The a source
033 */
034 protected DigitalSource m_aSource; // the A phase of the quad encoder
035 /**
036 * The b source
037 */
038 protected DigitalSource m_bSource; // the B phase of the quad encoder
039 /**
040 * The index source
041 */
042 protected DigitalSource m_indexSource = null; //Index on some encoders
043 private tEncoder m_encoder;
044 private int m_index;
045 private double m_distancePerPulse; // distance of travel for each encoder tick
046 private Counter m_counter; // Counter object for 1x and 2x encoding
047 private EncodingType m_encodingType = EncodingType.k4X;
048 private boolean m_allocatedA;
049 private boolean m_allocatedB;
050 private boolean m_allocatedI;
051 private PIDSourceParameter m_pidSource;
052
053 /**
054 * Common initialization code for Encoders.
055 * This code allocates resources for Encoders and is common to all constructors.
056 * @param reverseDirection If true, counts down instead of up (this is all relative)
057 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
058 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
059 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
060 * a counter object will be used and the returned value will either exactly match the spec'd count
061 * or be double (2x) the spec'd count.
062 */
063 private void initEncoder(boolean reverseDirection) {
064 switch (m_encodingType.value) {
065 case EncodingType.k4X_val:
066 try {
067 m_index = quadEncoders.allocate();
068 } catch (CheckedAllocationException e) {
069 throw new AllocationException("There are no encoders left to allocate");
070 }
071 m_encoder = new tEncoder(m_index);
072 m_encoder.writeConfig_ASource_Module(m_aSource.getModuleForRouting());
073 m_encoder.writeConfig_ASource_Channel(m_aSource.getChannelForRouting());
074 m_encoder.writeConfig_ASource_AnalogTrigger(m_aSource.getAnalogTriggerForRouting());
075 m_encoder.writeConfig_BSource_Module(m_bSource.getModuleForRouting());
076 m_encoder.writeConfig_BSource_Channel(m_bSource.getChannelForRouting());
077 m_encoder.writeConfig_BSource_AnalogTrigger(m_bSource.getAnalogTriggerForRouting());
078 m_encoder.strobeReset();
079 m_encoder.writeConfig_Reverse(reverseDirection);
080 m_encoder.writeTimerConfig_AverageSize(1);
081 if (m_indexSource != null) {
082 m_encoder.writeConfig_IndexSource_Module(m_indexSource.getModuleForRouting());
083 m_encoder.writeConfig_IndexSource_Channel(m_indexSource.getChannelForRouting());
084 m_encoder.writeConfig_IndexSource_AnalogTrigger(m_indexSource.getAnalogTriggerForRouting());
085 m_encoder.writeConfig_IndexActiveHigh(true);
086 }
087 m_counter = null;
088 break;
089 case EncodingType.k2X_val:
090 case EncodingType.k1X_val:
091 m_counter = new Counter(m_encodingType, m_aSource, m_bSource, reverseDirection);
092 break;
093 }
094 m_distancePerPulse = 1.0;
095
096 UsageReporting.report(UsageReporting.kResourceType_Encoder, m_index, m_encodingType.value);
097 LiveWindow.addSensor("Encoder", m_aSource.getModuleForRouting(), m_aSource.getChannelForRouting(), this);
098 }
099
100 /**
101 * Encoder constructor.
102 * Construct a Encoder given a and b modules and channels fully specified.
103 * @param aSlot The a channel digital input module.
104 * @param aChannel The a channel digital input channel.
105 * @param bSlot The b channel digital input module.
106 * @param bChannel The b channel digital input channel.
107 * @param reverseDirection represents the orientation of the encoder and inverts the output values
108 * if necessary so forward represents positive values.
109 */
110 public Encoder(final int aSlot, final int aChannel,
111 final int bSlot, final int bChannel,
112 boolean reverseDirection) {
113 m_allocatedA = true;
114 m_allocatedB = true;
115 m_allocatedI = false;
116 m_aSource = new DigitalInput(aSlot, aChannel);
117 m_bSource = new DigitalInput(bSlot, bChannel);
118 initEncoder(reverseDirection);
119 }
120
121 /**
122 * Encoder constructor.
123 * Construct a Encoder given a and b modules and channels fully specified.
124 * @param aSlot The a channel digital input module.
125 * @param aChannel The a channel digital input channel.
126 * @param bSlot The b channel digital input module.
127 * @param bChannel The b channel digital input channel.
128 */
129 public Encoder(final int aSlot, final int aChannel,
130 final int bSlot, final int bChannel) {
131 this(aSlot, aChannel, bSlot, bChannel, false);
132 }
133
134 /**
135 * Encoder constructor.
136 * Construct a Encoder given a and b modules and channels fully specified.
137 * @param aSlot The a channel digital input module.
138 * @param aChannel The a channel digital input channel.
139 * @param bSlot The b channel digital input module.
140 * @param bChannel The b channel digital input channel.
141 * @param reverseDirection represents the orientation of the encoder and inverts the output values
142 * if necessary so forward represents positive values.
143 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
144 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
145 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
146 * a counter object will be used and the returned value will either exactly match the spec'd count
147 * or be double (2x) the spec'd count.
148 */
149 public Encoder(final int aSlot, final int aChannel,
150 final int bSlot, final int bChannel,
151 boolean reverseDirection, final EncodingType encodingType) {
152 m_allocatedA = true;
153 m_allocatedB = true;
154 m_allocatedI = false;
155 m_aSource = new DigitalInput(aSlot, aChannel);
156 m_bSource = new DigitalInput(bSlot, bChannel);
157 if (encodingType == null)
158 throw new NullPointerException("Given encoding type was null");
159 m_encodingType = encodingType;
160 initEncoder(reverseDirection);
161 }
162
163 /**
164 * Encoder constructor.
165 * Construct a Encoder given a and b modules and channels fully specified.
166 * Using the index pulse forces 4x encoding.
167 * @param aSlot The a channel digital input module.
168 * @param aChannel The a channel digital input channel.
169 * @param bSlot The b channel digital input module.
170 * @param bChannel The b channel digital input channel.
171 * @param indexSlot The index channel digital input module.
172 * @param indexChannel The index channel digital input channel.
173 * @param reverseDirection represents the orientation of the encoder and inverts the output values
174 * if necessary so forward represents positive values.
175 */
176 public Encoder(final int aSlot, final int aChannel,
177 final int bSlot, final int bChannel, final int indexSlot,
178 final int indexChannel,
179 boolean reverseDirection) {
180 m_allocatedA = true;
181 m_allocatedB = true;
182 m_allocatedI = true;
183 m_aSource = new DigitalInput(aSlot, aChannel);
184 m_bSource = new DigitalInput(bSlot, bChannel);
185 m_indexSource = new DigitalInput(indexSlot, indexChannel);
186 initEncoder(reverseDirection);
187 }
188
189 /**
190 * Encoder constructor.
191 * Construct a Encoder given a and b modules and channels fully specified.
192 * Using the index pulse forces 4x encoding.
193 * @param aSlot The a channel digital input module.
194 * @param aChannel The a channel digital input channel.
195 * @param bSlot The b channel digital input module.
196 * @param bChannel The b channel digital input channel.
197 * @param indexSlot The index channel digital input module.
198 * @param indexChannel The index channel digital input channel.
199 */
200 public Encoder(final int aSlot, final int aChannel,
201 final int bSlot, final int bChannel, final int indexSlot,
202 final int indexChannel) {
203 this(aSlot, aChannel, bSlot, bChannel, indexSlot, indexChannel, false);
204 }
205
206 /**
207 * Encoder constructor.
208 * Construct a Encoder given a and b channels assuming the default module.
209 * @param aChannel The a channel digital input channel.
210 * @param bChannel The b channel digital input channel.
211 * @param reverseDirection represents the orientation of the encoder and inverts the output values
212 * if necessary so forward represents positive values.
213 */
214 public Encoder(final int aChannel, final int bChannel, boolean reverseDirection) {
215 m_allocatedA = true;
216 m_allocatedB = true;
217 m_allocatedI = false;
218 m_aSource = new DigitalInput(aChannel);
219 m_bSource = new DigitalInput(bChannel);
220 initEncoder(reverseDirection);
221 }
222
223 /**
224 * Encoder constructor.
225 * Construct a Encoder given a and b channels assuming the default module.
226 * @param aChannel The a channel digital input channel.
227 * @param bChannel The b channel digital input channel.
228 */
229 public Encoder(final int aChannel, final int bChannel) {
230 this(aChannel, bChannel, false);
231 }
232
233 /**
234 * Encoder constructor.
235 * Construct a Encoder given a and b channels assuming the default module.
236 * @param aChannel The a channel digital input channel.
237 * @param bChannel The b channel digital input channel.
238 * @param reverseDirection represents the orientation of the encoder and inverts the output values
239 * if necessary so forward represents positive values.
240 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
241 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
242 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
243 * a counter object will be used and the returned value will either exactly match the spec'd count
244 * or be double (2x) the spec'd count.
245 */
246 public Encoder(final int aChannel, final int bChannel, boolean reverseDirection, final EncodingType encodingType) {
247 m_allocatedA = true;
248 m_allocatedB = true;
249 m_allocatedI = false;
250 if (encodingType == null)
251 throw new NullPointerException("Given encoding type was null");
252 m_encodingType = encodingType;
253 m_aSource = new DigitalInput(aChannel);
254 m_bSource = new DigitalInput(bChannel);
255 initEncoder(reverseDirection);
256 }
257
258 /**
259 * Encoder constructor.
260 * Construct a Encoder given a and b channels assuming the default module.
261 * Using an index pulse forces 4x encoding
262 * @param aChannel The a channel digital input channel.
263 * @param bChannel The b channel digital input channel.
264 * @param indexChannel The index channel digital input channel.
265 * @param reverseDirection represents the orientation of the encoder and inverts the output values
266 * if necessary so forward represents positive values.
267 */
268 public Encoder(final int aChannel, final int bChannel, final int indexChannel, boolean reverseDirection) {
269 m_allocatedA = true;
270 m_allocatedB = true;
271 m_allocatedI = true;
272 m_aSource = new DigitalInput(aChannel);
273 m_bSource = new DigitalInput(bChannel);
274 m_indexSource = new DigitalInput(indexChannel);
275 initEncoder(reverseDirection);
276 }
277
278 /**
279 * Encoder constructor.
280 * Construct a Encoder given a and b channels assuming the default module.
281 * Using an index pulse forces 4x encoding
282 * @param aChannel The a channel digital input channel.
283 * @param bChannel The b channel digital input channel.
284 * @param indexChannel The index channel digital input channel.
285 */
286 public Encoder(final int aChannel, final int bChannel, final int indexChannel) {
287 this(aChannel, bChannel, indexChannel, false);
288 }
289
290 /**
291 * Encoder constructor.
292 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
293 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
294 * and assume that they already are counted.
295 * @param aSource The source that should be used for the a channel.
296 * @param bSource the source that should be used for the b channel.
297 * @param reverseDirection represents the orientation of the encoder and inverts the output values
298 * if necessary so forward represents positive values.
299 */
300 public Encoder(DigitalSource aSource, DigitalSource bSource, boolean reverseDirection) {
301 m_allocatedA = false;
302 m_allocatedB = false;
303 m_allocatedI = false;
304 if (aSource == null)
305 throw new NullPointerException("Digital Source A was null");
306 m_aSource = aSource;
307 if (bSource == null)
308 throw new NullPointerException("Digital Source B was null");
309 m_bSource = bSource;
310 initEncoder(reverseDirection);
311 }
312
313 /**
314 * Encoder constructor.
315 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
316 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
317 * and assume that they already are counted.
318 * @param aSource The source that should be used for the a channel.
319 * @param bSource the source that should be used for the b channel.
320 */
321 public Encoder(DigitalSource aSource, DigitalSource bSource) {
322 this(aSource, bSource, false);
323 }
324
325 /**
326 * Encoder constructor.
327 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
328 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
329 * and assume that they already are counted.
330 * @param aSource The source that should be used for the a channel.
331 * @param bSource the source that should be used for the b channel.
332 * @param reverseDirection represents the orientation of the encoder and inverts the output values
333 * if necessary so forward represents positive values.
334 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
335 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
336 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
337 * a counter object will be used and the returned value will either exactly match the spec'd count
338 * or be double (2x) the spec'd count.
339 */
340 public Encoder(DigitalSource aSource, DigitalSource bSource, boolean reverseDirection, final EncodingType encodingType) {
341 m_allocatedA = false;
342 m_allocatedB = false;
343 m_allocatedI = false;
344 if (encodingType == null)
345 throw new NullPointerException("Given encoding type was null");
346 m_encodingType = encodingType;
347 if (aSource == null)
348 throw new NullPointerException("Digital Source A was null");
349 m_aSource = aSource;
350 if (bSource == null)
351 throw new NullPointerException("Digital Source B was null");
352 m_aSource = aSource;
353 m_bSource = bSource;
354 initEncoder(reverseDirection);
355 }
356
357 /**
358 * Encoder constructor.
359 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
360 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
361 * and assume that they already are counted.
362 * @param aSource The source that should be used for the a channel.
363 * @param bSource the source that should be used for the b channel.
364 * @param indexSource the source that should be used for the index channel.
365 * @param reverseDirection represents the orientation of the encoder and inverts the output values
366 * if necessary so forward represents positive values.
367 */
368 public Encoder(DigitalSource aSource, DigitalSource bSource,
369 DigitalSource indexSource, boolean reverseDirection) {
370 m_allocatedA = false;
371 m_allocatedB = false;
372 m_allocatedI = false;
373 if (aSource == null)
374 throw new NullPointerException("Digital Source A was null");
375 m_aSource = aSource;
376 if (bSource == null)
377 throw new NullPointerException("Digital Source B was null");
378 m_aSource = aSource;
379 m_bSource = bSource;
380 m_indexSource = indexSource;
381 initEncoder(reverseDirection);
382 }
383
384 /**
385 * Encoder constructor.
386 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
387 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
388 * and assume that they already are counted.
389 * @param aSource The source that should be used for the a channel.
390 * @param bSource the source that should be used for the b channel.
391 * @param indexSource the source that should be used for the index channel.
392 */
393 public Encoder(DigitalSource aSource, DigitalSource bSource,
394 DigitalSource indexSource) {
395 this(aSource, bSource, indexSource, false);
396 }
397
398 public void free() {
399 if (m_aSource != null && m_allocatedA) {
400 m_aSource.free();
401 m_allocatedA = false;
402 }
403 if (m_bSource != null && m_allocatedB) {
404 m_bSource.free();
405 m_allocatedB = false;
406 }
407 if (m_indexSource != null && m_allocatedI) {
408 m_indexSource.free();
409 m_allocatedI = false;
410 }
411
412 m_aSource = null;
413 m_bSource = null;
414 m_indexSource = null;
415 if (m_counter != null) {
416 m_counter.free();
417 m_counter = null;
418 } else {
419 m_encoder.Release();
420 quadEncoders.free(m_index);
421 m_encoder = null;
422 }
423 }
424
425 /**
426 * Start the Encoder.
427 * Starts counting pulses on the Encoder device.
428 */
429 public void start() {
430 if (m_counter != null) {
431 m_counter.start();
432 } else {
433 m_encoder.writeConfig_Enable(true);
434 }
435 }
436
437 /**
438 * Stops counting pulses on the Encoder device. The value is not changed.
439 */
440 public void stop() {
441 if (m_counter != null) {
442 m_counter.stop();
443 } else {
444 m_encoder.writeConfig_Enable(false);
445 }
446 }
447
448 /**
449 * Gets the raw value from the encoder.
450 * The raw value is the actual count unscaled by the 1x, 2x, or 4x scale
451 * factor.
452 * @return Current raw count from the encoder
453 */
454 public int getRaw() {
455 int value;
456 if (m_counter != null) {
457 value = m_counter.get();
458 } else {
459 value = m_encoder.readOutput_Value();
460 }
461 return value;
462 }
463
464 /**
465 * Gets the current count.
466 * Returns the current count on the Encoder.
467 * This method compensates for the decoding type.
468 *
469 * @return Current count from the Encoder adjusted for the 1x, 2x, or 4x scale factor.
470 */
471 public int get() {
472 return (int) (getRaw() * decodingScaleFactor());
473 }
474
475 /**
476 * Reset the Encoder distance to zero.
477 * Resets the current count to zero on the encoder.
478 */
479 public void reset() {
480 if (m_counter != null) {
481 m_counter.reset();
482 } else {
483 m_encoder.strobeReset();
484 }
485 }
486
487 /**
488 * Returns the period of the most recent pulse.
489 * Returns the period of the most recent Encoder pulse in seconds.
490 * This method compensates for the decoding type.
491 *
492 * @deprecated Use getRate() in favor of this method. This returns unscaled periods and getRate() scales using value from setDistancePerPulse().
493 *
494 * @return Period in seconds of the most recent pulse.
495 */
496 public double getPeriod() {
497 double measuredPeriod;
498 if (m_counter != null) {
499 measuredPeriod = m_counter.getPeriod();
500 } else {
501 double value;
502 if (m_encoder.readTimerOutput_Stalled()) {
503 return Double.POSITIVE_INFINITY;
504 } else {
505 // output.Period is a fixed point number that counts by 2 (24 bits, 25 integer bits),
506 // but tEncoder.readTimerOutput_Period() handles integer shift already
507 value = (double)m_encoder.readTimerOutput_Period() / (double) m_encoder.readTimerOutput_Count();
508 }
509 measuredPeriod = value * 1.0e-6;
510 }
511 return measuredPeriod / decodingScaleFactor();
512 }
513
514 /**
515 * Sets the maximum period for stopped detection.
516 * Sets the value that represents the maximum period of the Encoder before it will assume
517 * that the attached device is stopped. This timeout allows users to determine if the wheels or
518 * other shaft has stopped rotating.
519 * This method compensates for the decoding type.
520 *
521 *
522 * @param maxPeriod The maximum time between rising and falling edges before the FPGA will
523 * report the device stopped. This is expressed in seconds.
524 */
525 public void setMaxPeriod(double maxPeriod) {
526 if (m_counter != null) {
527 m_counter.setMaxPeriod(maxPeriod * decodingScaleFactor());
528 } else {
529 m_encoder.writeTimerConfig_StallPeriod((int) (maxPeriod * 1.0e6 * decodingScaleFactor()));
530 }
531 }
532
533 /**
534 * Determine if the encoder is stopped.
535 * Using the MaxPeriod value, a boolean is returned that is true if the encoder is considered
536 * stopped and false if it is still moving. A stopped encoder is one where the most recent pulse
537 * width exceeds the MaxPeriod.
538 * @return True if the encoder is considered stopped.
539 */
540 public boolean getStopped() {
541 if (m_counter != null) {
542 return m_counter.getStopped();
543 } else {
544 boolean value = m_encoder.readTimerOutput_Stalled() != false;
545 return value;
546 }
547 }
548
549 /**
550 * The last direction the encoder value changed.
551 * @return The last direction the encoder value changed.
552 */
553 public boolean getDirection() {
554 if (m_counter != null) {
555 return m_counter.getDirection();
556 } else {
557 boolean value = m_encoder.readOutput_Direction();
558 return value;
559 }
560 }
561
562 /**
563 * The scale needed to convert a raw counter value into a number of encoder pulses.
564 */
565 private double decodingScaleFactor() {
566 switch (m_encodingType.value) {
567 case EncodingType.k1X_val:
568 return 1.0;
569 case EncodingType.k2X_val:
570 return 0.5;
571 case EncodingType.k4X_val:
572 return 0.25;
573 default:
574 //This is never reached, EncodingType enum limits values
575 return 0.0;
576 }
577 }
578
579 /**
580 * Get the distance the robot has driven since the last reset.
581 *
582 * @return The distance driven since the last reset as scaled by the value from setDistancePerPulse().
583 */
584 public double getDistance() {
585 return getRaw() * decodingScaleFactor() * m_distancePerPulse;
586 }
587
588 /**
589 * Get the current rate of the encoder.
590 * Units are distance per second as scaled by the value from setDistancePerPulse().
591 *
592 * @return The current rate of the encoder.
593 */
594 public double getRate() {
595 return m_distancePerPulse / getPeriod();
596 }
597
598 /**
599 * Set the minimum rate of the device before the hardware reports it stopped.
600 *
601 * @param minRate The minimum rate. The units are in distance per second as scaled by the value from setDistancePerPulse().
602 */
603 public void setMinRate(double minRate) {
604 setMaxPeriod(m_distancePerPulse / minRate);
605 }
606
607 /**
608 * Set the distance per pulse for this encoder.
609 * This sets the multiplier used to determine the distance driven based on the count value
610 * from the encoder.
611 * Do not include the decoding type in this scale. The library already compensates for the decoding type.
612 * Set this value based on the encoder's rated Pulses per Revolution and
613 * factor in gearing reductions following the encoder shaft.
614 * This distance can be in any units you like, linear or angular.
615 *
616 * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
617 */
618 public void setDistancePerPulse(double distancePerPulse) {
619 m_distancePerPulse = distancePerPulse;
620 }
621
622 /**
623 * Set the direction sensing for this encoder.
624 * This sets the direction sensing on the encoder so that it could count in the correct
625 * software direction regardless of the mounting.
626 * @param reverseDirection true if the encoder direction should be reversed
627 */
628 public void setReverseDirection(boolean reverseDirection) {
629 if (m_counter != null) {
630 m_counter.setReverseDirection(reverseDirection);
631 } else {
632 m_encoder.writeConfig_Reverse(reverseDirection);
633 }
634 }
635
636 /**
637 * Set the Samples to Average which specifies the number of samples of the timer to
638 * average when calculating the period. Perform averaging to account for
639 * mechanical imperfections or as oversampling to increase resolution.
640 * @param samplesToAverage The number of samples to average from 1 to 127.
641 */
642 public void setSamplesToAverage(int samplesToAverage)
643 {
644 BoundaryException.assertWithinBounds(samplesToAverage, 1, 127);
645 switch (m_encodingType.value) {
646 case EncodingType.k4X_val:
647 m_encoder.writeTimerConfig_AverageSize(samplesToAverage);
648 break;
649 case EncodingType.k1X_val:
650 case EncodingType.k2X_val:
651 m_counter.setSamplesToAverage(samplesToAverage);
652 }
653 }
654
655 /**
656 * Get the Samples to Average which specifies the number of samples of the timer to
657 * average when calculating the period. Perform averaging to account for
658 * mechanical imperfections or as oversampling to increase resolution.
659 * @return SamplesToAverage The number of samples being averaged (from 1 to 127)
660 */
661 public int getSamplesToAverage()
662 {
663 switch (m_encodingType.value) {
664 case EncodingType.k4X_val:
665 return m_encoder.readTimerConfig_AverageSize();
666 case EncodingType.k1X_val:
667 case EncodingType.k2X_val:
668 return m_counter.getSamplesToAverage();
669 }
670 return 1;
671 }
672
673 /**
674 * Set which parameter of the encoder you are using as a process control variable.
675 * The encoder class supports the rate and distance parameters.
676 * @param pidSource An enum to select the parameter.
677 */
678 public void setPIDSourceParameter(PIDSourceParameter pidSource) {
679 BoundaryException.assertWithinBounds(pidSource.value, 0, 1);
680 m_pidSource = pidSource;
681 }
682
683 /**
684 * Implement the PIDSource interface.
685 *
686 * @return The current value of the selected source parameter.
687 */
688 public double pidGet() {
689 switch (m_pidSource.value) {
690 case PIDSourceParameter.kDistance_val:
691 return getDistance();
692 case PIDSourceParameter.kRate_val:
693 return getRate();
694 default:
695 return 0.0;
696 }
697 }
698
699 /*
700 * Live Window code, only does anything if live window is activated.
701 */
702 public String getSmartDashboardType(){
703 switch(m_encodingType.value)
704 {
705 case EncodingType.k4X_val:
706 return "Quadrature Encoder";
707 default:
708 return "Encoder";
709 }
710 }
711 private ITable m_table;
712
713 /**
714 * {@inheritDoc}
715 */
716 public void initTable(ITable subtable) {
717 m_table = subtable;
718 updateTable();
719 }
720
721 /**
722 * {@inheritDoc}
723 */
724 public ITable getTable(){
725 return m_table;
726 }
727
728 /**
729 * {@inheritDoc}
730 */
731 public void updateTable() {
732 if (m_table != null) {
733 m_table.putNumber("Speed", getRate());
734 m_table.putNumber("Distance", getDistance());
735 m_table.putNumber("Distance per Tick", m_distancePerPulse);
736 }
737 }
738
739 /**
740 * {@inheritDoc}
741 */
742 public void startLiveWindowMode() {}
743
744 /**
745 * {@inheritDoc}
746 */
747 public void stopLiveWindowMode() {}
748 }