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  @SuppressWarnings("this-escape")
037  public DutyCycle(DigitalSource digitalSource) {
038    m_handle =
039        DutyCycleJNI.initialize(
040            digitalSource.getPortHandleForRouting(),
041            digitalSource.getAnalogTriggerTypeForRouting());
042
043    m_source = digitalSource;
044    int index = getFPGAIndex();
045    HAL.report(tResourceType.kResourceType_DutyCycle, index + 1);
046    SendableRegistry.addLW(this, "Duty Cycle", index);
047  }
048
049  /** Close the DutyCycle and free all resources. */
050  @Override
051  public void close() {
052    SendableRegistry.remove(this);
053    DutyCycleJNI.free(m_handle);
054  }
055
056  /**
057   * Get the frequency of the duty cycle signal.
058   *
059   * @return frequency in Hertz
060   */
061  public int getFrequency() {
062    return DutyCycleJNI.getFrequency(m_handle);
063  }
064
065  /**
066   * Get the output ratio of the duty cycle signal.
067   *
068   * <p>0 means always low, 1 means always high.
069   *
070   * @return output ratio between 0 and 1
071   */
072  public double getOutput() {
073    return DutyCycleJNI.getOutput(m_handle);
074  }
075
076  /**
077   * Get the raw high time of the duty cycle signal.
078   *
079   * @return high time of last pulse in nanoseconds
080   */
081  public int getHighTimeNanoseconds() {
082    return DutyCycleJNI.getHighTime(m_handle);
083  }
084
085  /**
086   * Get the scale factor of the output.
087   *
088   * <p>An output equal to this value is always high, and then linearly scales down to 0. Divide a
089   * raw result by this in order to get the percentage between 0 and 1. Used by DMA.
090   *
091   * @return the output scale factor
092   */
093  public int getOutputScaleFactor() {
094    return DutyCycleJNI.getOutputScaleFactor(m_handle);
095  }
096
097  /**
098   * Get the FPGA index for the DutyCycle.
099   *
100   * @return the FPGA index
101   */
102  public final int getFPGAIndex() {
103    return DutyCycleJNI.getFPGAIndex(m_handle);
104  }
105
106  /**
107   * Get the channel of the source.
108   *
109   * @return the source channel
110   */
111  public int getSourceChannel() {
112    return m_source.getChannel();
113  }
114
115  @Override
116  public void initSendable(SendableBuilder builder) {
117    builder.setSmartDashboardType("Duty Cycle");
118    builder.addDoubleProperty("Frequency", this::getFrequency, null);
119    builder.addDoubleProperty("Output", this::getOutput, null);
120  }
121}