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.communication.FRCNetworkCommunicationsLibrary.tResourceType;
011import edu.wpi.first.wpilibj.communication.UsageReporting;
012import edu.wpi.first.wpilibj.hal.AnalogJNI;
013import edu.wpi.first.wpilibj.hal.HALUtil;
014
015import java.nio.IntBuffer;
016
017/**
018 * Class to represent a specific output from an analog trigger. This class is
019 * used to get the current output value and also as a DigitalSource to provide
020 * routing of an output to digital subsystems on the FPGA such as Counter,
021 * Encoder, and Interrupt.
022 *
023 * The TriggerState output indicates the primary output value of the trigger. If
024 * the analog signal is less than the lower limit, the output is false. If the
025 * analog value is greater than the upper limit, then the output is true. If the
026 * analog value is in between, then the trigger output state maintains its most
027 * recent value.
028 *
029 * The InWindow output indicates whether or not the analog signal is inside the
030 * range defined by the limits.
031 *
032 * The RisingPulse and FallingPulse outputs detect an instantaneous transition
033 * from above the upper limit to below the lower limit, and vise versa. These
034 * pulses represent a rollover condition of a sensor and can be routed to an up
035 * / down couter or to interrupts. Because the outputs generate a pulse, they
036 * cannot be read directly. To help ensure that a rollover condition is not
037 * missed, there is an average rejection filter available that operates on the
038 * upper 8 bits of a 12 bit number and selects the nearest outlyer of 3 samples.
039 * This will reject a sample that is (due to averaging or sampling) errantly
040 * between the two limits. This filter will fail if more than one sample in a
041 * row is errantly in between the two limits. You may see this problem if
042 * attempting to use this feature with a mechanical rollover sensor, such as a
043 * 360 degree no-stop potentiometer without signal conditioning, because the
044 * rollover transition is not sharp / clean enough. Using the averaging engine
045 * may help with this, but rotational speeds of the sensor will then be limited.
046 */
047public class AnalogTriggerOutput extends DigitalSource {
048
049        /**
050         * Exceptions dealing with improper operation of the Analog trigger output
051         */
052        public class AnalogTriggerOutputException extends RuntimeException {
053
054                /**
055                 * Create a new exception with the given message
056                 *
057                 * @param message
058                 *            the message to pass with the exception
059                 */
060                public AnalogTriggerOutputException(String message) {
061                        super(message);
062                }
063
064        }
065
066        private final AnalogTrigger m_trigger;
067        private final AnalogTriggerType m_outputType;
068
069        /**
070         * Create an object that represents one of the four outputs from an analog
071         * trigger.
072         *
073         * Because this class derives from DigitalSource, it can be passed into
074         * routing functions for Counter, Encoder, etc.
075         *
076         * @param trigger
077         *            The trigger for which this is an output.
078         * @param outputType
079         *            An enum that specifies the output on the trigger to represent.
080         */
081        public AnalogTriggerOutput(AnalogTrigger trigger, final AnalogTriggerType outputType) {
082                if (trigger == null)
083                        throw new NullPointerException("Analog Trigger given was null");
084                if (outputType == null)
085                        throw new NullPointerException("Analog Trigger Type given was null");
086                m_trigger = trigger;
087                m_outputType = outputType;
088
089                UsageReporting.report(tResourceType.kResourceType_AnalogTriggerOutput,
090                                trigger.getIndex(), outputType.value);
091        }
092
093        @Override
094        public void free() {
095                
096        }
097
098        /**
099         * Get the state of the analog trigger output.
100         *
101         * @return The state of the analog trigger output.
102         */
103        public boolean get() {
104                IntBuffer status = IntBuffer.allocate(1);
105                byte value = AnalogJNI.getAnalogTriggerOutput(m_trigger.m_port,
106                                m_outputType.value, status);
107                HALUtil.checkStatus(status);
108                return value != 0;
109        }
110
111        @Override
112        public int getChannelForRouting() {
113                return (m_trigger.m_index << 2) + m_outputType.value;
114        }
115
116        @Override
117        public byte getModuleForRouting() {
118                return (byte) (m_trigger.m_index >> 2);
119        }
120
121        @Override
122        public boolean getAnalogTriggerForRouting() {
123                return true;
124        }
125
126        /**
127         * Defines the state in which the AnalogTrigger triggers
128         * @author jonathanleitschuh
129         */
130        public enum AnalogTriggerType{
131                kInWindow(AnalogJNI.AnalogTriggerType.kInWindow),
132                kState(AnalogJNI.AnalogTriggerType.kState),
133                kRisingPulse(AnalogJNI.AnalogTriggerType.kRisingPulse),
134                kFallingPulse(AnalogJNI.AnalogTriggerType.kFallingPulse);
135                
136                private final int value;
137                
138                private AnalogTriggerType(int value){
139                        this.value = value;
140                }
141        }
142}