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  public enum DebounceType {
015    kRising,
016    kFalling,
017    kBoth
018  }
019
020  private final double m_debounceTimeSeconds;
021  private final DebounceType m_debounceType;
022  private boolean m_baseline;
023
024  private double m_prevTimeSeconds;
025
026  /**
027   * Creates a new Debouncer.
028   *
029   * @param debounceTime The number of seconds the value must change from baseline for the filtered
030   *     value to change.
031   * @param type Which type of state change the debouncing will be performed on.
032   */
033  public Debouncer(double debounceTime, DebounceType type) {
034    m_debounceTimeSeconds = debounceTime;
035    m_debounceType = type;
036
037    resetTimer();
038
039    switch (m_debounceType) {
040      case kBoth: // fall-through
041      case kRising:
042        m_baseline = false;
043        break;
044      case kFalling:
045        m_baseline = true;
046        break;
047      default:
048        throw new IllegalArgumentException("Invalid debounce type!");
049    }
050  }
051
052  /**
053   * Creates a new Debouncer. Baseline value defaulted to "false."
054   *
055   * @param debounceTime The number of seconds the value must change from baseline for the filtered
056   *     value to change.
057   */
058  public Debouncer(double debounceTime) {
059    this(debounceTime, DebounceType.kRising);
060  }
061
062  private void resetTimer() {
063    m_prevTimeSeconds = MathSharedStore.getTimestamp();
064  }
065
066  private boolean hasElapsed() {
067    return MathSharedStore.getTimestamp() - m_prevTimeSeconds >= m_debounceTimeSeconds;
068  }
069
070  /**
071   * Applies the debouncer to the input stream.
072   *
073   * @param input The current value of the input stream.
074   * @return The debounced value of the input stream.
075   */
076  public boolean calculate(boolean input) {
077    if (input == m_baseline) {
078      resetTimer();
079    }
080
081    if (hasElapsed()) {
082      if (m_debounceType == DebounceType.kBoth) {
083        m_baseline = input;
084        resetTimer();
085      }
086      return input;
087    } else {
088      return m_baseline;
089    }
090  }
091}