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.
097   *
098   * <p>Not supported on the Rev PDH and returns 0.
099   *
100   * @return The temperature in degrees Celsius
101   */
102  public double getTemperature() {
103    return PowerDistributionJNI.getTemperature(m_handle);
104  }
105
106  /**
107   * Query the current of a single channel of the PDP/PDH.
108   *
109   * @param channel The channel (0-15 for PDP, 0-23 for PDH) to query
110   * @return The current of the channel in Amperes
111   */
112  public double getCurrent(int channel) {
113    return PowerDistributionJNI.getChannelCurrent(m_handle, channel);
114  }
115
116  /**
117   * Query the current of all monitored channels.
118   *
119   * @return The current of all the channels in Amperes
120   */
121  public double getTotalCurrent() {
122    return PowerDistributionJNI.getTotalCurrent(m_handle);
123  }
124
125  /**
126   * Query the total power drawn from the monitored channels of the PDP.
127   *
128   * <p>Not supported on the Rev PDH and returns 0.
129   *
130   * @return the total power in Watts
131   */
132  public double getTotalPower() {
133    return PowerDistributionJNI.getTotalPower(m_handle);
134  }
135
136  /**
137   * Query the total energy drawn from the monitored channels of the PDP.
138   *
139   * <p>Not supported on the Rev PDH and returns 0.
140   *
141   * @return the total energy in Joules
142   */
143  public double getTotalEnergy() {
144    return PowerDistributionJNI.getTotalEnergy(m_handle);
145  }
146
147  /**
148   * Reset the total energy to 0 of the PDP.
149   *
150   * <p>Not supported on the Rev PDH and does nothing.
151   */
152  public void resetTotalEnergy() {
153    PowerDistributionJNI.resetTotalEnergy(m_handle);
154  }
155
156  /** Clear all PDP/PDH sticky faults. */
157  public void clearStickyFaults() {
158    PowerDistributionJNI.clearStickyFaults(m_handle);
159  }
160
161  /**
162   * Gets module number (CAN ID).
163   *
164   * @return The module number (CAN ID).
165   */
166  public int getModule() {
167    return m_module;
168  }
169
170  /**
171   * Gets the module type for this power distribution object.
172   *
173   * @return The module type
174   */
175  public ModuleType getType() {
176    int type = PowerDistributionJNI.getType(m_handle);
177    if (type == PowerDistributionJNI.REV_TYPE) {
178      return ModuleType.kRev;
179    } else {
180      return ModuleType.kCTRE;
181    }
182  }
183
184  /**
185   * Gets whether the PDH switchable channel is turned on or off. Returns false with the CTRE PDP.
186   *
187   * @return The output state of the PDH switchable channel
188   */
189  public boolean getSwitchableChannel() {
190    return PowerDistributionJNI.getSwitchableChannel(m_handle);
191  }
192
193  /**
194   * Sets the PDH switchable channel on or off. Does nothing with the CTRE PDP.
195   *
196   * @param enabled Whether to turn the PDH switchable channel on or off
197   */
198  public void setSwitchableChannel(boolean enabled) {
199    PowerDistributionJNI.setSwitchableChannel(m_handle, enabled);
200  }
201
202  /**
203   * Returns the power distribution version number.
204   *
205   * @return The power distribution version number.
206   */
207  public PowerDistributionVersion getVersion() {
208    return PowerDistributionJNI.getVersion(m_handle);
209  }
210
211  /**
212   * Returns the power distribution faults.
213   *
214   * @return The power distribution faults.
215   */
216  public PowerDistributionFaults getFaults() {
217    return PowerDistributionJNI.getFaults(m_handle);
218  }
219
220  /**
221   * Returns the power distribution sticky faults.
222   *
223   * @return The power distribution sticky faults.
224   */
225  public PowerDistributionStickyFaults getStickyFaults() {
226    return PowerDistributionJNI.getStickyFaults(m_handle);
227  }
228
229  @Override
230  public void initSendable(SendableBuilder builder) {
231    builder.setSmartDashboardType("PowerDistribution");
232    int numChannels = getNumChannels();
233    for (int i = 0; i < numChannels; ++i) {
234      final int chan = i;
235      builder.addDoubleProperty(
236          "Chan" + i, () -> PowerDistributionJNI.getChannelCurrentNoError(m_handle, chan), null);
237    }
238    builder.addDoubleProperty(
239        "Voltage", () -> PowerDistributionJNI.getVoltageNoError(m_handle), null);
240    builder.addDoubleProperty(
241        "TotalCurrent", () -> PowerDistributionJNI.getTotalCurrent(m_handle), null);
242    builder.addBooleanProperty(
243        "SwitchableChannel",
244        () -> PowerDistributionJNI.getSwitchableChannelNoError(m_handle),
245        value -> PowerDistributionJNI.setSwitchableChannel(m_handle, value));
246  }
247}