blob: 9128d20250e970b0b0045523f03520327278d941 [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/Relay.h"
9
10#include <utility>
11
12#include <hal/HAL.h>
13#include <hal/Ports.h>
14#include <hal/Relay.h>
15#include <wpi/raw_ostream.h>
16
17#include "frc/SensorUtil.h"
18#include "frc/WPIErrors.h"
19#include "frc/smartdashboard/SendableBuilder.h"
20
21using namespace frc;
22
23Relay::Relay(int channel, Relay::Direction direction)
24 : m_channel(channel), m_direction(direction) {
25 if (!SensorUtil::CheckRelayChannel(m_channel)) {
26 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange,
27 "Relay Channel " + wpi::Twine(m_channel));
28 return;
29 }
30
31 HAL_PortHandle portHandle = HAL_GetPort(channel);
32
33 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
34 int32_t status = 0;
35 m_forwardHandle = HAL_InitializeRelayPort(portHandle, true, &status);
36 if (status != 0) {
37 wpi_setErrorWithContextRange(status, 0, HAL_GetNumRelayChannels(),
38 channel, HAL_GetErrorMessage(status));
39 m_forwardHandle = HAL_kInvalidHandle;
40 m_reverseHandle = HAL_kInvalidHandle;
41 return;
42 }
43 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel);
44 }
45 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
46 int32_t status = 0;
47 m_reverseHandle = HAL_InitializeRelayPort(portHandle, false, &status);
48 if (status != 0) {
49 wpi_setErrorWithContextRange(status, 0, HAL_GetNumRelayChannels(),
50 channel, HAL_GetErrorMessage(status));
51 m_forwardHandle = HAL_kInvalidHandle;
52 m_reverseHandle = HAL_kInvalidHandle;
53 return;
54 }
55
56 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 128);
57 }
58
59 int32_t status = 0;
60 if (m_forwardHandle != HAL_kInvalidHandle) {
61 HAL_SetRelay(m_forwardHandle, false, &status);
62 if (status != 0) {
63 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
64 m_forwardHandle = HAL_kInvalidHandle;
65 m_reverseHandle = HAL_kInvalidHandle;
66 return;
67 }
68 }
69 if (m_reverseHandle != HAL_kInvalidHandle) {
70 HAL_SetRelay(m_reverseHandle, false, &status);
71 if (status != 0) {
72 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
73 m_forwardHandle = HAL_kInvalidHandle;
74 m_reverseHandle = HAL_kInvalidHandle;
75 return;
76 }
77 }
78
79 SetName("Relay", m_channel);
80}
81
82Relay::~Relay() {
83 int32_t status = 0;
84 HAL_SetRelay(m_forwardHandle, false, &status);
85 HAL_SetRelay(m_reverseHandle, false, &status);
86 // ignore errors, as we want to make sure a free happens.
87 if (m_forwardHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_forwardHandle);
88 if (m_reverseHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_reverseHandle);
89}
90
91Relay::Relay(Relay&& rhs)
92 : MotorSafety(std::move(rhs)),
93 SendableBase(std::move(rhs)),
94 m_channel(std::move(rhs.m_channel)),
95 m_direction(std::move(rhs.m_direction)) {
96 std::swap(m_forwardHandle, rhs.m_forwardHandle);
97 std::swap(m_reverseHandle, rhs.m_reverseHandle);
98}
99
100Relay& Relay::operator=(Relay&& rhs) {
101 MotorSafety::operator=(std::move(rhs));
102 SendableBase::operator=(std::move(rhs));
103
104 m_channel = std::move(rhs.m_channel);
105 m_direction = std::move(rhs.m_direction);
106 std::swap(m_forwardHandle, rhs.m_forwardHandle);
107 std::swap(m_reverseHandle, rhs.m_reverseHandle);
108
109 return *this;
110}
111
112void Relay::Set(Relay::Value value) {
113 if (StatusIsFatal()) return;
114
115 int32_t status = 0;
116
117 switch (value) {
118 case kOff:
119 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
120 HAL_SetRelay(m_forwardHandle, false, &status);
121 }
122 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
123 HAL_SetRelay(m_reverseHandle, false, &status);
124 }
125 break;
126 case kOn:
127 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
128 HAL_SetRelay(m_forwardHandle, true, &status);
129 }
130 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
131 HAL_SetRelay(m_reverseHandle, true, &status);
132 }
133 break;
134 case kForward:
135 if (m_direction == kReverseOnly) {
136 wpi_setWPIError(IncompatibleMode);
137 break;
138 }
139 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
140 HAL_SetRelay(m_forwardHandle, true, &status);
141 }
142 if (m_direction == kBothDirections) {
143 HAL_SetRelay(m_reverseHandle, false, &status);
144 }
145 break;
146 case kReverse:
147 if (m_direction == kForwardOnly) {
148 wpi_setWPIError(IncompatibleMode);
149 break;
150 }
151 if (m_direction == kBothDirections) {
152 HAL_SetRelay(m_forwardHandle, false, &status);
153 }
154 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
155 HAL_SetRelay(m_reverseHandle, true, &status);
156 }
157 break;
158 }
159
160 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
161}
162
163Relay::Value Relay::Get() const {
164 int32_t status;
165
166 if (m_direction == kForwardOnly) {
167 if (HAL_GetRelay(m_forwardHandle, &status)) {
168 return kOn;
169 } else {
170 return kOff;
171 }
172 } else if (m_direction == kReverseOnly) {
173 if (HAL_GetRelay(m_reverseHandle, &status)) {
174 return kOn;
175 } else {
176 return kOff;
177 }
178 } else {
179 if (HAL_GetRelay(m_forwardHandle, &status)) {
180 if (HAL_GetRelay(m_reverseHandle, &status)) {
181 return kOn;
182 } else {
183 return kForward;
184 }
185 } else {
186 if (HAL_GetRelay(m_reverseHandle, &status)) {
187 return kReverse;
188 } else {
189 return kOff;
190 }
191 }
192 }
193
194 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
195}
196
197int Relay::GetChannel() const { return m_channel; }
198
199void Relay::StopMotor() { Set(kOff); }
200
201void Relay::GetDescription(wpi::raw_ostream& desc) const {
202 desc << "Relay " << GetChannel();
203}
204
205void Relay::InitSendable(SendableBuilder& builder) {
206 builder.SetSmartDashboardType("Relay");
207 builder.SetActuator(true);
208 builder.SetSafeState([=]() { Set(kOff); });
209 builder.AddSmallStringProperty(
210 "Value",
211 [=](wpi::SmallVectorImpl<char>& buf) -> wpi::StringRef {
212 switch (Get()) {
213 case kOn:
214 return "On";
215 case kForward:
216 return "Forward";
217 case kReverse:
218 return "Reverse";
219 default:
220 return "Off";
221 }
222 },
223 [=](wpi::StringRef value) {
224 if (value == "Off")
225 Set(kOff);
226 else if (value == "Forward")
227 Set(kForward);
228 else if (value == "Reverse")
229 Set(kReverse);
230 else if (value == "On")
231 Set(kOn);
232 });
233}