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 }