blob: cb95223b1d376dec2c3b22efd4f461dc099bafd5 [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
James Kuszmaul4b81d302019-12-14 20:53:14 -080012#include <hal/FRCUsageReporting.h>
13#include <hal/HALBase.h>
Brian Silverman41cdd3e2019-01-19 19:48:58 -080014#include <hal/Ports.h>
15#include <hal/Relay.h>
16#include <wpi/raw_ostream.h>
17
18#include "frc/SensorUtil.h"
19#include "frc/WPIErrors.h"
20#include "frc/smartdashboard/SendableBuilder.h"
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080021#include "frc/smartdashboard/SendableRegistry.h"
Brian Silverman41cdd3e2019-01-19 19:48:58 -080022
23using namespace frc;
24
25Relay::Relay(int channel, Relay::Direction direction)
26 : m_channel(channel), m_direction(direction) {
27 if (!SensorUtil::CheckRelayChannel(m_channel)) {
28 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange,
29 "Relay Channel " + wpi::Twine(m_channel));
30 return;
31 }
32
33 HAL_PortHandle portHandle = HAL_GetPort(channel);
34
35 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
36 int32_t status = 0;
37 m_forwardHandle = HAL_InitializeRelayPort(portHandle, true, &status);
38 if (status != 0) {
James Kuszmaul4b81d302019-12-14 20:53:14 -080039 wpi_setHALErrorWithRange(status, 0, HAL_GetNumRelayChannels(), channel);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080040 m_forwardHandle = HAL_kInvalidHandle;
41 m_reverseHandle = HAL_kInvalidHandle;
42 return;
43 }
James Kuszmaul4b81d302019-12-14 20:53:14 -080044 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 1);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080045 }
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) {
James Kuszmaul4b81d302019-12-14 20:53:14 -080050 wpi_setHALErrorWithRange(status, 0, HAL_GetNumRelayChannels(), channel);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080051 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) {
James Kuszmaul4b81d302019-12-14 20:53:14 -080063 wpi_setHALError(status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080064 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) {
James Kuszmaul4b81d302019-12-14 20:53:14 -080072 wpi_setHALError(status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080073 m_forwardHandle = HAL_kInvalidHandle;
74 m_reverseHandle = HAL_kInvalidHandle;
75 return;
76 }
77 }
78
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080079 SendableRegistry::GetInstance().AddLW(this, "Relay", m_channel);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080080}
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
Brian Silverman41cdd3e2019-01-19 19:48:58 -080091void Relay::Set(Relay::Value value) {
92 if (StatusIsFatal()) return;
93
94 int32_t status = 0;
95
96 switch (value) {
97 case kOff:
98 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
99 HAL_SetRelay(m_forwardHandle, false, &status);
100 }
101 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
102 HAL_SetRelay(m_reverseHandle, false, &status);
103 }
104 break;
105 case kOn:
106 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
107 HAL_SetRelay(m_forwardHandle, true, &status);
108 }
109 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
110 HAL_SetRelay(m_reverseHandle, true, &status);
111 }
112 break;
113 case kForward:
114 if (m_direction == kReverseOnly) {
115 wpi_setWPIError(IncompatibleMode);
116 break;
117 }
118 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
119 HAL_SetRelay(m_forwardHandle, true, &status);
120 }
121 if (m_direction == kBothDirections) {
122 HAL_SetRelay(m_reverseHandle, false, &status);
123 }
124 break;
125 case kReverse:
126 if (m_direction == kForwardOnly) {
127 wpi_setWPIError(IncompatibleMode);
128 break;
129 }
130 if (m_direction == kBothDirections) {
131 HAL_SetRelay(m_forwardHandle, false, &status);
132 }
133 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
134 HAL_SetRelay(m_reverseHandle, true, &status);
135 }
136 break;
137 }
138
James Kuszmaul4b81d302019-12-14 20:53:14 -0800139 wpi_setHALError(status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800140}
141
142Relay::Value Relay::Get() const {
143 int32_t status;
144
145 if (m_direction == kForwardOnly) {
146 if (HAL_GetRelay(m_forwardHandle, &status)) {
147 return kOn;
148 } else {
149 return kOff;
150 }
151 } else if (m_direction == kReverseOnly) {
152 if (HAL_GetRelay(m_reverseHandle, &status)) {
153 return kOn;
154 } else {
155 return kOff;
156 }
157 } else {
158 if (HAL_GetRelay(m_forwardHandle, &status)) {
159 if (HAL_GetRelay(m_reverseHandle, &status)) {
160 return kOn;
161 } else {
162 return kForward;
163 }
164 } else {
165 if (HAL_GetRelay(m_reverseHandle, &status)) {
166 return kReverse;
167 } else {
168 return kOff;
169 }
170 }
171 }
172
James Kuszmaul4b81d302019-12-14 20:53:14 -0800173 wpi_setHALError(status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800174}
175
176int Relay::GetChannel() const { return m_channel; }
177
178void Relay::StopMotor() { Set(kOff); }
179
180void Relay::GetDescription(wpi::raw_ostream& desc) const {
181 desc << "Relay " << GetChannel();
182}
183
184void Relay::InitSendable(SendableBuilder& builder) {
185 builder.SetSmartDashboardType("Relay");
186 builder.SetActuator(true);
187 builder.SetSafeState([=]() { Set(kOff); });
188 builder.AddSmallStringProperty(
189 "Value",
190 [=](wpi::SmallVectorImpl<char>& buf) -> wpi::StringRef {
191 switch (Get()) {
192 case kOn:
193 return "On";
194 case kForward:
195 return "Forward";
196 case kReverse:
197 return "Reverse";
198 default:
199 return "Off";
200 }
201 },
202 [=](wpi::StringRef value) {
203 if (value == "Off")
204 Set(kOff);
205 else if (value == "Forward")
206 Set(kForward);
207 else if (value == "Reverse")
208 Set(kReverse);
209 else if (value == "On")
210 Set(kOn);
211 });
212}