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}