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}