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
028  /**
029   * Constructs a compressor for a specified module and type.
030   *
031   * @param module The module ID to use.
032   * @param moduleType The module type to use.
033   */
034  public Compressor(int module, PneumaticsModuleType moduleType) {
035    m_module = PneumaticsBase.getForType(module, moduleType);
036
037    if (!m_module.reserveCompressor()) {
038      m_module.close();
039      throw new AllocationException("Compressor already allocated");
040    }
041
042    m_module.enableCompressorDigital();
043
044    HAL.report(tResourceType.kResourceType_Compressor, module + 1);
045    SendableRegistry.addLW(this, "Compressor", module);
046  }
047
048  /**
049   * Constructs a compressor for a default module and specified type.
050   *
051   * @param moduleType The module type to use.
052   */
053  public Compressor(PneumaticsModuleType moduleType) {
054    this(PneumaticsBase.getDefaultForType(moduleType), moduleType);
055  }
056
057  @Override
058  public void close() {
059    SendableRegistry.remove(this);
060    m_module.unreserveCompressor();
061    m_module.close();
062    m_module = null;
063  }
064
065  /**
066   * Get the status of the compressor. To (re)enable the compressor use enableDigital() or
067   * enableAnalog(...).
068   *
069   * @return true if the compressor is on
070   * @deprecated To avoid confusion in thinking this (re)enables the compressor use IsEnabled().
071   */
072  @Deprecated(since = "2023", forRemoval = true)
073  public boolean enabled() {
074    return isEnabled();
075  }
076
077  /**
078   * Returns whether the compressor is active or not.
079   *
080   * @return true if the compressor is on - otherwise false.
081   */
082  public boolean isEnabled() {
083    return m_module.getCompressor();
084  }
085
086  /**
087   * Returns the state of the pressure switch.
088   *
089   * @return True if pressure switch indicates that the system is not full, otherwise false.
090   */
091  public boolean getPressureSwitchValue() {
092    return m_module.getPressureSwitch();
093  }
094
095  /**
096   * Get the current drawn by the compressor.
097   *
098   * @return Current drawn by the compressor in amps.
099   */
100  public double getCurrent() {
101    return m_module.getCompressorCurrent();
102  }
103
104  /**
105   * If supported by the device, returns the analog input voltage (on channel 0).
106   *
107   * <p>This function is only supported by the REV PH. On CTRE PCM, this will return 0.
108   *
109   * @return The analog input voltage, in volts.
110   */
111  public double getAnalogVoltage() {
112    return m_module.getAnalogVoltage(0);
113  }
114
115  /**
116   * If supported by the device, returns the pressure (in PSI) read by the analog pressure sensor
117   * (on channel 0).
118   *
119   * <p>This function is only supported by the REV PH with the REV Analog Pressure Sensor. On CTRE
120   * PCM, this will return 0.
121   *
122   * @return The pressure (in PSI) read by the analog pressure sensor.
123   */
124  public double getPressure() {
125    return m_module.getPressure(0);
126  }
127
128  /** Disable the compressor. */
129  public void disable() {
130    m_module.disableCompressor();
131  }
132
133  /**
134   * Enables the compressor in digital mode using the digital pressure switch. The compressor will
135   * turn on when the pressure switch indicates that the system is not full, and will turn off when
136   * the pressure switch indicates that the system is full.
137   */
138  public void enableDigital() {
139    m_module.enableCompressorDigital();
140  }
141
142  /**
143   * If supported by the device, enables the compressor in analog mode. This mode uses an analog
144   * pressure sensor connected to analog channel 0 to cycle the compressor. The compressor will turn
145   * on when the pressure drops below {@code minPressure} and will turn off when the pressure
146   * reaches {@code maxPressure}. This mode is only supported by the REV PH with the REV Analog
147   * Pressure Sensor connected to analog channel 0.
148   *
149   * <p>On CTRE PCM, this will enable digital control.
150   *
151   * @param minPressure The minimum pressure in PSI. The compressor will turn on when the pressure
152   *     drops below this value.
153   * @param maxPressure The maximum pressure in PSI. The compressor will turn off when the pressure
154   *     reaches this value.
155   */
156  public void enableAnalog(double minPressure, double maxPressure) {
157    m_module.enableCompressorAnalog(minPressure, maxPressure);
158  }
159
160  /**
161   * If supported by the device, enables the compressor in hybrid mode. This mode uses both a
162   * digital pressure switch and an analog pressure sensor connected to analog channel 0 to cycle
163   * the compressor. This mode is only supported by the REV PH with the REV Analog Pressure Sensor
164   * connected to analog channel 0.
165   *
166   * <p>The compressor will turn on when <i>both</i>:
167   *
168   * <ul>
169   *   <li>The digital pressure switch indicates the system is not full AND
170   *   <li>The analog pressure sensor indicates that the pressure in the system is below the
171   *       specified minimum pressure.
172   * </ul>
173   *
174   * <p>The compressor will turn off when <i>either</i>:
175   *
176   * <ul>
177   *   <li>The digital pressure switch is disconnected or indicates that the system is full OR
178   *   <li>The pressure detected by the analog sensor is greater than the specified maximum
179   *       pressure.
180   * </ul>
181   *
182   * <p>On CTRE PCM, this will enable digital control.
183   *
184   * @param minPressure The minimum pressure in PSI. The compressor will turn on when the pressure
185   *     drops below this value and the pressure switch indicates that the system is not full.
186   * @param maxPressure The maximum pressure in PSI. The compressor will turn off when the pressure
187   *     reaches this value or the pressure switch is disconnected or indicates that the system is
188   *     full.
189   */
190  public void enableHybrid(double minPressure, double maxPressure) {
191    m_module.enableCompressorHybrid(minPressure, maxPressure);
192  }
193
194  /**
195   * Returns the active compressor configuration.
196   *
197   * @return The active compressor configuration.
198   */
199  public CompressorConfigType getConfigType() {
200    return m_module.getCompressorConfigType();
201  }
202
203  @Override
204  public void initSendable(SendableBuilder builder) {
205    builder.setSmartDashboardType("Compressor");
206    builder.addBooleanProperty("Enabled", this::isEnabled, null);
207    builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
208  }
209}