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