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.HAL;
008import edu.wpi.first.hal.PowerDistributionFaults;
009import edu.wpi.first.hal.PowerDistributionJNI;
010import edu.wpi.first.hal.PowerDistributionStickyFaults;
011import edu.wpi.first.hal.PowerDistributionVersion;
012import edu.wpi.first.util.sendable.Sendable;
013import edu.wpi.first.util.sendable.SendableBuilder;
014import edu.wpi.first.util.sendable.SendableRegistry;
015
016/**
017 * Class for getting voltage, current, temperature, power and energy from the CTRE Power
018 * Distribution Panel (PDP) or REV Power Distribution Hub (PDH) over CAN.
019 */
020public class PowerDistribution implements Sendable, AutoCloseable {
021  private final int m_handle;
022  private final int m_module;
023
024  /** Default module number. */
025  public static final int kDefaultModule = PowerDistributionJNI.DEFAULT_MODULE;
026
027  /** Power distribution module type. */
028  public enum ModuleType {
029    /** CTRE (Cross The Road Electronics) Power Distribution Panel (PDP). */
030    kCTRE(PowerDistributionJNI.CTRE_TYPE),
031    /** REV Power Distribution Hub (PDH). */
032    kRev(PowerDistributionJNI.REV_TYPE);
033
034    /** ModuleType value. */
035    public final int value;
036
037    ModuleType(int value) {
038      this.value = value;
039    }
040  }
041
042  /**
043   * Constructs a PowerDistribution object.
044   *
045   * @param busId The bus ID
046   * @param module The CAN ID of the PDP/PDH.
047   * @param moduleType Module type (CTRE or REV).
048   */
049  @SuppressWarnings("this-escape")
050  public PowerDistribution(int busId, int module, ModuleType moduleType) {
051    m_handle = PowerDistributionJNI.initialize(busId, module, moduleType.value);
052    m_module = PowerDistributionJNI.getModuleNumber(m_handle);
053
054    if (moduleType == ModuleType.kCTRE) {
055      HAL.reportUsage("PDP", m_module, "");
056    } else {
057      HAL.reportUsage("PDH", m_module, "");
058    }
059    SendableRegistry.add(this, "PowerDistribution", m_module);
060  }
061
062  /**
063   * Constructs a PowerDistribution object.
064   *
065   * <p>Detects the connected PDP/PDH using the default CAN ID (0 for CTRE and 1 for REV).
066   *
067   * @param busId The bus ID
068   */
069  @SuppressWarnings("this-escape")
070  public PowerDistribution(int busId) {
071    m_handle =
072        PowerDistributionJNI.initialize(busId, kDefaultModule, PowerDistributionJNI.AUTOMATIC_TYPE);
073    m_module = PowerDistributionJNI.getModuleNumber(m_handle);
074
075    if (PowerDistributionJNI.getType(m_handle) == PowerDistributionJNI.CTRE_TYPE) {
076      HAL.reportUsage("PowerDistribution", m_module, "CTRE");
077    } else {
078      HAL.reportUsage("PowerDistribution", m_module, "Rev");
079    }
080
081    SendableRegistry.add(this, "PowerDistribution", m_module);
082  }
083
084  @Override
085  public void close() {
086    SendableRegistry.remove(this);
087  }
088
089  /**
090   * Gets the number of channels for this power distribution object.
091   *
092   * @return Number of output channels (16 for PDP, 24 for PDH).
093   */
094  public int getNumChannels() {
095    return PowerDistributionJNI.getNumChannels(m_handle);
096  }
097
098  /**
099   * Query the input voltage of the PDP/PDH.
100   *
101   * @return The voltage in volts
102   */
103  public double getVoltage() {
104    return PowerDistributionJNI.getVoltage(m_handle);
105  }
106
107  /**
108   * Query the temperature of the PDP.
109   *
110   * <p>Not supported on the Rev PDH and returns 0.
111   *
112   * @return The temperature in degrees Celsius
113   */
114  public double getTemperature() {
115    return PowerDistributionJNI.getTemperature(m_handle);
116  }
117
118  /**
119   * Query the current of a single channel of the PDP/PDH.
120   *
121   * @param channel The channel (0-15 for PDP, 0-23 for PDH) to query
122   * @return The current of the channel in Amperes
123   */
124  public double getCurrent(int channel) {
125    return PowerDistributionJNI.getChannelCurrent(m_handle, channel);
126  }
127
128  /**
129   * Query all currents of the PDP.
130   *
131   * @return The current of each channel in Amperes
132   */
133  public double[] getAllCurrents() {
134    double[] currents = new double[getNumChannels()];
135    PowerDistributionJNI.getAllCurrents(m_handle, currents);
136    return currents;
137  }
138
139  /**
140   * Query the current of all monitored channels.
141   *
142   * @return The current of all the channels in Amperes
143   */
144  public double getTotalCurrent() {
145    return PowerDistributionJNI.getTotalCurrent(m_handle);
146  }
147
148  /**
149   * Query the total power drawn from the monitored channels of the PDP.
150   *
151   * <p>Not supported on the Rev PDH and returns 0.
152   *
153   * @return the total power in Watts
154   */
155  public double getTotalPower() {
156    return PowerDistributionJNI.getTotalPower(m_handle);
157  }
158
159  /**
160   * Query the total energy drawn from the monitored channels of the PDP.
161   *
162   * <p>Not supported on the Rev PDH and returns 0.
163   *
164   * @return the total energy in Joules
165   */
166  public double getTotalEnergy() {
167    return PowerDistributionJNI.getTotalEnergy(m_handle);
168  }
169
170  /**
171   * Reset the total energy to 0 of the PDP.
172   *
173   * <p>Not supported on the Rev PDH and does nothing.
174   */
175  public void resetTotalEnergy() {
176    PowerDistributionJNI.resetTotalEnergy(m_handle);
177  }
178
179  /** Clear all PDP/PDH sticky faults. */
180  public void clearStickyFaults() {
181    PowerDistributionJNI.clearStickyFaults(m_handle);
182  }
183
184  /**
185   * Gets module number (CAN ID).
186   *
187   * @return The module number (CAN ID).
188   */
189  public int getModule() {
190    return m_module;
191  }
192
193  /**
194   * Gets the module type for this power distribution object.
195   *
196   * @return The module type
197   */
198  public ModuleType getType() {
199    int type = PowerDistributionJNI.getType(m_handle);
200    if (type == PowerDistributionJNI.REV_TYPE) {
201      return ModuleType.kRev;
202    } else {
203      return ModuleType.kCTRE;
204    }
205  }
206
207  /**
208   * Gets whether the PDH switchable channel is turned on or off. Returns false with the CTRE PDP.
209   *
210   * @return The output state of the PDH switchable channel
211   */
212  public boolean getSwitchableChannel() {
213    return PowerDistributionJNI.getSwitchableChannel(m_handle);
214  }
215
216  /**
217   * Sets the PDH switchable channel on or off. Does nothing with the CTRE PDP.
218   *
219   * @param enabled Whether to turn the PDH switchable channel on or off
220   */
221  public void setSwitchableChannel(boolean enabled) {
222    PowerDistributionJNI.setSwitchableChannel(m_handle, enabled);
223  }
224
225  /**
226   * Returns the power distribution version number.
227   *
228   * @return The power distribution version number.
229   */
230  public PowerDistributionVersion getVersion() {
231    return PowerDistributionJNI.getVersion(m_handle);
232  }
233
234  /**
235   * Returns the power distribution faults.
236   *
237   * <p>On a CTRE PDP, this will return an object with no faults active.
238   *
239   * @return The power distribution faults.
240   */
241  public PowerDistributionFaults getFaults() {
242    return PowerDistributionJNI.getFaults(m_handle);
243  }
244
245  /**
246   * Returns the power distribution sticky faults.
247   *
248   * <p>On a CTRE PDP, this will return an object with no faults active.
249   *
250   * @return The power distribution sticky faults.
251   */
252  public PowerDistributionStickyFaults getStickyFaults() {
253    return PowerDistributionJNI.getStickyFaults(m_handle);
254  }
255
256  @Override
257  public void initSendable(SendableBuilder builder) {
258    builder.setSmartDashboardType("PowerDistribution");
259    int numChannels = getNumChannels();
260    for (int i = 0; i < numChannels; ++i) {
261      final int chan = i;
262      builder.addDoubleProperty(
263          "Chan" + i, () -> PowerDistributionJNI.getChannelCurrentNoError(m_handle, chan), null);
264    }
265    builder.addDoubleProperty(
266        "Voltage", () -> PowerDistributionJNI.getVoltageNoError(m_handle), null);
267    builder.addDoubleProperty(
268        "TotalCurrent", () -> PowerDistributionJNI.getTotalCurrent(m_handle), null);
269    builder.addBooleanProperty(
270        "SwitchableChannel",
271        () -> PowerDistributionJNI.getSwitchableChannelNoError(m_handle),
272        value -> PowerDistributionJNI.setSwitchableChannel(m_handle, value));
273  }
274}