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