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.AnalogJNI;
008import edu.wpi.first.hal.FRCNetComm.tResourceType;
009import edu.wpi.first.hal.HAL;
010import edu.wpi.first.hal.util.BoundaryException;
011import edu.wpi.first.util.sendable.Sendable;
012import edu.wpi.first.util.sendable.SendableBuilder;
013import edu.wpi.first.util.sendable.SendableRegistry;
014import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
015
016/** Class for creating and configuring Analog Triggers. */
017public class AnalogTrigger implements Sendable, AutoCloseable {
018  /** Exceptions dealing with improper operation of the Analog trigger. */
019  public static class AnalogTriggerException extends RuntimeException {
020    /**
021     * Create a new exception with the given message.
022     *
023     * @param message the message to pass with the exception
024     */
025    public AnalogTriggerException(String message) {
026      super(message);
027    }
028  }
029
030  /** Where the analog trigger is attached. */
031  protected int m_port;
032
033  protected AnalogInput m_analogInput;
034  protected DutyCycle m_dutyCycle;
035  protected boolean m_ownsAnalog;
036
037  /**
038   * Constructor for an analog trigger given a channel number.
039   *
040   * @param channel the port to use for the analog trigger
041   */
042  @SuppressWarnings("this-escape")
043  public AnalogTrigger(final int channel) {
044    this(new AnalogInput(channel));
045    m_ownsAnalog = true;
046    SendableRegistry.addChild(this, m_analogInput);
047  }
048
049  /**
050   * Construct an analog trigger given an analog channel. This should be used in the case of sharing
051   * an analog channel between the trigger and an analog input object.
052   *
053   * @param channel the AnalogInput to use for the analog trigger
054   */
055  @SuppressWarnings("this-escape")
056  public AnalogTrigger(AnalogInput channel) {
057    m_analogInput = channel;
058
059    m_port = AnalogJNI.initializeAnalogTrigger(channel.m_port);
060
061    int index = getIndex();
062
063    HAL.report(tResourceType.kResourceType_AnalogTrigger, index + 1);
064    SendableRegistry.addLW(this, "AnalogTrigger", index);
065  }
066
067  /**
068   * Construct an analog trigger given a duty cycle input.
069   *
070   * @param input the DutyCycle to use for the analog trigger
071   */
072  @SuppressWarnings("this-escape")
073  public AnalogTrigger(DutyCycle input) {
074    m_dutyCycle = input;
075
076    m_port = AnalogJNI.initializeAnalogTriggerDutyCycle(input.m_handle);
077
078    int index = getIndex();
079
080    HAL.report(tResourceType.kResourceType_AnalogTrigger, index + 1);
081    SendableRegistry.addLW(this, "AnalogTrigger", index);
082  }
083
084  @Override
085  public void close() {
086    SendableRegistry.remove(this);
087    AnalogJNI.cleanAnalogTrigger(m_port);
088    m_port = 0;
089    if (m_ownsAnalog && m_analogInput != null) {
090      m_analogInput.close();
091    }
092  }
093
094  /**
095   * Set the upper and lower limits of the analog trigger. The limits are given in ADC codes. If
096   * oversampling is used, the units must be scaled appropriately.
097   *
098   * @param lower the lower raw limit
099   * @param upper the upper raw limit
100   */
101  public void setLimitsRaw(final int lower, final int upper) {
102    if (lower > upper) {
103      throw new BoundaryException("Lower bound is greater than upper");
104    }
105    AnalogJNI.setAnalogTriggerLimitsRaw(m_port, lower, upper);
106  }
107
108  /**
109   * Set the upper and lower limits of the analog trigger. The limits are given as floating point
110   * values between 0 and 1.
111   *
112   * @param lower the lower duty cycle limit
113   * @param upper the upper duty cycle limit
114   */
115  public void setLimitsDutyCycle(double lower, double upper) {
116    if (lower > upper) {
117      throw new BoundaryException("Lower bound is greater than upper bound");
118    }
119    AnalogJNI.setAnalogTriggerLimitsDutyCycle(m_port, lower, upper);
120  }
121
122  /**
123   * Set the upper and lower limits of the analog trigger. The limits are given as floating point
124   * voltage values.
125   *
126   * @param lower the lower voltage limit
127   * @param upper the upper voltage limit
128   */
129  public void setLimitsVoltage(double lower, double upper) {
130    if (lower > upper) {
131      throw new BoundaryException("Lower bound is greater than upper bound");
132    }
133    AnalogJNI.setAnalogTriggerLimitsVoltage(m_port, lower, upper);
134  }
135
136  /**
137   * Configure the analog trigger to use the averaged vs. raw values. If the value is true, then the
138   * averaged value is selected for the analog trigger, otherwise the immediate value is used.
139   *
140   * @param useAveragedValue true to use an averaged value, false otherwise
141   */
142  public void setAveraged(boolean useAveragedValue) {
143    AnalogJNI.setAnalogTriggerAveraged(m_port, useAveragedValue);
144  }
145
146  /**
147   * Configure the analog trigger to use a filtered value. The analog trigger will operate with a 3
148   * point average rejection filter. This is designed to help with 360 degree pot applications for
149   * the period where the pot crosses through zero.
150   *
151   * @param useFilteredValue true to use a filtered value, false otherwise
152   */
153  public void setFiltered(boolean useFilteredValue) {
154    AnalogJNI.setAnalogTriggerFiltered(m_port, useFilteredValue);
155  }
156
157  /**
158   * Return the index of the analog trigger. This is the FPGA index of this analog trigger instance.
159   *
160   * @return The index of the analog trigger.
161   */
162  public final int getIndex() {
163    return AnalogJNI.getAnalogTriggerFPGAIndex(m_port);
164  }
165
166  /**
167   * Return the InWindow output of the analog trigger. True if the analog input is between the upper
168   * and lower limits.
169   *
170   * @return The InWindow output of the analog trigger.
171   */
172  public boolean getInWindow() {
173    return AnalogJNI.getAnalogTriggerInWindow(m_port);
174  }
175
176  /**
177   * Return the TriggerState output of the analog trigger. True if above upper limit. False if below
178   * lower limit. If in Hysteresis, maintain previous state.
179   *
180   * @return The TriggerState output of the analog trigger.
181   */
182  public boolean getTriggerState() {
183    return AnalogJNI.getAnalogTriggerTriggerState(m_port);
184  }
185
186  /**
187   * Creates an AnalogTriggerOutput object. Gets an output object that can be used for routing.
188   * Caller is responsible for deleting the AnalogTriggerOutput object.
189   *
190   * @param type An enum of the type of output object to create.
191   * @return A pointer to a new AnalogTriggerOutput object.
192   */
193  public AnalogTriggerOutput createOutput(AnalogTriggerType type) {
194    return new AnalogTriggerOutput(this, type);
195  }
196
197  @Override
198  public void initSendable(SendableBuilder builder) {
199    if (m_ownsAnalog) {
200      m_analogInput.initSendable(builder);
201    }
202  }
203}