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