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 008package edu.wpi.first.wpilibj; 009 010import java.nio.ByteBuffer; 011import java.nio.ByteOrder; 012 013import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType; 014import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType; 015import edu.wpi.first.wpilibj.communication.UsageReporting; 016import edu.wpi.first.wpilibj.hal.CounterJNI; 017import edu.wpi.first.wpilibj.hal.HALUtil; 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 for counting the number of ticks on a digital input channel. This is a 024 * general purpose class for counting repetitive events. It can return the 025 * number of counts, the period of the most recent cycle, and detect when the 026 * signal being counted has stopped by supplying a maximum cycle time. 027 * 028 * All counters will immediately start counting - reset() them if you need them 029 * to be zeroed before use. 030 */ 031public class Counter extends SensorBase implements CounterBase, 032 LiveWindowSendable, PIDSource { 033 034 /** 035 * Mode determines how and what the counter counts 036 */ 037 public static enum Mode { 038 /** 039 * mode: two pulse 040 */ 041 kTwoPulse(0), 042 /** 043 * mode: semi period 044 */ 045 kSemiperiod(1), 046 /** 047 * mode: pulse length 048 */ 049 kPulseLength(2), 050 /** 051 * mode: external direction 052 */ 053 kExternalDirection(3); 054 055 /** 056 * The integer value representing this enumeration 057 */ 058 public final int value; 059 private Mode(int value) { 060 this.value = value; 061 } 062 } 063 064 private DigitalSource m_upSource; // /< What makes the counter count up. 065 private DigitalSource m_downSource; // /< What makes the counter count down. 066 private boolean m_allocatedUpSource; 067 private boolean m_allocatedDownSource; 068 private ByteBuffer m_counter; // /< The FPGA counter object. 069 private int m_index; // /< The index of this counter. 070 private PIDSourceParameter m_pidSource; 071 private double m_distancePerPulse; // distance of travel for each tick 072 073 private void initCounter(final Mode mode) { 074 ByteBuffer status = ByteBuffer.allocateDirect(4); 075 // set the byte order 076 status.order(ByteOrder.LITTLE_ENDIAN); 077 ByteBuffer index = ByteBuffer.allocateDirect(4); 078 // set the byte order 079 index.order(ByteOrder.LITTLE_ENDIAN); 080 m_counter = CounterJNI.initializeCounter(mode.value, index.asIntBuffer(), status.asIntBuffer()); 081 HALUtil.checkStatus(status.asIntBuffer()); 082 m_index = index.asIntBuffer().get(0); 083 084 m_allocatedUpSource = false; 085 m_allocatedDownSource = false; 086 m_upSource = null; 087 m_downSource = null; 088 089 setMaxPeriod(.5); 090 091 UsageReporting.report(tResourceType.kResourceType_Counter, m_index, 092 mode.value); 093 } 094 095 /** 096 * Create an instance of a counter where no sources are selected. Then they 097 * all must be selected by calling functions to specify the upsource and the 098 * downsource independently. 099 * 100 * The counter will start counting immediately. 101 */ 102 public Counter() { 103 initCounter(Mode.kTwoPulse); 104 } 105 106 /** 107 * Create an instance of a counter from a Digital Input. This is used if an 108 * existing digital input is to be shared by multiple other objects such as 109 * encoders or if the Digital Source is not a DIO channel (such as an Analog Trigger) 110 * 111 * The counter will start counting immediately. 112 * 113 * @param source 114 * the digital source to count 115 */ 116 public Counter(DigitalSource source) { 117 if (source == null) 118 throw new NullPointerException("Digital Source given was null"); 119 initCounter(Mode.kTwoPulse); 120 setUpSource(source); 121 } 122 123 /** 124 * Create an instance of a Counter object. Create an up-Counter instance 125 * given a channel. 126 * 127 * The counter will start counting immediately. 128 * 129 * @param channel 130 * the DIO channel to use as the up source. 0-9 are on-board, 10-25 are on the MXP 131 */ 132 public Counter(int channel) { 133 initCounter(Mode.kTwoPulse); 134 setUpSource(channel); 135 } 136 137 /** 138 * Create an instance of a Counter object. Create an instance of a simple 139 * up-Counter given an analog trigger. Use the trigger state output from the 140 * analog trigger. 141 * 142 * The counter will start counting immediately. 143 * 144 * @param encodingType 145 * which edges to count 146 * @param upSource 147 * first source to count 148 * @param downSource 149 * second source for direction 150 * @param inverted 151 * true to invert the count 152 */ 153 public Counter(EncodingType encodingType, DigitalSource upSource, 154 DigitalSource downSource, boolean inverted) { 155 initCounter(Mode.kExternalDirection); 156 if (encodingType != EncodingType.k1X 157 && encodingType != EncodingType.k2X) { 158 throw new RuntimeException( 159 "Counters only support 1X and 2X quadreature decoding!"); 160 } 161 if (upSource == null) 162 throw new NullPointerException("Up Source given was null"); 163 setUpSource(upSource); 164 if (downSource == null) 165 throw new NullPointerException("Down Source given was null"); 166 setDownSource(downSource); 167 168 if (encodingType == null) 169 throw new NullPointerException("Encoding type given was null"); 170 171 ByteBuffer status = ByteBuffer.allocateDirect(4); 172 if (encodingType == EncodingType.k1X) { 173 setUpSourceEdge(true, false); 174 CounterJNI.setCounterAverageSize(m_counter, 1, status.asIntBuffer()); 175 } else { 176 setUpSourceEdge(true, true); 177 CounterJNI.setCounterAverageSize(m_counter, 2, status.asIntBuffer()); 178 } 179 180 HALUtil.checkStatus(status.asIntBuffer()); 181 setDownSourceEdge(inverted, true); 182 } 183 184 /** 185 * Create an instance of a Counter object. Create an instance of a simple 186 * up-Counter given an analog trigger. Use the trigger state output from the 187 * analog trigger. 188 * 189 * The counter will start counting immediately. 190 * 191 * @param trigger 192 * the analog trigger to count 193 */ 194 public Counter(AnalogTrigger trigger) { 195 if( trigger == null){ 196 throw new NullPointerException("The Analog Trigger given was null"); 197 } 198 initCounter(Mode.kTwoPulse); 199 setUpSource(trigger.createOutput(AnalogTriggerType.kState)); 200 } 201 202 @Override 203 public void free() { 204 setUpdateWhenEmpty(true); 205 206 clearUpSource(); 207 clearDownSource(); 208 209 ByteBuffer status = ByteBuffer.allocateDirect(4); 210 status.order(ByteOrder.LITTLE_ENDIAN); 211 CounterJNI.freeCounter(m_counter, status.asIntBuffer()); 212 HALUtil.checkStatus(status.asIntBuffer()); 213 214 m_upSource = null; 215 m_downSource = null; 216 m_counter = null; 217 } 218 219 /** 220 * @return the Counter's FPGA index 221 */ 222 public int getFPGAIndex() { 223 return m_index; 224 } 225 226 /** 227 * Set the upsource for the counter as a digital input channel. 228 * 229 * @param channel 230 * the DIO channel to count 0-9 are on-board, 10-25 are on the MXP 231 */ 232 public void setUpSource(int channel) { 233 setUpSource(new DigitalInput(channel)); 234 m_allocatedUpSource = true; 235 } 236 237 /** 238 * Set the source object that causes the counter to count up. Set the up 239 * counting DigitalSource. 240 * 241 * @param source 242 * the digital source to count 243 */ 244 public void setUpSource(DigitalSource source) { 245 if (m_upSource != null && m_allocatedUpSource) { 246 m_upSource.free(); 247 m_allocatedUpSource = false; 248 } 249 m_upSource = source; 250 ByteBuffer status = ByteBuffer.allocateDirect(4); 251 status.order(ByteOrder.LITTLE_ENDIAN); 252 CounterJNI.setCounterUpSource(m_counter, 253 source.getChannelForRouting(), 254 (byte) (source.getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer()); 255 HALUtil.checkStatus(status.asIntBuffer()); 256 } 257 258 /** 259 * Set the up counting source to be an analog trigger. 260 * 261 * @param analogTrigger 262 * The analog trigger object that is used for the Up Source 263 * @param triggerType 264 * The analog trigger output that will trigger the counter. 265 */ 266 public void setUpSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) { 267 if (analogTrigger == null){ 268 throw new NullPointerException("Analog Trigger given was null"); 269 } 270 if (triggerType == null){ 271 throw new NullPointerException("Analog Trigger Type given was null"); 272 } 273 setUpSource(analogTrigger.createOutput(triggerType)); 274 m_allocatedUpSource = true; 275 } 276 277 /** 278 * Set the edge sensitivity on an up counting source. Set the up source to 279 * either detect rising edges or falling edges. 280 * 281 * @param risingEdge 282 * true to count rising edge 283 * @param fallingEdge 284 * true to count falling edge 285 */ 286 public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) { 287 if (m_upSource == null) 288 throw new RuntimeException( 289 "Up Source must be set before setting the edge!"); 290 ByteBuffer status = ByteBuffer.allocateDirect(4); 291 status.order(ByteOrder.LITTLE_ENDIAN); 292 CounterJNI.setCounterUpSourceEdge(m_counter, 293 (byte) (risingEdge ? 1 : 0), (byte) (fallingEdge ? 1 : 0), 294 status.asIntBuffer()); 295 HALUtil.checkStatus(status.asIntBuffer()); 296 } 297 298 /** 299 * Disable the up counting source to the counter. 300 */ 301 public void clearUpSource() { 302 if (m_upSource != null && m_allocatedUpSource) { 303 m_upSource.free(); 304 m_allocatedUpSource = false; 305 } 306 m_upSource = null; 307 308 ByteBuffer status = ByteBuffer.allocateDirect(4); 309 status.order(ByteOrder.LITTLE_ENDIAN); 310 CounterJNI.clearCounterUpSource(m_counter, status.asIntBuffer()); 311 HALUtil.checkStatus(status.asIntBuffer()); 312 } 313 314 /** 315 * Set the down counting source to be a digital input channel. 316 * 317 * @param channel 318 * the DIO channel to count 0-9 are on-board, 10-25 are on the MXP 319 */ 320 public void setDownSource(int channel) { 321 setDownSource(new DigitalInput(channel)); 322 m_allocatedDownSource = true; 323 } 324 325 /** 326 * Set the source object that causes the counter to count down. Set the down 327 * counting DigitalSource. 328 * 329 * @param source 330 * the digital source to count 331 */ 332 public void setDownSource(DigitalSource source) { 333 if(source == null){ 334 throw new NullPointerException("The Digital Source given was null"); 335 } 336 337 if (m_downSource != null && m_allocatedDownSource) { 338 m_downSource.free(); 339 m_allocatedDownSource = false; 340 } 341 ByteBuffer status = ByteBuffer.allocateDirect(4); 342 status.order(ByteOrder.LITTLE_ENDIAN); 343 CounterJNI.setCounterDownSource(m_counter, 344 source.getChannelForRouting(), 345 (byte) (source.getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer()); 346 if (status.asIntBuffer().get(0) == HALUtil.PARAMETER_OUT_OF_RANGE) { 347 throw new IllegalArgumentException( 348 "Counter only supports DownSource in TwoPulse and ExternalDirection modes."); 349 } 350 HALUtil.checkStatus(status.asIntBuffer()); 351 m_downSource = source; 352 } 353 354 /** 355 * Set the down counting source to be an analog trigger. 356 * 357 * @param analogTrigger 358 * The analog trigger object that is used for the Down Source 359 * @param triggerType 360 * The analog trigger output that will trigger the counter. 361 */ 362 public void setDownSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) { 363 if (analogTrigger == null){ 364 throw new NullPointerException("Analog Trigger given was null"); 365 } 366 if (triggerType == null){ 367 throw new NullPointerException("Analog Trigger Type given was null"); 368 } 369 370 setDownSource(analogTrigger.createOutput(triggerType)); 371 m_allocatedDownSource = true; 372 } 373 374 /** 375 * Set the edge sensitivity on a down counting source. Set the down source 376 * to either detect rising edges or falling edges. 377 * 378 * @param risingEdge 379 * true to count the rising edge 380 * @param fallingEdge 381 * true to count the falling edge 382 */ 383 public void setDownSourceEdge(boolean risingEdge, boolean fallingEdge) { 384 if (m_downSource == null) 385 throw new RuntimeException( 386 " Down Source must be set before setting the edge!"); 387 ByteBuffer status = ByteBuffer.allocateDirect(4); 388 status.order(ByteOrder.LITTLE_ENDIAN); 389 CounterJNI.setCounterDownSourceEdge(m_counter, (byte) (risingEdge ? 1 390 : 0), (byte) (fallingEdge ? 1 : 0), status.asIntBuffer()); 391 HALUtil.checkStatus(status.asIntBuffer()); 392 } 393 394 /** 395 * Disable the down counting source to the counter. 396 */ 397 public void clearDownSource() { 398 if (m_downSource != null && m_allocatedDownSource) { 399 m_downSource.free(); 400 m_allocatedDownSource = false; 401 } 402 m_downSource = null; 403 404 ByteBuffer status = ByteBuffer.allocateDirect(4); 405 status.order(ByteOrder.LITTLE_ENDIAN); 406 CounterJNI.clearCounterDownSource(m_counter, status.asIntBuffer()); 407 HALUtil.checkStatus(status.asIntBuffer()); 408 } 409 410 /** 411 * Set standard up / down counting mode on this counter. Up and down counts 412 * are sourced independently from two inputs. 413 */ 414 public void setUpDownCounterMode() { 415 ByteBuffer status = ByteBuffer.allocateDirect(4); 416 status.order(ByteOrder.LITTLE_ENDIAN); 417 CounterJNI.setCounterUpDownMode(m_counter, status.asIntBuffer()); 418 HALUtil.checkStatus(status.asIntBuffer()); 419 } 420 421 /** 422 * Set external direction mode on this counter. Counts are sourced on the Up 423 * counter input. The Down counter input represents the direction to count. 424 */ 425 public void setExternalDirectionMode() { 426 ByteBuffer status = ByteBuffer.allocateDirect(4); 427 status.order(ByteOrder.LITTLE_ENDIAN); 428 CounterJNI.setCounterExternalDirectionMode(m_counter, status.asIntBuffer()); 429 HALUtil.checkStatus(status.asIntBuffer()); 430 } 431 432 /** 433 * Set Semi-period mode on this counter. Counts up on both rising and 434 * falling edges. 435 * 436 * @param highSemiPeriod 437 * true to count up on both rising and falling 438 */ 439 public void setSemiPeriodMode(boolean highSemiPeriod) { 440 ByteBuffer status = ByteBuffer.allocateDirect(4); 441 status.order(ByteOrder.LITTLE_ENDIAN); 442 CounterJNI.setCounterSemiPeriodMode(m_counter, 443 (byte) (highSemiPeriod ? 1 : 0), status.asIntBuffer()); 444 HALUtil.checkStatus(status.asIntBuffer()); 445 } 446 447 /** 448 * Configure the counter to count in up or down based on the length of the 449 * input pulse. This mode is most useful for direction sensitive gear tooth 450 * sensors. 451 * 452 * @param threshold 453 * The pulse length beyond which the counter counts the opposite 454 * direction. Units are seconds. 455 */ 456 public void setPulseLengthMode(double threshold) { 457 ByteBuffer status = ByteBuffer.allocateDirect(4); 458 status.order(ByteOrder.LITTLE_ENDIAN); 459 CounterJNI.setCounterPulseLengthMode(m_counter, threshold, 460 status.asIntBuffer()); 461 HALUtil.checkStatus(status.asIntBuffer()); 462 } 463 464 /** 465 * Read the current counter value. Read the value at this instant. It may 466 * still be running, so it reflects the current value. Next time it is read, 467 * it might have a different value. 468 */ 469 @Override 470 public int get() { 471 ByteBuffer status = ByteBuffer.allocateDirect(4); 472 status.order(ByteOrder.LITTLE_ENDIAN); 473 int value = CounterJNI.getCounter(m_counter, status.asIntBuffer()); 474 HALUtil.checkStatus(status.asIntBuffer()); 475 return value; 476 } 477 478 /** 479 * Read the current scaled counter value. Read the value at this instant, 480 * scaled by the distance per pulse (defaults to 1). 481 * 482 * @return The distance since the last reset 483 */ 484 public double getDistance() { 485 return get() * m_distancePerPulse; 486 } 487 488 /** 489 * Reset the Counter to zero. Set the counter value to zero. This doesn't 490 * effect the running state of the counter, just sets the current value to 491 * zero. 492 */ 493 @Override 494 public void reset() { 495 ByteBuffer status = ByteBuffer.allocateDirect(4); 496 status.order(ByteOrder.LITTLE_ENDIAN); 497 CounterJNI.resetCounter(m_counter, status.asIntBuffer()); 498 HALUtil.checkStatus(status.asIntBuffer()); 499 } 500 501 /** 502 * Set the maximum period where the device is still considered "moving". 503 * Sets the maximum period where the device is considered moving. This value 504 * is used to determine the "stopped" state of the counter using the 505 * GetStopped method. 506 * 507 * @param maxPeriod 508 * The maximum period where the counted device is considered 509 * moving in seconds. 510 */ 511 @Override 512 public void setMaxPeriod(double maxPeriod) { 513 ByteBuffer status = ByteBuffer.allocateDirect(4); 514 status.order(ByteOrder.LITTLE_ENDIAN); 515 CounterJNI.setCounterMaxPeriod(m_counter, maxPeriod, status.asIntBuffer()); 516 HALUtil.checkStatus(status.asIntBuffer()); 517 } 518 519 /** 520 * Select whether you want to continue updating the event timer output when 521 * there are no samples captured. The output of the event timer has a buffer 522 * of periods that are averaged and posted to a register on the FPGA. When 523 * the timer detects that the event source has stopped (based on the 524 * MaxPeriod) the buffer of samples to be averaged is emptied. If you enable 525 * the update when empty, you will be notified of the stopped source and the 526 * event time will report 0 samples. If you disable update when empty, the 527 * most recent average will remain on the output until a new sample is 528 * acquired. You will never see 0 samples output (except when there have 529 * been no events since an FPGA reset) and you will likely not see the 530 * stopped bit become true (since it is updated at the end of an average and 531 * there are no samples to average). 532 * 533 * @param enabled 534 * true to continue updating 535 */ 536 public void setUpdateWhenEmpty(boolean enabled) { 537 ByteBuffer status = ByteBuffer.allocateDirect(4); 538 status.order(ByteOrder.LITTLE_ENDIAN); 539 CounterJNI.setCounterUpdateWhenEmpty(m_counter, 540 (byte) (enabled ? 1 : 0), status.asIntBuffer()); 541 HALUtil.checkStatus(status.asIntBuffer()); 542 } 543 544 /** 545 * Determine if the clock is stopped. Determine if the clocked input is 546 * stopped based on the MaxPeriod value set using the SetMaxPeriod method. 547 * If the clock exceeds the MaxPeriod, then the device (and counter) are 548 * assumed to be stopped and it returns true. 549 * 550 * @return Returns true if the most recent counter period exceeds the 551 * MaxPeriod value set by SetMaxPeriod. 552 */ 553 @Override 554 public boolean getStopped() { 555 ByteBuffer status = ByteBuffer.allocateDirect(4); 556 status.order(ByteOrder.LITTLE_ENDIAN); 557 boolean value = CounterJNI.getCounterStopped(m_counter, status.asIntBuffer()) != 0; 558 HALUtil.checkStatus(status.asIntBuffer()); 559 return value; 560 } 561 562 /** 563 * The last direction the counter value changed. 564 * 565 * @return The last direction the counter value changed. 566 */ 567 @Override 568 public boolean getDirection() { 569 ByteBuffer status = ByteBuffer.allocateDirect(4); 570 status.order(ByteOrder.LITTLE_ENDIAN); 571 boolean value = CounterJNI.getCounterDirection(m_counter, status.asIntBuffer()) != 0; 572 HALUtil.checkStatus(status.asIntBuffer()); 573 return value; 574 } 575 576 /** 577 * Set the Counter to return reversed sensing on the direction. This allows 578 * counters to change the direction they are counting in the case of 1X and 579 * 2X quadrature encoding only. Any other counter mode isn't supported. 580 * 581 * @param reverseDirection 582 * true if the value counted should be negated. 583 */ 584 public void setReverseDirection(boolean reverseDirection) { 585 ByteBuffer status = ByteBuffer.allocateDirect(4); 586 status.order(ByteOrder.LITTLE_ENDIAN); 587 CounterJNI.setCounterReverseDirection(m_counter, 588 (byte) (reverseDirection ? 1 : 0), status.asIntBuffer()); 589 HALUtil.checkStatus(status.asIntBuffer()); 590 } 591 592 /** 593 * Get the Period of the most recent count. Returns the time interval of the 594 * most recent count. This can be used for velocity calculations to 595 * determine shaft speed. 596 * 597 * @return The period of the last two pulses in units of seconds. 598 */ 599 @Override 600 public double getPeriod() { 601 ByteBuffer status = ByteBuffer.allocateDirect(4); 602 status.order(ByteOrder.LITTLE_ENDIAN); 603 double value = CounterJNI.getCounterPeriod(m_counter, status.asIntBuffer()); 604 HALUtil.checkStatus(status.asIntBuffer()); 605 return value; 606 } 607 608 /** 609 * Get the current rate of the Counter. Read the current rate of the counter 610 * accounting for the distance per pulse value. The default value for 611 * distance per pulse (1) yields units of pulses per second. 612 * 613 * @return The rate in units/sec 614 */ 615 public double getRate() { 616 return m_distancePerPulse / getPeriod(); 617 } 618 619 /** 620 * Set the Samples to Average which specifies the number of samples of the 621 * timer to average when calculating the period. Perform averaging to 622 * account for mechanical imperfections or as oversampling to increase 623 * resolution. 624 * 625 * @param samplesToAverage 626 * The number of samples to average from 1 to 127. 627 */ 628 public void setSamplesToAverage(int samplesToAverage) { 629 ByteBuffer status = ByteBuffer.allocateDirect(4); 630 status.order(ByteOrder.LITTLE_ENDIAN); 631 CounterJNI.setCounterSamplesToAverage(m_counter, samplesToAverage, 632 status.asIntBuffer()); 633 if (status.asIntBuffer().get(0) == HALUtil.PARAMETER_OUT_OF_RANGE) { 634 throw new BoundaryException(BoundaryException.getMessage( 635 samplesToAverage, 1, 127)); 636 } 637 HALUtil.checkStatus(status.asIntBuffer()); 638 } 639 640 /** 641 * Get the Samples to Average which specifies the number of samples of the 642 * timer to average when calculating the period. Perform averaging to 643 * account for mechanical imperfections or as oversampling to increase 644 * resolution. 645 * 646 * @return SamplesToAverage The number of samples being averaged (from 1 to 647 * 127) 648 */ 649 public int getSamplesToAverage() { 650 ByteBuffer status = ByteBuffer.allocateDirect(4); 651 status.order(ByteOrder.LITTLE_ENDIAN); 652 int value = CounterJNI.getCounterSamplesToAverage(m_counter, status.asIntBuffer()); 653 HALUtil.checkStatus(status.asIntBuffer()); 654 return value; 655 } 656 657 /** 658 * Set the distance per pulse for this counter. This sets the multiplier 659 * used to determine the distance driven based on the count value from the 660 * encoder. Set this value based on the Pulses per Revolution and factor in 661 * any gearing reductions. This distance can be in any units you like, 662 * linear or angular. 663 * 664 * @param distancePerPulse 665 * The scale factor that will be used to convert pulses to useful 666 * units. 667 */ 668 public void setDistancePerPulse(double distancePerPulse) { 669 m_distancePerPulse = distancePerPulse; 670 } 671 672 /** 673 * Set which parameter of the encoder you are using as a process control 674 * variable. The counter class supports the rate and distance parameters. 675 * 676 * @param pidSource 677 * An enum to select the parameter. 678 */ 679 public void setPIDSourceParameter(PIDSourceParameter pidSource) { 680 if(pidSource == null){ 681 throw new NullPointerException("PID Source Parameter given was null"); 682 } 683 BoundaryException.assertWithinBounds(pidSource.value, 0, 1); 684 m_pidSource = pidSource; 685 } 686 687 @Override 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 @Override 703 public String getSmartDashboardType() { 704 return "Counter"; 705 } 706 707 private ITable m_table; 708 709 /** 710 * {@inheritDoc} 711 */ 712 @Override 713 public void initTable(ITable subtable) { 714 m_table = subtable; 715 updateTable(); 716 } 717 718 /** 719 * {@inheritDoc} 720 */ 721 @Override 722 public ITable getTable() { 723 return m_table; 724 } 725 726 /** 727 * {@inheritDoc} 728 */ 729 @Override 730 public void updateTable() { 731 if (m_table != null) { 732 m_table.putNumber("Value", get()); 733 } 734 } 735 736 /** 737 * {@inheritDoc} 738 */ 739 @Override 740 public void startLiveWindowMode() { 741 } 742 743 /** 744 * {@inheritDoc} 745 */ 746 @Override 747 public void stopLiveWindowMode() { 748 } 749}