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}