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