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 }