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