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 final double m_debounceTimeSeconds;
025  private final 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 =
044        switch (m_debounceType) {
045          case kBoth, kRising -> false;
046          case kFalling -> true;
047        };
048  }
049
050  /**
051   * Creates a new Debouncer. Baseline value defaulted to "false."
052   *
053   * @param debounceTime The number of seconds the value must change from baseline for the filtered
054   *     value to change.
055   */
056  public Debouncer(double debounceTime) {
057    this(debounceTime, DebounceType.kRising);
058  }
059
060  private void resetTimer() {
061    m_prevTimeSeconds = MathSharedStore.getTimestamp();
062  }
063
064  private boolean hasElapsed() {
065    return MathSharedStore.getTimestamp() - m_prevTimeSeconds >= m_debounceTimeSeconds;
066  }
067
068  /**
069   * Applies the debouncer to the input stream.
070   *
071   * @param input The current value of the input stream.
072   * @return The debounced value of the input stream.
073   */
074  public boolean calculate(boolean input) {
075    if (input == m_baseline) {
076      resetTimer();
077    }
078
079    if (hasElapsed()) {
080      if (m_debounceType == DebounceType.kBoth) {
081        m_baseline = input;
082        resetTimer();
083      }
084      return input;
085    } else {
086      return m_baseline;
087    }
088  }
089}