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