blob: b05c6b101ee14bdb467505fe6d95b307e2dd1600 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. 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 "frc/DigitalOutput.h"
9
10#include <limits>
11#include <utility>
12
13#include <hal/DIO.h>
14#include <hal/HAL.h>
15#include <hal/Ports.h>
16
17#include "frc/SensorUtil.h"
18#include "frc/WPIErrors.h"
19#include "frc/smartdashboard/SendableBuilder.h"
20
21using namespace frc;
22
23DigitalOutput::DigitalOutput(int channel) {
24 m_pwmGenerator = HAL_kInvalidHandle;
25 if (!SensorUtil::CheckDigitalChannel(channel)) {
26 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange,
27 "Digital Channel " + wpi::Twine(channel));
28 m_channel = std::numeric_limits<int>::max();
29 return;
30 }
31 m_channel = channel;
32
33 int32_t status = 0;
34 m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), false, &status);
35 if (status != 0) {
36 wpi_setErrorWithContextRange(status, 0, HAL_GetNumDigitalChannels(),
37 channel, HAL_GetErrorMessage(status));
38 m_channel = std::numeric_limits<int>::max();
39 m_handle = HAL_kInvalidHandle;
40 return;
41 }
42
43 HAL_Report(HALUsageReporting::kResourceType_DigitalOutput, channel);
44 SetName("DigitalOutput", channel);
45}
46
47DigitalOutput::~DigitalOutput() {
48 if (StatusIsFatal()) return;
49 // Disable the PWM in case it was running.
50 DisablePWM();
51
52 HAL_FreeDIOPort(m_handle);
53}
54
55DigitalOutput::DigitalOutput(DigitalOutput&& rhs)
56 : ErrorBase(std::move(rhs)),
57 SendableBase(std::move(rhs)),
58 m_channel(std::move(rhs.m_channel)),
59 m_pwmGenerator(std::move(rhs.m_pwmGenerator)) {
60 std::swap(m_handle, rhs.m_handle);
61}
62
63DigitalOutput& DigitalOutput::operator=(DigitalOutput&& rhs) {
64 ErrorBase::operator=(std::move(rhs));
65 SendableBase::operator=(std::move(rhs));
66
67 m_channel = std::move(rhs.m_channel);
68 std::swap(m_handle, rhs.m_handle);
69 m_pwmGenerator = std::move(rhs.m_pwmGenerator);
70
71 return *this;
72}
73
74void DigitalOutput::Set(bool value) {
75 if (StatusIsFatal()) return;
76
77 int32_t status = 0;
78 HAL_SetDIO(m_handle, value, &status);
79 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
80}
81
82bool DigitalOutput::Get() const {
83 if (StatusIsFatal()) return false;
84
85 int32_t status = 0;
86 bool val = HAL_GetDIO(m_handle, &status);
87 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
88 return val;
89}
90
91int DigitalOutput::GetChannel() const { return m_channel; }
92
93void DigitalOutput::Pulse(double length) {
94 if (StatusIsFatal()) return;
95
96 int32_t status = 0;
97 HAL_Pulse(m_handle, length, &status);
98 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
99}
100
101bool DigitalOutput::IsPulsing() const {
102 if (StatusIsFatal()) return false;
103
104 int32_t status = 0;
105 bool value = HAL_IsPulsing(m_handle, &status);
106 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
107 return value;
108}
109
110void DigitalOutput::SetPWMRate(double rate) {
111 if (StatusIsFatal()) return;
112
113 int32_t status = 0;
114 HAL_SetDigitalPWMRate(rate, &status);
115 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
116}
117
118void DigitalOutput::EnablePWM(double initialDutyCycle) {
119 if (m_pwmGenerator != HAL_kInvalidHandle) return;
120
121 int32_t status = 0;
122
123 if (StatusIsFatal()) return;
124 m_pwmGenerator = HAL_AllocateDigitalPWM(&status);
125 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
126
127 if (StatusIsFatal()) return;
128 HAL_SetDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle, &status);
129 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
130
131 if (StatusIsFatal()) return;
132 HAL_SetDigitalPWMOutputChannel(m_pwmGenerator, m_channel, &status);
133 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
134}
135
136void DigitalOutput::DisablePWM() {
137 if (StatusIsFatal()) return;
138 if (m_pwmGenerator == HAL_kInvalidHandle) return;
139
140 int32_t status = 0;
141
142 // Disable the output by routing to a dead bit.
143 HAL_SetDigitalPWMOutputChannel(m_pwmGenerator, SensorUtil::kDigitalChannels,
144 &status);
145 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
146
147 HAL_FreeDigitalPWM(m_pwmGenerator, &status);
148 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
149
150 m_pwmGenerator = HAL_kInvalidHandle;
151}
152
153void DigitalOutput::UpdateDutyCycle(double dutyCycle) {
154 if (StatusIsFatal()) return;
155
156 int32_t status = 0;
157 HAL_SetDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle, &status);
158 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
159}
160
161void DigitalOutput::InitSendable(SendableBuilder& builder) {
162 builder.SetSmartDashboardType("Digital Output");
163 builder.AddBooleanProperty("Value", [=]() { return Get(); },
164 [=](bool value) { Set(value); });
165}