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 high time of the duty cycle signal.
077   *
078   * @return high time of last pulse in nanoseconds
079   */
080  public int getHighTimeNanoseconds() {
081    return DutyCycleJNI.getHighTime(m_handle);
082  }
083
084  /**
085   * Get the scale factor of the output.
086   *
087   * <p>An output equal to this value is always high, and then linearly scales down to 0. Divide a
088   * raw result by this in order to get the percentage between 0 and 1. Used by DMA.
089   *
090   * @return the output scale factor
091   */
092  public int getOutputScaleFactor() {
093    return DutyCycleJNI.getOutputScaleFactor(m_handle);
094  }
095
096  /**
097   * Get the FPGA index for the DutyCycle.
098   *
099   * @return the FPGA index
100   */
101  public final int getFPGAIndex() {
102    return DutyCycleJNI.getFPGAIndex(m_handle);
103  }
104
105  public int getSourceChannel() {
106    return m_source.getChannel();
107  }
108
109  @Override
110  public void initSendable(SendableBuilder builder) {
111    builder.setSmartDashboardType("Duty Cycle");
112    builder.addDoubleProperty("Frequency", this::getFrequency, null);
113    builder.addDoubleProperty("Output", this::getOutput, null);
114  }
115}