blob: d74f93b008bbee0feaff905d47a494adbcde4102 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5/*----------------------------------------------------------------------------*/
6
7#include "DigitalOutput.h"
8#include "Resource.h"
9#include "WPIErrors.h"
10
11#include <limits>
12#include <sstream>
13
14/**
15 * Create an instance of a digital output.
16 * Create a digital output given a channel.
17 *
18 * @param channel The digital channel 0-9 are on-board, 10-25 are on the MXP
19 * port
20 */
21DigitalOutput::DigitalOutput(uint32_t channel) {
22 std::stringstream buf;
23
24 m_pwmGenerator = (void *)std::numeric_limits<uint32_t>::max();
25 if (!CheckDigitalChannel(channel)) {
26 buf << "Digital Channel " << channel;
27 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
28 m_channel = std::numeric_limits<uint32_t>::max();
29 return;
30 }
31 m_channel = channel;
32
33 int32_t status = 0;
34 allocateDIO(m_digital_ports[channel], false, &status);
35 wpi_setErrorWithContext(status, getHALErrorMessage(status));
36
37 HALReport(HALUsageReporting::kResourceType_DigitalOutput, channel);
38}
39
40/**
41 * Free the resources associated with a digital output.
42 */
43DigitalOutput::~DigitalOutput() {
44 if (m_table != nullptr) m_table->RemoveTableListener(this);
45 if (StatusIsFatal()) return;
46 // Disable the PWM in case it was running.
47 DisablePWM();
48
49 int32_t status = 0;
50 freeDIO(m_digital_ports[m_channel], &status);
51 wpi_setErrorWithContext(status, getHALErrorMessage(status));
52}
53
54/**
55 * Set the value of a digital output.
56 * Set the value of a digital output to either one (true) or zero (false).
57 * @param value 1 (true) for high, 0 (false) for disabled
58 */
59void DigitalOutput::Set(uint32_t value) {
60 if (StatusIsFatal()) return;
61
62 int32_t status = 0;
63 setDIO(m_digital_ports[m_channel], value, &status);
64 wpi_setErrorWithContext(status, getHALErrorMessage(status));
65}
66
67/**
68 * @return The GPIO channel number that this object represents.
69 */
70uint32_t DigitalOutput::GetChannel() const { return m_channel; }
71
72/**
73 * Output a single pulse on the digital output line.
74 * Send a single pulse on the digital output line where the pulse duration is
75 * specified in seconds.
76 * Maximum pulse length is 0.0016 seconds.
77 * @param length The pulselength in seconds
78 */
79void DigitalOutput::Pulse(float length) {
80 if (StatusIsFatal()) return;
81
82 int32_t status = 0;
83 pulse(m_digital_ports[m_channel], length, &status);
84 wpi_setErrorWithContext(status, getHALErrorMessage(status));
85}
86
87/**
88 * Determine if the pulse is still going.
89 * Determine if a previously started pulse is still going.
90 */
91bool DigitalOutput::IsPulsing() const {
92 if (StatusIsFatal()) return false;
93
94 int32_t status = 0;
95 bool value = isPulsing(m_digital_ports[m_channel], &status);
96 wpi_setErrorWithContext(status, getHALErrorMessage(status));
97 return value;
98}
99
100/**
101 * Change the PWM frequency of the PWM output on a Digital Output line.
102 *
103 * The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is
104 * logarithmic.
105 *
106 * There is only one PWM frequency for all digital channels.
107 *
108 * @param rate The frequency to output all digital output PWM signals.
109 */
110void DigitalOutput::SetPWMRate(float rate) {
111 if (StatusIsFatal()) return;
112
113 int32_t status = 0;
114 setPWMRate(rate, &status);
115 wpi_setErrorWithContext(status, getHALErrorMessage(status));
116}
117
118/**
119 * Enable a PWM Output on this line.
120 *
121 * Allocate one of the 6 DO PWM generator resources from this module.
122 *
123 * Supply the initial duty-cycle to output so as to avoid a glitch when first
124 * starting.
125 *
126 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
127 * but is reduced the higher the frequency of the PWM signal is.
128 *
129 * @param initialDutyCycle The duty-cycle to start generating. [0..1]
130 */
131void DigitalOutput::EnablePWM(float initialDutyCycle) {
132 if (m_pwmGenerator != (void *)std::numeric_limits<uint32_t>::max()) return;
133
134 int32_t status = 0;
135
136 if (StatusIsFatal()) return;
137 m_pwmGenerator = allocatePWM(&status);
138 wpi_setErrorWithContext(status, getHALErrorMessage(status));
139
140 if (StatusIsFatal()) return;
141 setPWMDutyCycle(m_pwmGenerator, initialDutyCycle, &status);
142 wpi_setErrorWithContext(status, getHALErrorMessage(status));
143
144 if (StatusIsFatal()) return;
145 setPWMOutputChannel(m_pwmGenerator, m_channel, &status);
146 wpi_setErrorWithContext(status, getHALErrorMessage(status));
147}
148
149/**
150 * Change this line from a PWM output back to a static Digital Output line.
151 *
152 * Free up one of the 6 DO PWM generator resources that were in use.
153 */
154void DigitalOutput::DisablePWM() {
155 if (StatusIsFatal()) return;
156 if (m_pwmGenerator == (void *)std::numeric_limits<uint32_t>::max()) return;
157
158 int32_t status = 0;
159
160 // Disable the output by routing to a dead bit.
161 setPWMOutputChannel(m_pwmGenerator, kDigitalChannels, &status);
162 wpi_setErrorWithContext(status, getHALErrorMessage(status));
163
164 freePWM(m_pwmGenerator, &status);
165 wpi_setErrorWithContext(status, getHALErrorMessage(status));
166
167 m_pwmGenerator = (void *)std::numeric_limits<uint32_t>::max();
168}
169
170/**
171 * Change the duty-cycle that is being generated on the line.
172 *
173 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
174 * but is reduced the higher the frequency of the PWM signal is.
175 *
176 * @param dutyCycle The duty-cycle to change to. [0..1]
177 */
178void DigitalOutput::UpdateDutyCycle(float dutyCycle) {
179 if (StatusIsFatal()) return;
180
181 int32_t status = 0;
182 setPWMDutyCycle(m_pwmGenerator, dutyCycle, &status);
183 wpi_setErrorWithContext(status, getHALErrorMessage(status));
184}
185
186/**
187 * @return The value to be written to the channel field of a routing mux.
188 */
189uint32_t DigitalOutput::GetChannelForRouting() const { return GetChannel(); }
190
191/**
192 * @return The value to be written to the module field of a routing mux.
193 */
194uint32_t DigitalOutput::GetModuleForRouting() const { return 0; }
195
196/**
197 * @return The value to be written to the analog trigger field of a routing mux.
198 */
199bool DigitalOutput::GetAnalogTriggerForRouting() const { return false; }
200
201void DigitalOutput::ValueChanged(ITable* source, llvm::StringRef key,
202 std::shared_ptr<nt::Value> value, bool isNew) {
203 if (!value->IsBoolean()) return;
204 Set(value->GetBoolean());
205}
206
207void DigitalOutput::UpdateTable() {}
208
209void DigitalOutput::StartLiveWindowMode() {
210 if (m_table != nullptr) {
211 m_table->AddTableListener("Value", this, true);
212 }
213}
214
215void DigitalOutput::StopLiveWindowMode() {
216 if (m_table != nullptr) {
217 m_table->RemoveTableListener(this);
218 }
219}
220
221std::string DigitalOutput::GetSmartDashboardType() const {
222 return "Digital Output";
223}
224
225void DigitalOutput::InitTable(std::shared_ptr<ITable> subTable) {
226 m_table = subTable;
227 UpdateTable();
228}
229
230std::shared_ptr<ITable> DigitalOutput::GetTable() const { return m_table; }