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.FRCNetComm.tResourceType;
008import edu.wpi.first.hal.HAL;
009import edu.wpi.first.hal.util.AllocationException;
010import edu.wpi.first.util.sendable.Sendable;
011import edu.wpi.first.util.sendable.SendableBuilder;
012import edu.wpi.first.util.sendable.SendableRegistry;
013
014/**
015 * Class for operating a compressor connected to a pneumatics module. The module will automatically
016 * run in closed loop mode by default whenever a {@link Solenoid} object is created. For most cases,
017 * a Compressor object does not need to be instantiated or used in a robot program. This class is
018 * only required in cases where the robot program needs a more detailed status of the compressor or
019 * to enable/disable closed loop control.
020 *
021 * <p>Note: you cannot operate the compressor directly from this class as doing so would circumvent
022 * the safety provided by using the pressure switch and closed loop control. You can only turn off
023 * closed loop control, thereby stopping the compressor from operating.
024 */
025public class Compressor implements Sendable, AutoCloseable {
026  private PneumaticsBase m_module;
027  private PneumaticsModuleType m_moduleType;
028
029  /**
030   * Constructs a compressor for a specified module and type.
031   *
032   * @param module The module ID to use.
033   * @param moduleType The module type to use.
034   */
035  @SuppressWarnings("this-escape")
036  public Compressor(int module, PneumaticsModuleType moduleType) {
037    m_module = PneumaticsBase.getForType(module, moduleType);
038    m_moduleType = moduleType;
039
040    if (!m_module.reserveCompressor()) {
041      m_module.close();
042      throw new AllocationException("Compressor already allocated");
043    }
044
045    m_module.enableCompressorDigital();
046
047    HAL.report(tResourceType.kResourceType_Compressor, module + 1);
048    SendableRegistry.addLW(this, "Compressor", module);
049  }
050
051  /**
052   * Constructs a compressor for a default module and specified type.
053   *
054   * @param moduleType The module type to use.
055   */
056  public Compressor(PneumaticsModuleType moduleType) {
057    this(PneumaticsBase.getDefaultForType(moduleType), moduleType);
058  }
059
060  @Override
061  public void close() {
062    SendableRegistry.remove(this);
063    m_module.unreserveCompressor();
064    m_module.close();
065    m_module = null;
066  }
067
068  /**
069   * Returns whether the compressor is active or not.
070   *
071   * @return true if the compressor is on - otherwise false.
072   */
073  public boolean isEnabled() {
074    return m_module.getCompressor();
075  }
076
077  /**
078   * Returns the state of the pressure switch.
079   *
080   * @return True if pressure switch indicates that the system is not full, otherwise false.
081   */
082  public boolean getPressureSwitchValue() {
083    return m_module.getPressureSwitch();
084  }
085
086  /**
087   * Get the current drawn by the compressor.
088   *
089   * @return Current drawn by the compressor in amps.
090   */
091  public double getCurrent() {
092    return m_module.getCompressorCurrent();
093  }
094
095  /**
096   * If supported by the device, returns the analog input voltage (on channel 0).
097   *
098   * <p>This function is only supported by the REV PH. On CTRE PCM, this will return 0.
099   *
100   * @return The analog input voltage, in volts.
101   */
102  public double getAnalogVoltage() {
103    return m_module.getAnalogVoltage(0);
104  }
105
106  /**
107   * If supported by the device, returns the pressure (in PSI) read by the analog pressure sensor
108   * (on channel 0).
109   *
110   * <p>This function is only supported by the REV PH with the REV Analog Pressure Sensor. On CTRE
111   * PCM, this will return 0.
112   *
113   * @return The pressure (in PSI) read by the analog pressure sensor.
114   */
115  public double getPressure() {
116    return m_module.getPressure(0);
117  }
118
119  /** Disable the compressor. */
120  public void disable() {
121    m_module.disableCompressor();
122  }
123
124  /**
125   * Enables the compressor in digital mode using the digital pressure switch. The compressor will
126   * turn on when the pressure switch indicates that the system is not full, and will turn off when
127   * the pressure switch indicates that the system is full.
128   */
129  public void enableDigital() {
130    m_module.enableCompressorDigital();
131  }
132
133  /**
134   * If supported by the device, enables the compressor in analog mode. This mode uses an analog
135   * pressure sensor connected to analog channel 0 to cycle the compressor. The compressor will turn
136   * on when the pressure drops below {@code minPressure} and will turn off when the pressure
137   * reaches {@code maxPressure}. This mode is only supported by the REV PH with the REV Analog
138   * Pressure Sensor connected to analog channel 0.
139   *
140   * <p>On CTRE PCM, this will enable digital control.
141   *
142   * @param minPressure The minimum pressure in PSI. The compressor will turn on when the pressure
143   *     drops below this value.
144   * @param maxPressure The maximum pressure in PSI. The compressor will turn off when the pressure
145   *     reaches this value.
146   */
147  public void enableAnalog(double minPressure, double maxPressure) {
148    m_module.enableCompressorAnalog(minPressure, maxPressure);
149  }
150
151  /**
152   * If supported by the device, enables the compressor in hybrid mode. This mode uses both a
153   * digital pressure switch and an analog pressure sensor connected to analog channel 0 to cycle
154   * the compressor. This mode is only supported by the REV PH with the REV Analog Pressure Sensor
155   * connected to analog channel 0.
156   *
157   * <p>The compressor will turn on when <i>both</i>:
158   *
159   * <ul>
160   *   <li>The digital pressure switch indicates the system is not full AND
161   *   <li>The analog pressure sensor indicates that the pressure in the system is below the
162   *       specified minimum pressure.
163   * </ul>
164   *
165   * <p>The compressor will turn off when <i>either</i>:
166   *
167   * <ul>
168   *   <li>The digital pressure switch is disconnected or indicates that the system is full OR
169   *   <li>The pressure detected by the analog sensor is greater than the specified maximum
170   *       pressure.
171   * </ul>
172   *
173   * <p>On CTRE PCM, this will enable digital control.
174   *
175   * @param minPressure The minimum pressure in PSI. The compressor will turn on when the pressure
176   *     drops below this value and the pressure switch indicates that the system is not full.
177   * @param maxPressure The maximum pressure in PSI. The compressor will turn off when the pressure
178   *     reaches this value or the pressure switch is disconnected or indicates that the system is
179   *     full.
180   */
181  public void enableHybrid(double minPressure, double maxPressure) {
182    m_module.enableCompressorHybrid(minPressure, maxPressure);
183  }
184
185  /**
186   * Returns the active compressor configuration.
187   *
188   * @return The active compressor configuration.
189   */
190  public CompressorConfigType getConfigType() {
191    return m_module.getCompressorConfigType();
192  }
193
194  @Override
195  public void initSendable(SendableBuilder builder) {
196    builder.setSmartDashboardType("Compressor");
197    builder.addBooleanProperty("Enabled", this::isEnabled, null);
198    builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
199    builder.addDoubleProperty("Current (A)", this::getCurrent, null);
200    if (m_moduleType == PneumaticsModuleType.REVPH) { // These are not supported by the CTRE PCM
201      builder.addDoubleProperty("Analog Voltage", this::getAnalogVoltage, null);
202      builder.addDoubleProperty("Pressure (PSI)", this::getPressure, null);
203    }
204  }
205}