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