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.tDIO;
012 import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
013 import edu.wpi.first.wpilibj.parsing.IInputOutput;
014 import edu.wpi.first.wpilibj.tables.ITable;
015 import edu.wpi.first.wpilibj.tables.ITableListener;
016
017 /**
018 * Class to write digital outputs.
019 * This class will wrtie digital outputs. Other devices
020 * that are implemented elsewhere will automatically
021 * allocate digital inputs and outputs as required.
022 */
023 public class DigitalOutput extends DigitalSource implements IInputOutput, LiveWindowSendable {
024
025 private int m_channel;
026 private int m_pwmGenerator;
027 private DigitalModule m_module;
028
029 private void initDigitalOutput(int moduleNumber, int channel) {
030 m_channel = channel;
031 m_pwmGenerator = ~0;
032 m_module = DigitalModule.getInstance(moduleNumber);
033 m_module.allocateDIO(m_channel, false);
034
035 UsageReporting.report(UsageReporting.kResourceType_DigitalOutput, channel, moduleNumber-1);
036 }
037
038 /**
039 * Create an instance of a digital output.
040 * Create an instance of a digital output given a module number and channel.
041 * @param moduleNumber The number of the digital module to use
042 * @param channel the port to use for the digital output
043 */
044 public DigitalOutput(int moduleNumber, int channel) {
045 initDigitalOutput(moduleNumber, channel);
046 }
047
048 /**
049 * Create an instance of a digital output.
050 * Create a digital output given a channel. The default module is used.
051 * @param channel the port to use for the digital output
052 */
053 public DigitalOutput(int channel) {
054 initDigitalOutput(getDefaultDigitalModule(), channel);
055 }
056
057 /**
058 * Free the resources associated with a digital output.
059 */
060 public void free() {
061 disablePWM();
062 m_module.freeDIO(m_channel);
063 }
064
065 /**
066 * Set the value of a digital output.
067 * @param value true is on, off is false
068 */
069 public void set(boolean value) {
070 m_module.setDIO(m_channel, value);
071 }
072
073 /**
074 * @return The GPIO channel number that this object represents.
075 */
076 public int getChannel() {
077 return m_channel;
078 }
079
080 /**
081 * Output a single pulse on the digital output line.
082 * Send a single pulse on the digital output line where the pulse diration is specified in seconds.
083 * Maximum pulse length is 0.0016 seconds.
084 * @param length The pulselength in seconds
085 */
086 public void pulse(double length) {
087 m_module.pulse(m_channel, (char) (1e9 * length / (tDIO.readLoopTiming() * 25)));
088 }
089
090 /**
091 * Determine if the pulse is still going.
092 * Determine if a previously started pulse is still going.
093 * @return true if pulsing
094 */
095 public boolean isPulsing() {
096 return m_module.isPulsing(m_channel);
097 }
098
099 /**
100 * Change the PWM frequency of the PWM output on a Digital Output line.
101 *
102 * The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is logarithmic.
103 *
104 * There is only one PWM frequency per digital module.
105 *
106 * @param rate The frequency to output all digital output PWM signals on this module.
107 */
108 public void setPWMRate(double rate)
109 {
110 m_module.setDO_PWMRate(rate);
111 }
112
113 /**
114 * Enable a PWM Output on this line.
115 *
116 * Allocate one of the 4 DO PWM generator resources from this module.
117 *
118 * Supply the initial duty-cycle to output so as to avoid a glitch when first starting.
119 *
120 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
121 * but is reduced the higher the frequency of the PWM signal is.
122 *
123 * @param initialDutyCycle The duty-cycle to start generating. [0..1]
124 */
125 public void enablePWM(double initialDutyCycle) {
126 if (m_pwmGenerator != ~0) return;
127 m_pwmGenerator = m_module.allocateDO_PWM();
128 m_module.setDO_PWMDutyCycle(m_pwmGenerator, initialDutyCycle);
129 m_module.setDO_PWMOutputChannel(m_pwmGenerator, m_channel);
130 }
131
132 /**
133 * Change this line from a PWM output back to a static Digital Output line.
134 *
135 * Free up one of the 4 DO PWM generator resources that were in use.
136 */
137 public void disablePWM() {
138 // Disable the output by routing to a dead bit.
139 m_module.setDO_PWMOutputChannel(m_pwmGenerator, kDigitalChannels);
140 m_module.freeDO_PWM(m_pwmGenerator);
141 m_pwmGenerator = ~0;
142 }
143
144 /**
145 * Change the duty-cycle that is being generated on the line.
146 *
147 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
148 * but is reduced the higher the frequency of the PWM signal is.
149 *
150 * @param dutyCycle The duty-cycle to change to. [0..1]
151 */
152 public void updateDutyCycle(double dutyCycle) {
153 m_module.setDO_PWMDutyCycle(m_pwmGenerator, dutyCycle);
154 }
155
156 /**
157 * @return The value to be written to the channel field of a routing mux.
158 */
159 public int getChannelForRouting() {
160 return DigitalModule.remapDigitalChannel(getChannel() - 1);
161 }
162
163 /**
164 * @return The value to be written to the module field of a routing mux.
165 */
166 public int getModuleForRouting() {
167 return m_module.getModuleNumber() - 1;
168 }
169
170 /**
171 * @return The value to be written to the analog trigger field of a routing mux.
172 */
173 public boolean getAnalogTriggerForRouting() {
174 return false;
175 }
176 /*
177 * Live Window code, only does anything if live window is activated.
178 */
179 public String getSmartDashboardType(){
180 return "Digital Output";
181 }
182 private ITable m_table;
183 private ITableListener m_table_listener;
184
185 /**
186 * {@inheritDoc}
187 */
188 public void initTable(ITable subtable) {
189 m_table = subtable;
190 updateTable();
191 }
192
193 /**
194 * {@inheritDoc}
195 */
196 public ITable getTable(){
197 return m_table;
198 }
199
200 /**
201 * {@inheritDoc}
202 */
203 public void updateTable() {
204 // TODO: Put current value.
205 }
206
207 /**
208 * {@inheritDoc}
209 */
210 public void startLiveWindowMode() {
211 m_table_listener = new ITableListener() {
212 public void valueChanged(ITable itable, String key, Object value, boolean bln) {
213 set(((Boolean) value).booleanValue());
214 }
215 };
216 m_table.addTableListener("Value", m_table_listener, true);
217 }
218
219 /**
220 * {@inheritDoc}
221 */
222 public void stopLiveWindowMode() {
223 // TODO: Broken, should only remove the listener from "Value" only.
224 m_table.removeTableListener(m_table_listener);
225 }
226 }