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  public UpDownCounter(DigitalSource upSource, DigitalSource downSource) {
036    ByteBuffer index = ByteBuffer.allocateDirect(4);
037    // set the byte order
038    index.order(ByteOrder.LITTLE_ENDIAN);
039    m_handle = CounterJNI.initializeCounter(CounterJNI.TWO_PULSE, index.asIntBuffer());
040
041    if (upSource != null) {
042      m_upSource = upSource;
043      CounterJNI.setCounterUpSource(
044          m_handle, upSource.getPortHandleForRouting(), upSource.getAnalogTriggerTypeForRouting());
045      CounterJNI.setCounterUpSourceEdge(m_handle, true, false);
046    } else {
047      m_upSource = null;
048    }
049
050    if (downSource != null) {
051      m_downSource = downSource;
052      CounterJNI.setCounterDownSource(
053          m_handle,
054          downSource.getPortHandleForRouting(),
055          downSource.getAnalogTriggerTypeForRouting());
056      CounterJNI.setCounterDownSourceEdge(m_handle, true, false);
057    } else {
058      m_downSource = null;
059    }
060
061    reset();
062
063    int intIndex = index.getInt();
064    HAL.report(tResourceType.kResourceType_Counter, intIndex + 1);
065    SendableRegistry.addLW(this, "UpDown Counter", intIndex);
066  }
067
068  @Override
069  public void close() {
070    SendableRegistry.remove(this);
071    CounterJNI.freeCounter(m_handle);
072    CounterJNI.suppressUnused(m_upSource);
073    CounterJNI.suppressUnused(m_downSource);
074  }
075
076  /**
077   * Sets the configuration for the up source.
078   *
079   * @param configuration The up source configuration.
080   */
081  public void setUpEdgeConfiguration(EdgeConfiguration configuration) {
082    CounterJNI.setCounterUpSourceEdge(m_handle, configuration.rising, configuration.falling);
083  }
084
085  /**
086   * Sets the configuration for the down source.
087   *
088   * @param configuration The down source configuration.
089   */
090  public void setDownEdgeConfiguration(EdgeConfiguration configuration) {
091    CounterJNI.setCounterDownSourceEdge(m_handle, configuration.rising, configuration.falling);
092  }
093
094  /** Resets the current count. */
095  public void reset() {
096    CounterJNI.resetCounter(m_handle);
097  }
098
099  /**
100   * Sets to reverse the counter direction.
101   *
102   * @param reverseDirection True to reverse counting direction.
103   */
104  public void setReverseDirection(boolean reverseDirection) {
105    CounterJNI.setCounterReverseDirection(m_handle, reverseDirection);
106  }
107
108  /**
109   * Gets the current count.
110   *
111   * @return The current count.
112   */
113  public int getCount() {
114    return CounterJNI.getCounter(m_handle);
115  }
116
117  @Override
118  public void initSendable(SendableBuilder builder) {
119    builder.setSmartDashboardType("UpDown Counter");
120    builder.addDoubleProperty("Count", this::getCount, null);
121  }
122}