001 /*----------------------------------------------------------------------------*/
002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
003 /* Open Source Software - may be modified and shared by FRC teams. The code */
004 /* must be accompanied by the FIRST BSD license file in the root directory of */
005 /* the project. */
006 /*----------------------------------------------------------------------------*/
007
008 package edu.wpi.first.wpilibj;
009
010 import edu.wpi.first.wpilibj.communication.UsageReporting;
011 import edu.wpi.first.wpilibj.fpga.tAnalogTrigger;
012 import edu.wpi.first.wpilibj.parsing.IInputOutput;
013 import edu.wpi.first.wpilibj.util.AllocationException;
014 import edu.wpi.first.wpilibj.util.BoundaryException;
015 import edu.wpi.first.wpilibj.util.CheckedAllocationException;
016
017 /**
018 * Class for creating and configuring Analog Triggers
019 * @author dtjones
020 */
021 public class AnalogTrigger implements IInputOutput{
022
023 /**
024 * Exceptions dealing with improper operation of the Analog trigger
025 */
026 public class AnalogTriggerException extends RuntimeException {
027
028 /**
029 * Create a new exception with the given message
030 * @param message the message to pass with the exception
031 */
032 public AnalogTriggerException(String message) {
033 super(message);
034 }
035
036 }
037
038 private static Resource triggers = new Resource(tAnalogTrigger.kNumSystems);
039 /**
040 * Where the analog trigger is attached
041 */
042 protected int m_index;
043 private tAnalogTrigger m_trigger;
044 private AnalogModule m_analogModule;
045 private int m_channel;
046
047 /**
048 * Initialize an analog trigger from a module number and channel.
049 * This is the common code for the two constructors that use a module number and channel.
050 * @param moduleNumber The number of the analog module to create this trigger on.
051 * @param channel the port to use for the analog trigger
052 */
053 protected void initTrigger(final int moduleNumber, final int channel) {
054 m_channel = channel;
055 m_analogModule = AnalogModule.getInstance(moduleNumber);
056 try {
057 m_index = triggers.allocate();
058 } catch (CheckedAllocationException e) {
059 throw new AllocationException("No analog triggers are available to allocate");
060 }
061 m_trigger = new tAnalogTrigger((byte) m_index);
062 m_trigger.writeSourceSelect_Channel((byte) (m_channel - 1));
063 m_trigger.writeSourceSelect_Module((byte) moduleNumber - 1);
064 UsageReporting.report(UsageReporting.kResourceType_AnalogTrigger, channel, moduleNumber-1);
065 }
066
067 /**
068 * Constructor for an analog trigger given a channel number.
069 * The default module is used in this case.
070 * @param channel the port to use for the analog trigger
071 */
072 public AnalogTrigger(final int channel) {
073 initTrigger(AnalogModule.getDefaultAnalogModule(), channel);
074 }
075
076 /**
077 * Constructor for an analog trigger given both the module number and channel.
078 * @param moduleNumber The number of the analog module to create this trigger on.
079 * @param channel the port to use for the analog trigger
080 */
081 public AnalogTrigger(final int moduleNumber, final int channel) {
082 initTrigger(moduleNumber, channel);
083 }
084
085 /**
086 * Construct an analog trigger given an analog channel.
087 * This should be used in the case of sharing an analog channel between the trigger
088 * and an analog input object.
089 * @param channel the AnalogChannel to use for the analog trigger
090 */
091 public AnalogTrigger(AnalogChannel channel) {
092 initTrigger(channel.getModuleNumber(), channel.getChannel());
093 }
094
095 /**
096 * Release the resources used by this object
097 */
098 public void free() {
099 triggers.free(m_index);
100 m_trigger.Release();
101 m_trigger = null;
102 }
103
104 /**
105 * Set the upper and lower limits of the analog trigger.
106 * The limits are given in ADC codes. If oversampling is used, the units must be scaled
107 * appropriately.
108 * @param lower the lower raw limit
109 * @param upper the upper raw limit
110 */
111 public void setLimitsRaw(final int lower, final int upper) {
112 if (lower > upper) {
113 throw new BoundaryException("Lower bound is greater than upper");
114 }
115 m_trigger.writeLowerLimit(lower);
116 m_trigger.writeUpperLimit(upper);
117 }
118
119 /**
120 * Set the upper and lower limits of the analog trigger.
121 * The limits are given as floating point voltage values.
122 * @param lower the lower voltage limit
123 * @param upper the upper voltage limit
124 */
125 public void setLimitsVoltage(double lower, double upper) {
126 if (lower > upper) {
127 throw new BoundaryException("Lower bound is greater than upper bound");
128 }
129 // TODO: This depends on the averaged setting. Only raw values will work as is.
130 m_trigger.writeLowerLimit(m_analogModule.voltsToValue(m_channel, lower));
131 m_trigger.writeUpperLimit(m_analogModule.voltsToValue(m_channel, upper));
132 }
133
134 /**
135 * Configure the analog trigger to use the averaged vs. raw values.
136 * If the value is true, then the averaged value is selected for the analog trigger, otherwise
137 * the immediate value is used.
138 * @param useAveragedValue true to use an averaged value, false otherwise
139 */
140 public void setAveraged(boolean useAveragedValue) {
141 if (m_trigger.readSourceSelect_Filter() && useAveragedValue) {
142 throw new AnalogTriggerException("Cannot set to Averaged if the analog trigger is filtered");
143 }
144 m_trigger.writeSourceSelect_Averaged(useAveragedValue);
145 }
146
147 /**
148 * Configure the analog trigger to use a filtered value.
149 * The analog trigger will operate with a 3 point average rejection filter. This is designed to
150 * help with 360 degree pot applications for the period where the pot crosses through zero.
151 * @param useFilteredValue true to use a filterd value, false otherwise
152 */
153 public void setFiltered(boolean useFilteredValue) {
154 if (m_trigger.readSourceSelect_Averaged() && useFilteredValue) {
155 throw new AnalogTriggerException("Cannot set to Filtered if the analog trigger is averaged");
156 }
157 m_trigger.writeSourceSelect_Filter(useFilteredValue);
158 }
159
160 /**
161 * Return the index of the analog trigger.
162 * This is the FPGA index of this analog trigger instance.
163 * @return The index of the analog trigger.
164 */
165 public int getIndex() {
166 return m_index;
167 }
168
169 /**
170 * Return the InWindow output of the analog trigger.
171 * True if the analog input is between the upper and lower limits.
172 * @return The InWindow output of the analog trigger.
173 */
174 public boolean getInWindow() {
175 return tAnalogTrigger.readOutput_InHysteresis((byte) m_index);
176 }
177
178 /**
179 * Return the TriggerState output of the analog trigger.
180 * True if above upper limit.
181 * False if below lower limit.
182 * If in Hysteresis, maintain previous state.
183 * @return The TriggerState output of the analog trigger.
184 */
185 public boolean getTriggerState() {
186 return tAnalogTrigger.readOutput_OverLimit((byte) m_index);
187 }
188
189 /**
190 * Creates an AnalogTriggerOutput object.
191 * Gets an output object that can be used for routing.
192 * Caller is responsible for deleting the AnalogTriggerOutput object.
193 * @param type An enum of the type of output object to create.
194 * @return A pointer to a new AnalogTriggerOutput object.
195 */
196 AnalogTriggerOutput createOutput(AnalogTriggerOutput.Type type) {
197 return new AnalogTriggerOutput(this, type);
198 }
199 }