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.CTREPCMJNI;
008import java.util.HashMap;
009import java.util.Map;
010
011/** Module class for controlling a Cross The Road Electronics Pneumatics Control Module. */
012public class PneumaticsControlModule implements PneumaticsBase {
013  private static class DataStore implements AutoCloseable {
014    public final int m_module;
015    public final int m_handle;
016    private int m_refCount;
017    private int m_reservedMask;
018    private boolean m_compressorReserved;
019    private final Object m_reserveLock = new Object();
020
021    DataStore(int module) {
022      m_handle = CTREPCMJNI.initialize(module);
023      m_module = module;
024      m_handleMap.put(module, this);
025    }
026
027    @Override
028    public void close() {
029      CTREPCMJNI.free(m_handle);
030      m_handleMap.remove(m_module);
031    }
032
033    public void addRef() {
034      m_refCount++;
035    }
036
037    public void removeRef() {
038      m_refCount--;
039      if (m_refCount == 0) {
040        this.close();
041      }
042    }
043  }
044
045  private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
046  private static final Object m_handleLock = new Object();
047
048  private static DataStore getForModule(int module) {
049    synchronized (m_handleLock) {
050      DataStore pcm = m_handleMap.get(module);
051      if (pcm == null) {
052        pcm = new DataStore(module);
053      }
054      pcm.addRef();
055      return pcm;
056    }
057  }
058
059  private static void freeModule(DataStore store) {
060    synchronized (m_handleLock) {
061      store.removeRef();
062    }
063  }
064
065  private final DataStore m_dataStore;
066  private final int m_handle;
067
068  /** Constructs a PneumaticsControlModule with the default ID (0). */
069  public PneumaticsControlModule() {
070    this(SensorUtil.getDefaultCTREPCMModule());
071  }
072
073  /**
074   * Constructs a PneumaticsControlModule.
075   *
076   * @param module module number to construct
077   */
078  public PneumaticsControlModule(int module) {
079    m_dataStore = getForModule(module);
080    m_handle = m_dataStore.m_handle;
081  }
082
083  @Override
084  public void close() {
085    freeModule(m_dataStore);
086  }
087
088  @Override
089  public boolean getCompressor() {
090    return CTREPCMJNI.getCompressor(m_handle);
091  }
092
093  @Override
094  public boolean getPressureSwitch() {
095    return CTREPCMJNI.getPressureSwitch(m_handle);
096  }
097
098  @Override
099  public double getCompressorCurrent() {
100    return CTREPCMJNI.getCompressorCurrent(m_handle);
101  }
102
103  /**
104   * Return whether the compressor current is currently too high.
105   *
106   * @return True if the compressor current is too high, otherwise false.
107   * @see #getCompressorCurrentTooHighStickyFault()
108   */
109  public boolean getCompressorCurrentTooHighFault() {
110    return CTREPCMJNI.getCompressorCurrentTooHighFault(m_handle);
111  }
112
113  /**
114   * Returns whether the compressor current has been too high since sticky faults were last cleared.
115   * This fault is persistent and can be cleared by {@link #clearAllStickyFaults()}
116   *
117   * @return True if the compressor current has been too high since sticky faults were last cleared.
118   * @see #getCompressorCurrentTooHighFault()
119   */
120  public boolean getCompressorCurrentTooHighStickyFault() {
121    return CTREPCMJNI.getCompressorCurrentTooHighStickyFault(m_handle);
122  }
123
124  /**
125   * Returns whether the compressor is currently shorted.
126   *
127   * @return True if the compressor is currently shorted, otherwise false.
128   * @see #getCompressorShortedStickyFault()
129   */
130  public boolean getCompressorShortedFault() {
131    return CTREPCMJNI.getCompressorShortedFault(m_handle);
132  }
133
134  /**
135   * Returns whether the compressor has been shorted since sticky faults were last cleared. This
136   * fault is persistent and can be cleared by {@link #clearAllStickyFaults()}
137   *
138   * @return True if the compressor has been shorted since sticky faults were last cleared,
139   *     otherwise false.
140   * @see #getCompressorShortedFault()
141   */
142  public boolean getCompressorShortedStickyFault() {
143    return CTREPCMJNI.getCompressorShortedStickyFault(m_handle);
144  }
145
146  /**
147   * Returns whether the compressor is currently disconnected.
148   *
149   * @return True if compressor is currently disconnected, otherwise false.
150   * @see #getCompressorNotConnectedStickyFault()
151   */
152  public boolean getCompressorNotConnectedFault() {
153    return CTREPCMJNI.getCompressorNotConnectedFault(m_handle);
154  }
155
156  /**
157   * Returns whether the compressor has been disconnected since sticky faults were last cleared.
158   * This fault is persistent and can be cleared by {@link #clearAllStickyFaults()}
159   *
160   * @return True if the compressor has been disconnected since sticky faults were last cleared,
161   *     otherwise false.
162   * @see #getCompressorNotConnectedFault()
163   */
164  public boolean getCompressorNotConnectedStickyFault() {
165    return CTREPCMJNI.getCompressorNotConnectedStickyFault(m_handle);
166  }
167
168  @Override
169  public void setSolenoids(int mask, int values) {
170    CTREPCMJNI.setSolenoids(m_handle, mask, values);
171  }
172
173  @Override
174  public int getSolenoids() {
175    return CTREPCMJNI.getSolenoids(m_handle);
176  }
177
178  @Override
179  public int getModuleNumber() {
180    return m_dataStore.m_module;
181  }
182
183  @Override
184  public int getSolenoidDisabledList() {
185    return CTREPCMJNI.getSolenoidDisabledList(m_handle);
186  }
187
188  /**
189   * Returns whether the solenoid is currently reporting a voltage fault.
190   *
191   * @return True if solenoid is reporting a fault, otherwise false.
192   * @see #getSolenoidVoltageStickyFault()
193   */
194  public boolean getSolenoidVoltageFault() {
195    return CTREPCMJNI.getSolenoidVoltageFault(m_handle);
196  }
197
198  /**
199   * Returns whether the solenoid has reported a voltage fault since sticky faults were last
200   * cleared. This fault is persistent and can be cleared by ClearAllStickyFaults()
201   *
202   * @return True if solenoid is reporting a fault, otherwise false.
203   * @see #getSolenoidVoltageFault()
204   */
205  public boolean getSolenoidVoltageStickyFault() {
206    return CTREPCMJNI.getSolenoidVoltageStickyFault(m_handle);
207  }
208
209  /** Clears all sticky faults on this device. */
210  public void clearAllStickyFaults() {
211    CTREPCMJNI.clearAllStickyFaults(m_handle);
212  }
213
214  @Override
215  public void fireOneShot(int index) {
216    CTREPCMJNI.fireOneShot(m_handle, index);
217  }
218
219  @Override
220  public void setOneShotDuration(int index, int durMs) {
221    CTREPCMJNI.setOneShotDuration(m_handle, index, durMs);
222  }
223
224  @Override
225  public boolean checkSolenoidChannel(int channel) {
226    return CTREPCMJNI.checkSolenoidChannel(channel);
227  }
228
229  @Override
230  public int checkAndReserveSolenoids(int mask) {
231    synchronized (m_dataStore.m_reserveLock) {
232      if ((m_dataStore.m_reservedMask & mask) != 0) {
233        return m_dataStore.m_reservedMask & mask;
234      }
235      m_dataStore.m_reservedMask |= mask;
236      return 0;
237    }
238  }
239
240  @Override
241  public void unreserveSolenoids(int mask) {
242    synchronized (m_dataStore.m_reserveLock) {
243      m_dataStore.m_reservedMask &= ~mask;
244    }
245  }
246
247  @Override
248  public Solenoid makeSolenoid(int channel) {
249    return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.CTREPCM, channel);
250  }
251
252  @Override
253  public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
254    return new DoubleSolenoid(
255        m_dataStore.m_module, PneumaticsModuleType.CTREPCM, forwardChannel, reverseChannel);
256  }
257
258  @Override
259  public Compressor makeCompressor() {
260    return new Compressor(m_dataStore.m_module, PneumaticsModuleType.CTREPCM);
261  }
262
263  @Override
264  public boolean reserveCompressor() {
265    synchronized (m_dataStore.m_reserveLock) {
266      if (m_dataStore.m_compressorReserved) {
267        return false;
268      }
269      m_dataStore.m_compressorReserved = true;
270      return true;
271    }
272  }
273
274  @Override
275  public void unreserveCompressor() {
276    synchronized (m_dataStore.m_reserveLock) {
277      m_dataStore.m_compressorReserved = false;
278    }
279  }
280
281  /**
282   * Disables the compressor. The compressor will not turn on until {@link
283   * #enableCompressorDigital()} is called.
284   */
285  @Override
286  public void disableCompressor() {
287    CTREPCMJNI.setClosedLoopControl(m_handle, false);
288  }
289
290  @Override
291  public void enableCompressorDigital() {
292    CTREPCMJNI.setClosedLoopControl(m_handle, true);
293  }
294
295  /**
296   * Enables the compressor in digital mode. Analog mode is unsupported by the CTRE PCM.
297   *
298   * @param minPressure Unsupported.
299   * @param maxPressure Unsupported.
300   * @see #enableCompressorDigital()
301   */
302  @Override
303  public void enableCompressorAnalog(double minPressure, double maxPressure) {
304    CTREPCMJNI.setClosedLoopControl(m_handle, false);
305  }
306
307  /**
308   * Enables the compressor in digital mode. Hybrid mode is unsupported by the CTRE PCM.
309   *
310   * @param minPressure Unsupported.
311   * @param maxPressure Unsupported.
312   * @see #enableCompressorDigital()
313   */
314  @Override
315  public void enableCompressorHybrid(double minPressure, double maxPressure) {
316    CTREPCMJNI.setClosedLoopControl(m_handle, false);
317  }
318
319  @Override
320  public CompressorConfigType getCompressorConfigType() {
321    return CTREPCMJNI.getClosedLoopControl(m_handle)
322        ? CompressorConfigType.Digital
323        : CompressorConfigType.Disabled;
324  }
325
326  /**
327   * Unsupported by the CTRE PCM.
328   *
329   * @param channel Unsupported.
330   * @return 0
331   */
332  @Override
333  public double getAnalogVoltage(int channel) {
334    return 0;
335  }
336
337  /**
338   * Unsupported by the CTRE PCM.
339   *
340   * @param channel Unsupported.
341   * @return 0
342   */
343  @Override
344  public double getPressure(int channel) {
345    return 0;
346  }
347}