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.math.filter;
006
007import edu.wpi.first.math.MathSharedStore;
008
009/**
010 * A simple debounce filter for boolean streams. Requires that the boolean change value from
011 * baseline for a specified period of time before the filtered value changes.
012 */
013public class Debouncer {
014  /** Type of debouncing to perform. */
015  public enum DebounceType {
016    /** Rising edge. */
017    kRising,
018    /** Falling edge. */
019    kFalling,
020    /** Both rising and falling edges. */
021    kBoth
022  }
023
024  private double m_debounceTimeSeconds;
025  private DebounceType m_debounceType;
026  private boolean m_baseline;
027
028  private double m_prevTimeSeconds;
029
030  /**
031   * Creates a new Debouncer.
032   *
033   * @param debounceTime The number of seconds the value must change from baseline for the filtered
034   *     value to change.
035   * @param type Which type of state change the debouncing will be performed on.
036   */
037  public Debouncer(double debounceTime, DebounceType type) {
038    m_debounceTimeSeconds = debounceTime;
039    m_debounceType = type;
040
041    resetTimer();
042
043    m_baseline = m_debounceType == DebounceType.kFalling;
044  }
045
046  /**
047   * Creates a new Debouncer. Baseline value defaulted to "false."
048   *
049   * @param debounceTime The number of seconds the value must change from baseline for the filtered
050   *     value to change.
051   */
052  public Debouncer(double debounceTime) {
053    this(debounceTime, DebounceType.kRising);
054  }
055
056  private void resetTimer() {
057    m_prevTimeSeconds = MathSharedStore.getTimestamp();
058  }
059
060  private boolean hasElapsed() {
061    return MathSharedStore.getTimestamp() - m_prevTimeSeconds >= m_debounceTimeSeconds;
062  }
063
064  /**
065   * Applies the debouncer to the input stream.
066   *
067   * @param input The current value of the input stream.
068   * @return The debounced value of the input stream.
069   */
070  public boolean calculate(boolean input) {
071    if (input == m_baseline) {
072      resetTimer();
073    }
074
075    if (hasElapsed()) {
076      if (m_debounceType == DebounceType.kBoth) {
077        m_baseline = input;
078        resetTimer();
079      }
080      return input;
081    } else {
082      return m_baseline;
083    }
084  }
085
086  /**
087   * Sets the time to debounce.
088   *
089   * @param time The number of seconds the value must change from baseline for the filtered value to
090   *     change.
091   */
092  public void setDebounceTime(double time) {
093    m_debounceTimeSeconds = time;
094  }
095
096  /**
097   * Gets the time to debounce.
098   *
099   * @return The number of seconds the value must change from baseline for the filtered value to
100   *     change.
101   */
102  public double getDebounceTime() {
103    return m_debounceTimeSeconds;
104  }
105
106  /**
107   * Sets the debounce type.
108   *
109   * @param type Which type of state change the debouncing will be performed on.
110   */
111  public void setDebounceType(DebounceType type) {
112    m_debounceType = type;
113
114    m_baseline = m_debounceType == DebounceType.kFalling;
115  }
116
117  /**
118   * Gets the debounce type.
119   *
120   * @return Which type of state change the debouncing will be performed on.
121   */
122  public DebounceType getDebounceType() {
123    return m_debounceType;
124  }
125}