blob: f4b278179cd49b69bab1e87ac048b2fdfcd0d82d [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. 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 the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "frc971/wpilib/ahal/DigitalOutput.h"
9
10#include <limits>
11#include <sstream>
12
Austin Schuhf6b94632019-02-02 22:11:27 -080013#include "hal/DIO.h"
14#include "hal/HAL.h"
15#include "hal/Ports.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080016#include "frc971/wpilib/ahal/WPIErrors.h"
17
18using namespace frc;
19
20/**
21 * Create an instance of a digital output.
22 *
23 * Create a digital output given a channel.
24 *
25 * @param channel The digital channel 0-9 are on-board, 10-25 are on the MXP
26 * port
27 */
28DigitalOutput::DigitalOutput(int channel) {
29 std::stringstream buf;
30
31 m_pwmGenerator = HAL_kInvalidHandle;
32 if (!CheckDigitalChannel(channel)) {
33 buf << "Digital Channel " << channel;
34 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
35 m_channel = std::numeric_limits<int>::max();
36 return;
37 }
38 m_channel = channel;
39
40 int32_t status = 0;
41 m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), false, &status);
42 if (status != 0) {
43 wpi_setErrorWithContextRange(status, 0, HAL_GetNumDigitalChannels(),
44 channel, HAL_GetErrorMessage(status));
45 m_channel = std::numeric_limits<int>::max();
46 m_handle = HAL_kInvalidHandle;
47 return;
48 }
49
50 HAL_Report(HALUsageReporting::kResourceType_DigitalOutput, channel);
51}
52
53/**
54 * Free the resources associated with a digital output.
55 */
56DigitalOutput::~DigitalOutput() {
57 if (StatusIsFatal()) return;
58 // Disable the PWM in case it was running.
59 DisablePWM();
60
61 HAL_FreeDIOPort(m_handle);
62}
63
64/**
65 * Set the value of a digital output.
66 *
67 * Set the value of a digital output to either one (true) or zero (false).
68 *
69 * @param value 1 (true) for high, 0 (false) for disabled
70 */
71void DigitalOutput::Set(bool value) {
72 if (StatusIsFatal()) return;
73
74 int32_t status = 0;
75 HAL_SetDIO(m_handle, value, &status);
76 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
77}
78
79/**
80 * Gets the value being output from the Digital Output.
81 *
82 * @return the state of the digital output.
83 */
84bool DigitalOutput::Get() const {
85 if (StatusIsFatal()) return false;
86
87 int32_t status = 0;
88 bool val = HAL_GetDIO(m_handle, &status);
89 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
90 return val;
91}
92
93/**
94 * @return The GPIO channel number that this object represents.
95 */
96int DigitalOutput::GetChannel() const { return m_channel; }
97
98/**
99 * Output a single pulse on the digital output line.
100 *
101 * Send a single pulse on the digital output line where the pulse duration is
102 * specified in seconds. Maximum pulse length is 0.0016 seconds.
103 *
104 * @param length The pulse length in seconds
105 */
106void DigitalOutput::Pulse(double length) {
107 if (StatusIsFatal()) return;
108
109 int32_t status = 0;
110 HAL_Pulse(m_handle, length, &status);
111 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
112}
113
114/**
115 * Determine if the pulse is still going.
116 *
117 * Determine if a previously started pulse is still going.
118 */
119bool DigitalOutput::IsPulsing() const {
120 if (StatusIsFatal()) return false;
121
122 int32_t status = 0;
123 bool value = HAL_IsPulsing(m_handle, &status);
124 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
125 return value;
126}
127
128/**
129 * Change the PWM frequency of the PWM output on a Digital Output line.
130 *
131 * The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is
132 * logarithmic.
133 *
134 * There is only one PWM frequency for all digital channels.
135 *
136 * @param rate The frequency to output all digital output PWM signals.
137 */
138void DigitalOutput::SetPWMRate(double rate) {
139 if (StatusIsFatal()) return;
140
141 int32_t status = 0;
142 HAL_SetDigitalPWMRate(rate, &status);
143 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
144}
145
146/**
147 * Enable a PWM Output on this line.
148 *
149 * Allocate one of the 6 DO PWM generator resources from this module.
150 *
151 * Supply the initial duty-cycle to output so as to avoid a glitch when first
152 * starting.
153 *
154 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
155 * but is reduced the higher the frequency of the PWM signal is.
156 *
157 * @param initialDutyCycle The duty-cycle to start generating. [0..1]
158 */
159void DigitalOutput::EnablePWM(double initialDutyCycle) {
160 if (m_pwmGenerator != HAL_kInvalidHandle) return;
161
162 int32_t status = 0;
163
164 if (StatusIsFatal()) return;
165 m_pwmGenerator = HAL_AllocateDigitalPWM(&status);
166 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
167
168 if (StatusIsFatal()) return;
169 HAL_SetDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle, &status);
170 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
171
172 if (StatusIsFatal()) return;
173 HAL_SetDigitalPWMOutputChannel(m_pwmGenerator, m_channel, &status);
174 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
175}
176
177/**
178 * Change this line from a PWM output back to a static Digital Output line.
179 *
180 * Free up one of the 6 DO PWM generator resources that were in use.
181 */
182void DigitalOutput::DisablePWM() {
183 if (StatusIsFatal()) return;
184 if (m_pwmGenerator == HAL_kInvalidHandle) return;
185
186 int32_t status = 0;
187
188 // Disable the output by routing to a dead bit.
189 HAL_SetDigitalPWMOutputChannel(m_pwmGenerator, kDigitalChannels, &status);
190 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
191
192 HAL_FreeDigitalPWM(m_pwmGenerator, &status);
193 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
194
195 m_pwmGenerator = HAL_kInvalidHandle;
196}
197
198/**
199 * Change the duty-cycle that is being generated on the line.
200 *
201 * The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less)
202 * but is reduced the higher the frequency of the PWM signal is.
203 *
204 * @param dutyCycle The duty-cycle to change to. [0..1]
205 */
206void DigitalOutput::UpdateDutyCycle(double dutyCycle) {
207 if (StatusIsFatal()) return;
208
209 int32_t status = 0;
210 HAL_SetDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle, &status);
211 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
212}
213
214/**
215 * @return The HAL Handle to the specified source.
216 */
217HAL_Handle DigitalOutput::GetPortHandleForRouting() const { return m_handle; }
218
219/**
220 * Is source an AnalogTrigger
221 */
222bool DigitalOutput::IsAnalogTrigger() const { return false; }
223
224/**
225 * @return The type of analog trigger output to be used. 0 for Digitals
226 */
227AnalogTriggerType DigitalOutput::GetAnalogTriggerTypeForRouting() const {
228 return (AnalogTriggerType)0;
229}