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