001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj.counter;
006
007import edu.wpi.first.hal.CounterJNI;
008import edu.wpi.first.hal.FRCNetComm.tResourceType;
009import edu.wpi.first.hal.HAL;
010import edu.wpi.first.util.sendable.Sendable;
011import edu.wpi.first.util.sendable.SendableBuilder;
012import edu.wpi.first.util.sendable.SendableRegistry;
013import edu.wpi.first.wpilibj.DigitalSource;
014import java.nio.ByteBuffer;
015import java.nio.ByteOrder;
016
017/**
018 * Up Down Counter.
019 *
020 * <p>This class can count edges on a single digital input or count up based on an edge from one
021 * digital input and down on an edge from another digital input.
022 */
023public class UpDownCounter implements Sendable, AutoCloseable {
024  private final DigitalSource m_upSource;
025  private final DigitalSource m_downSource;
026
027  private final int m_handle;
028
029  /**
030   * Constructs a new UpDown Counter.
031   *
032   * @param upSource The up count source (can be null).
033   * @param downSource The down count source (can be null).
034   */
035  @SuppressWarnings("this-escape")
036  public UpDownCounter(DigitalSource upSource, DigitalSource downSource) {
037    ByteBuffer index = ByteBuffer.allocateDirect(4);
038    // set the byte order
039    index.order(ByteOrder.LITTLE_ENDIAN);
040    m_handle = CounterJNI.initializeCounter(CounterJNI.TWO_PULSE, index.asIntBuffer());
041
042    if (upSource != null) {
043      m_upSource = upSource;
044      CounterJNI.setCounterUpSource(
045          m_handle, upSource.getPortHandleForRouting(), upSource.getAnalogTriggerTypeForRouting());
046      CounterJNI.setCounterUpSourceEdge(m_handle, true, false);
047    } else {
048      m_upSource = null;
049    }
050
051    if (downSource != null) {
052      m_downSource = downSource;
053      CounterJNI.setCounterDownSource(
054          m_handle,
055          downSource.getPortHandleForRouting(),
056          downSource.getAnalogTriggerTypeForRouting());
057      CounterJNI.setCounterDownSourceEdge(m_handle, true, false);
058    } else {
059      m_downSource = null;
060    }
061
062    reset();
063
064    int intIndex = index.getInt();
065    HAL.report(tResourceType.kResourceType_Counter, intIndex + 1);
066    SendableRegistry.addLW(this, "UpDown Counter", intIndex);
067  }
068
069  @Override
070  public void close() {
071    SendableRegistry.remove(this);
072    CounterJNI.freeCounter(m_handle);
073    CounterJNI.suppressUnused(m_upSource);
074    CounterJNI.suppressUnused(m_downSource);
075  }
076
077  /**
078   * Sets the configuration for the up source.
079   *
080   * @param configuration The up source configuration.
081   */
082  public void setUpEdgeConfiguration(EdgeConfiguration configuration) {
083    CounterJNI.setCounterUpSourceEdge(m_handle, configuration.rising, configuration.falling);
084  }
085
086  /**
087   * Sets the configuration for the down source.
088   *
089   * @param configuration The down source configuration.
090   */
091  public void setDownEdgeConfiguration(EdgeConfiguration configuration) {
092    CounterJNI.setCounterDownSourceEdge(m_handle, configuration.rising, configuration.falling);
093  }
094
095  /** Resets the current count. */
096  public final void reset() {
097    CounterJNI.resetCounter(m_handle);
098  }
099
100  /**
101   * Sets to reverse the counter direction.
102   *
103   * @param reverseDirection True to reverse counting direction.
104   */
105  public void setReverseDirection(boolean reverseDirection) {
106    CounterJNI.setCounterReverseDirection(m_handle, reverseDirection);
107  }
108
109  /**
110   * Gets the current count.
111   *
112   * @return The current count.
113   */
114  public int getCount() {
115    return CounterJNI.getCounter(m_handle);
116  }
117
118  @Override
119  public void initSendable(SendableBuilder builder) {
120    builder.setSmartDashboardType("UpDown Counter");
121    builder.addDoubleProperty("Count", this::getCount, null);
122  }
123}