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.DutyCycleJNI;
008import edu.wpi.first.hal.FRCNetComm.tResourceType;
009import edu.wpi.first.hal.HAL;
010import edu.wpi.first.util.sendable.Sendable;
011import edu.wpi.first.util.sendable.SendableBuilder;
012import edu.wpi.first.util.sendable.SendableRegistry;
013
014/**
015 * Class to read a duty cycle PWM input.
016 *
017 * <p>PWM input signals are specified with a frequency and a ratio of high to low in that frequency.
018 * There are 8 of these in the roboRIO, and they can be attached to any {@link DigitalSource}.
019 *
020 * <p>These can be combined as the input of an AnalogTrigger to a Counter in order to implement
021 * rollover checking.
022 */
023public class DutyCycle implements Sendable, AutoCloseable {
024  // Explicitly package private
025  final int m_handle;
026
027  private final DigitalSource m_source;
028
029  /**
030   * Constructs a DutyCycle input from a DigitalSource input.
031   *
032   * <p>This class does not own the inputted source.
033   *
034   * @param digitalSource The DigitalSource to use.
035   */
036  public DutyCycle(DigitalSource digitalSource) {
037    m_handle =
038        DutyCycleJNI.initialize(
039            digitalSource.getPortHandleForRouting(),
040            digitalSource.getAnalogTriggerTypeForRouting());
041
042    m_source = digitalSource;
043    int index = getFPGAIndex();
044    HAL.report(tResourceType.kResourceType_DutyCycle, index + 1);
045    SendableRegistry.addLW(this, "Duty Cycle", index);
046  }
047
048  /** Close the DutyCycle and free all resources. */
049  @Override
050  public void close() {
051    SendableRegistry.remove(this);
052    DutyCycleJNI.free(m_handle);
053  }
054
055  /**
056   * Get the frequency of the duty cycle signal.
057   *
058   * @return frequency in Hertz
059   */
060  public int getFrequency() {
061    return DutyCycleJNI.getFrequency(m_handle);
062  }
063
064  /**
065   * Get the output ratio of the duty cycle signal.
066   *
067   * <p>0 means always low, 1 means always high.
068   *
069   * @return output ratio between 0 and 1
070   */
071  public double getOutput() {
072    return DutyCycleJNI.getOutput(m_handle);
073  }
074
075  /**
076   * Get the raw output ratio of the duty cycle signal.
077   *
078   * <p>0 means always low, an output equal to getOutputScaleFactor() means always high.
079   *
080   * @return output ratio in raw units
081   */
082  public int getOutputRaw() {
083    return DutyCycleJNI.getOutputRaw(m_handle);
084  }
085
086  /**
087   * Get the scale factor of the output.
088   *
089   * <p>An output equal to this value is always high, and then linearly scales down to 0. Divide the
090   * result of getOutputRaw by this in order to get the percentage between 0 and 1.
091   *
092   * @return the output scale factor
093   */
094  public int getOutputScaleFactor() {
095    return DutyCycleJNI.getOutputScaleFactor(m_handle);
096  }
097
098  /**
099   * Get the FPGA index for the DutyCycle.
100   *
101   * @return the FPGA index
102   */
103  @SuppressWarnings("AbbreviationAsWordInName")
104  public final int getFPGAIndex() {
105    return DutyCycleJNI.getFPGAIndex(m_handle);
106  }
107
108  public int getSourceChannel() {
109    return m_source.getChannel();
110  }
111
112  @Override
113  public void initSendable(SendableBuilder builder) {
114    builder.setSmartDashboardType("Duty Cycle");
115    builder.addDoubleProperty("Frequency", this::getFrequency, null);
116    builder.addDoubleProperty("Output", this::getOutput, null);
117  }
118}