001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2015-2017. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import java.util.concurrent.locks.Lock;
011import java.util.concurrent.locks.ReentrantLock;
012
013import edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI;
014import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
015import edu.wpi.first.wpilibj.hal.HAL;
016
017/**
018 * Class to enable glitch filtering on a set of digital inputs. This class will manage adding and
019 * removing digital inputs from a FPGA glitch filter. The filter lets the user configure the time
020 * that an input must remain high or low before it is classified as high or low.
021 */
022public class DigitalGlitchFilter extends SensorBase {
023
024  /**
025   * Configures the Digital Glitch Filter to its default settings.
026   */
027  public DigitalGlitchFilter() {
028    synchronized (m_mutex) {
029      int index = 0;
030      while (m_filterAllocated[index] != false && index < m_filterAllocated.length) {
031        index++;
032      }
033      if (index != m_filterAllocated.length) {
034        m_channelIndex = index;
035        m_filterAllocated[index] = true;
036        HAL.report(tResourceType.kResourceType_DigitalFilter,
037            m_channelIndex, 0);
038      }
039    }
040  }
041
042  /**
043   * Free the resources used by this object.
044   */
045  public void free() {
046    if (m_channelIndex >= 0) {
047      synchronized (m_mutex) {
048        m_filterAllocated[m_channelIndex] = false;
049      }
050      m_channelIndex = -1;
051    }
052  }
053
054  private static void setFilter(DigitalSource input, int channelIndex) {
055    if (input != null) { // Counter might have just one input
056      // analog triggers are not supported for DigitalGlitchFilters
057      if (input.isAnalogTrigger()) {
058        throw new IllegalStateException("Analog Triggers not supported for DigitalGlitchFilters");
059      }
060      DigitalGlitchFilterJNI.setFilterSelect(input.getPortHandleForRouting(), channelIndex);
061
062      int selected = DigitalGlitchFilterJNI.getFilterSelect(input.getPortHandleForRouting());
063      if (selected != channelIndex) {
064        throw new IllegalStateException("DigitalGlitchFilterJNI.setFilterSelect("
065            + channelIndex + ") failed -> " + selected);
066      }
067    }
068  }
069
070  /**
071   * Assigns the DigitalSource to this glitch filter.
072   *
073   * @param input The DigitalSource to add.
074   */
075  public void add(DigitalSource input) {
076    setFilter(input, m_channelIndex + 1);
077  }
078
079  /**
080   * Assigns the Encoder to this glitch filter.
081   *
082   * @param input The Encoder to add.
083   */
084  public void add(Encoder input) {
085    add(input.m_aSource);
086    add(input.m_bSource);
087  }
088
089  /**
090   * Assigns the Counter to this glitch filter.
091   *
092   * @param input The Counter to add.
093   */
094  public void add(Counter input) {
095    add(input.m_upSource);
096    add(input.m_downSource);
097  }
098
099  /**
100   * Removes this filter from the given digital input.
101   *
102   * @param input The DigitalSource to stop filtering.
103   */
104  public void remove(DigitalSource input) {
105    setFilter(input, 0);
106  }
107
108  /**
109   * Removes this filter from the given Encoder.
110   *
111   * @param input the Encoder to stop filtering.
112   */
113  public void remove(Encoder input) {
114    remove(input.m_aSource);
115    remove(input.m_bSource);
116  }
117
118  /**
119   * Removes this filter from the given Counter.
120   *
121   * @param input The Counter to stop filtering.
122   */
123  public void remove(Counter input) {
124    remove(input.m_upSource);
125    remove(input.m_downSource);
126  }
127
128  /**
129   * Sets the number of FPGA cycles that the input must hold steady to pass through this glitch
130   * filter.
131   *
132   * @param fpgaCycles The number of FPGA cycles.
133   */
134  public void setPeriodCycles(int fpgaCycles) {
135    DigitalGlitchFilterJNI.setFilterPeriod(m_channelIndex, fpgaCycles);
136  }
137
138  /**
139   * Sets the number of nanoseconds that the input must hold steady to pass through this glitch
140   * filter.
141   *
142   * @param nanoseconds The number of nanoseconds.
143   */
144  public void setPeriodNanoSeconds(long nanoseconds) {
145    int fpgaCycles = (int) (nanoseconds * kSystemClockTicksPerMicrosecond / 4
146        / 1000);
147    setPeriodCycles(fpgaCycles);
148  }
149
150  /**
151   * Gets the number of FPGA cycles that the input must hold steady to pass through this glitch
152   * filter.
153   *
154   * @return The number of cycles.
155   */
156  public int getPeriodCycles() {
157    return DigitalGlitchFilterJNI.getFilterPeriod(m_channelIndex);
158  }
159
160  /**
161   * Gets the number of nanoseconds that the input must hold steady to pass through this glitch
162   * filter.
163   *
164   * @return The number of nanoseconds.
165   */
166  public long getPeriodNanoSeconds() {
167    int fpgaCycles = getPeriodCycles();
168
169    return (long) fpgaCycles * 1000L
170        / (long) (kSystemClockTicksPerMicrosecond / 4);
171  }
172
173  private int m_channelIndex = -1;
174  private static final Lock m_mutex = new ReentrantLock(true);
175  private static final boolean[] m_filterAllocated = new boolean[3];
176}