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 public boolean getSolenoidVoltageFault() { 190 return CTREPCMJNI.getSolenoidVoltageFault(m_handle); 191 } 192 193 public boolean getSolenoidVoltageStickyFault() { 194 return CTREPCMJNI.getSolenoidVoltageStickyFault(m_handle); 195 } 196 197 /** Clears all sticky faults on this device. */ 198 public void clearAllStickyFaults() { 199 CTREPCMJNI.clearAllStickyFaults(m_handle); 200 } 201 202 @Override 203 public void fireOneShot(int index) { 204 CTREPCMJNI.fireOneShot(m_handle, index); 205 } 206 207 @Override 208 public void setOneShotDuration(int index, int durMs) { 209 CTREPCMJNI.setOneShotDuration(m_handle, index, durMs); 210 } 211 212 @Override 213 public boolean checkSolenoidChannel(int channel) { 214 return CTREPCMJNI.checkSolenoidChannel(channel); 215 } 216 217 @Override 218 public int checkAndReserveSolenoids(int mask) { 219 synchronized (m_dataStore.m_reserveLock) { 220 if ((m_dataStore.m_reservedMask & mask) != 0) { 221 return m_dataStore.m_reservedMask & mask; 222 } 223 m_dataStore.m_reservedMask |= mask; 224 return 0; 225 } 226 } 227 228 @Override 229 public void unreserveSolenoids(int mask) { 230 synchronized (m_dataStore.m_reserveLock) { 231 m_dataStore.m_reservedMask &= ~mask; 232 } 233 } 234 235 @Override 236 public Solenoid makeSolenoid(int channel) { 237 return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.CTREPCM, channel); 238 } 239 240 @Override 241 public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) { 242 return new DoubleSolenoid( 243 m_dataStore.m_module, PneumaticsModuleType.CTREPCM, forwardChannel, reverseChannel); 244 } 245 246 @Override 247 public Compressor makeCompressor() { 248 return new Compressor(m_dataStore.m_module, PneumaticsModuleType.CTREPCM); 249 } 250 251 @Override 252 public boolean reserveCompressor() { 253 synchronized (m_dataStore.m_reserveLock) { 254 if (m_dataStore.m_compressorReserved) { 255 return false; 256 } 257 m_dataStore.m_compressorReserved = true; 258 return true; 259 } 260 } 261 262 @Override 263 public void unreserveCompressor() { 264 synchronized (m_dataStore.m_reserveLock) { 265 m_dataStore.m_compressorReserved = false; 266 } 267 } 268 269 /** 270 * Disables the compressor. The compressor will not turn on until {@link 271 * #enableCompressorDigital()} is called. 272 */ 273 @Override 274 public void disableCompressor() { 275 CTREPCMJNI.setClosedLoopControl(m_handle, false); 276 } 277 278 @Override 279 public void enableCompressorDigital() { 280 CTREPCMJNI.setClosedLoopControl(m_handle, true); 281 } 282 283 /** 284 * Enables the compressor in digital mode. Analog mode is unsupported by the CTRE PCM. 285 * 286 * @param minPressure Unsupported. 287 * @param maxPressure Unsupported. 288 * @see #enableCompressorDigital() 289 */ 290 @Override 291 public void enableCompressorAnalog(double minPressure, double maxPressure) { 292 CTREPCMJNI.setClosedLoopControl(m_handle, false); 293 } 294 295 /** 296 * Enables the compressor in digital mode. Hybrid 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 enableCompressorHybrid(double minPressure, double maxPressure) { 304 CTREPCMJNI.setClosedLoopControl(m_handle, false); 305 } 306 307 @Override 308 public CompressorConfigType getCompressorConfigType() { 309 return CTREPCMJNI.getClosedLoopControl(m_handle) 310 ? CompressorConfigType.Digital 311 : CompressorConfigType.Disabled; 312 } 313 314 /** 315 * Unsupported by the CTRE PCM. 316 * 317 * @param channel Unsupported. 318 * @return 0 319 */ 320 @Override 321 public double getAnalogVoltage(int channel) { 322 return 0; 323 } 324 325 /** 326 * Unsupported by the CTRE PCM. 327 * 328 * @param channel Unsupported. 329 * @return 0 330 */ 331 @Override 332 public double getPressure(int channel) { 333 return 0; 334 } 335}