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
014 /**
015 * Class to represent a specific output from an analog trigger.
016 * This class is used to get the current output value and also as a DigitalSource
017 * to provide routing of an output to digital subsystems on the FPGA such as
018 * Counter, Encoder, and Interrupt.
019 *
020 * The TriggerState output indicates the primary output value of the trigger. If the analog
021 * signal is less than the lower limit, the output is false. If the analog value is greater
022 * than the upper limit, then the output is true. If the analog value is in between, then
023 * the trigger output state maintains its most recent value.
024 *
025 * The InWindow output indicates whether or not the analog signal is inside the range defined
026 * by the limits.
027 *
028 * The RisingPulse and FallingPulse outputs detect an instantaneous transition from above the
029 * upper limit to below the lower limit, and vise versa. These pulses represent a rollover
030 * condition of a sensor and can be routed to an up / down couter or to interrupts. Because
031 * the outputs generate a pulse, they cannot be read directly. To help ensure that a rollover
032 * condition is not missed, there is an average rejection filter available that operates on the
033 * upper 8 bits of a 12 bit number and selects the nearest outlyer of 3 samples. This will reject
034 * a sample that is (due to averaging or sampling) errantly between the two limits. This filter
035 * will fail if more than one sample in a row is errantly in between the two limits. You may see
036 * this problem if attempting to use this feature with a mechanical rollover sensor, such as a
037 * 360 degree no-stop potentiometer without signal conditioning, because the rollover transition
038 * is not sharp / clean enough. Using the averaging engine may help with this, but rotational speeds of
039 * the sensor will then be limited.
040 */
041 public class AnalogTriggerOutput extends DigitalSource implements IInputOutput{
042
043 /**
044 * Exceptions dealing with improper operation of the Analog trigger output
045 */
046 public class AnalogTriggerOutputException extends RuntimeException {
047
048 /**
049 * Create a new exception with the given message
050 * @param message the message to pass with the exception
051 */
052 public AnalogTriggerOutputException(String message) {
053 super(message);
054 }
055
056 }
057
058 /**
059 * Type determines under what state the analog trigger evaluates to true or
060 * false
061 */
062 public static class Type {
063
064 /**
065 * The integer value representing this enumeration
066 */
067 public final int value;
068 static final int kInWindow_val = 0;
069 static final int kTypeState_val = 1;
070 static final int kRisingPulse_val = 2;
071 static final int kFallingPulse_val = 3;
072 /**
073 * outputType: true if in the trigger window
074 */
075 public static final Type kInWindow = new Type(kInWindow_val);
076 /**
077 * outputType: true if above the upper limit, false if below the lower limit
078 * maintain previous state otherwise
079 */
080 public static final Type kTypeState = new Type(kTypeState_val);
081 /**
082 * outputType: true on a rising edge
083 */
084 public static final Type kRisingPulse = new Type(kRisingPulse_val);
085 /**
086 * outputType: true on a falling edge
087 */
088 public static final Type kFallingPulse = new Type(kFallingPulse_val);
089
090 private Type(int value) {
091 this.value = value;
092 }
093 }
094 private AnalogTrigger m_trigger;
095 private Type m_outputType;
096
097 /**
098 * Create an object that represents one of the four outputs from an analog trigger.
099 *
100 * Because this class derives from DigitalSource, it can be passed into routing functions
101 * for Counter, Encoder, etc.
102 *
103 * @param trigger The trigger for which this is an output.
104 * @param outputType An enum that specifies the output on the trigger to represent.
105 */
106 public AnalogTriggerOutput(AnalogTrigger trigger, final Type outputType) {
107 if (trigger == null)
108 throw new NullPointerException("Analog Trigger given was null");
109 m_trigger = trigger;
110 m_outputType = outputType;
111
112 UsageReporting.report(UsageReporting.kResourceType_AnalogTriggerOutput, trigger.getIndex(), outputType.value);
113 }
114
115 public void free() {
116 }
117
118 /**
119 * Get the state of the analog trigger output.
120 * @return The state of the analog trigger output.
121 */
122 public boolean get() {
123 switch (m_outputType.value) {
124 case Type.kInWindow_val:
125 return tAnalogTrigger.readOutput_InHysteresis((byte) m_trigger.m_index);
126 case Type.kTypeState_val:
127 return tAnalogTrigger.readOutput_OverLimit((byte) m_trigger.m_index);
128 case Type.kRisingPulse_val:
129 case Type.kFallingPulse_val:
130 throw new AnalogTriggerOutputException("Cannot get the state of the analog trigger output if it is configured for a rising or falling edge");
131 }
132 // Should never get here.
133 return false;
134 }
135
136 public int getChannelForRouting() {
137 return (m_trigger.m_index << 2) + m_outputType.value;
138 }
139
140 public int getModuleForRouting() {
141 return m_trigger.m_index >> 2;
142 }
143
144 public boolean getAnalogTriggerForRouting() {
145 return true;
146 }
147
148 /**
149 * Request interrupts asynchronously on this digital input.
150 * @param handler the interrupt service routine
151 * @param param a parameter for the ISR
152 */
153 // public void requestInterrupts(/*tInterruptHandler*/Object handler, Object param) {
154 //TODO: add interrupt support
155 //TODO: throw exception
156 // }
157
158 /**
159 * Request interrupts synchronously on this digital input.
160 */
161 // public void requestInterrupts() {
162 //TODO: throw exception
163 // }
164 }