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