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