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}