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