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