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