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