blob: 13aa13a67cb53dfd7f890a8269b581b0c3657887 [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
Austin Schuhf6b94632019-02-02 22:11:27 -08008#include "hal/Relay.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -08009
10#include <sstream>
11
Philipp Schrader790cb542023-07-05 21:06:52 -070012#include "frc971/wpilib/ahal/Relay.h"
13#include "frc971/wpilib/ahal/WPIErrors.h"
Austin Schuhf6b94632019-02-02 22:11:27 -080014#include "hal/HAL.h"
15#include "hal/Ports.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080016
17using namespace frc;
18
19/**
20 * Relay constructor given a channel.
21 *
22 * This code initializes the relay and reserves all resources that need to be
23 * locked. Initially the relay is set to both lines at 0v.
24 *
25 * @param channel The channel number (0-3).
26 * @param direction The direction that the Relay object will control.
27 */
28Relay::Relay(int channel, Relay::Direction direction)
29 : m_channel(channel), m_direction(direction) {
30 std::stringstream buf;
31 if (!CheckRelayChannel(m_channel)) {
32 buf << "Relay Channel " << m_channel;
33 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
34 return;
35 }
36
37 HAL_PortHandle portHandle = HAL_GetPort(channel);
38
39 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
40 int32_t status = 0;
Austin Schuh9950f682021-11-06 15:27:58 -070041 m_forwardHandle =
42 HAL_InitializeRelayPort(portHandle, true, nullptr, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080043 if (status != 0) {
44 wpi_setErrorWithContextRange(status, 0, HAL_GetNumRelayChannels(),
45 channel, HAL_GetErrorMessage(status));
46 m_forwardHandle = HAL_kInvalidHandle;
47 m_reverseHandle = HAL_kInvalidHandle;
48 return;
49 }
50 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel);
51 }
52 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
53 int32_t status = 0;
Philipp Schrader790cb542023-07-05 21:06:52 -070054 m_reverseHandle =
55 HAL_InitializeRelayPort(portHandle, false, nullptr, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080056 if (status != 0) {
57 wpi_setErrorWithContextRange(status, 0, HAL_GetNumRelayChannels(),
58 channel, HAL_GetErrorMessage(status));
59 m_forwardHandle = HAL_kInvalidHandle;
60 m_reverseHandle = HAL_kInvalidHandle;
61 return;
62 }
63
64 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 128);
65 }
66
67 int32_t status = 0;
68 if (m_forwardHandle != HAL_kInvalidHandle) {
69 HAL_SetRelay(m_forwardHandle, false, &status);
70 if (status != 0) {
71 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
72 m_forwardHandle = HAL_kInvalidHandle;
73 m_reverseHandle = HAL_kInvalidHandle;
74 return;
75 }
76 }
77 if (m_reverseHandle != HAL_kInvalidHandle) {
78 HAL_SetRelay(m_reverseHandle, false, &status);
79 if (status != 0) {
80 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
81 m_forwardHandle = HAL_kInvalidHandle;
82 m_reverseHandle = HAL_kInvalidHandle;
83 return;
84 }
85 }
86}
87
88/**
89 * Free the resource associated with a relay.
90 *
91 * The relay channels are set to free and the relay output is turned off.
92 */
93Relay::~Relay() {
94 int32_t status = 0;
95 HAL_SetRelay(m_forwardHandle, false, &status);
96 HAL_SetRelay(m_reverseHandle, false, &status);
97 // ignore errors, as we want to make sure a free happens.
98 if (m_forwardHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_forwardHandle);
99 if (m_reverseHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_reverseHandle);
100}
101
102/**
103 * Set the relay state.
104 *
105 * Valid values depend on which directions of the relay are controlled by the
106 * object.
107 *
108 * When set to kBothDirections, the relay can be any of the four states:
109 * 0v-0v, 0v-12v, 12v-0v, 12v-12v
110 *
111 * When set to kForwardOnly or kReverseOnly, you can specify the constant for
112 * the direction or you can simply specify kOff and kOn. Using only kOff and
113 * kOn is recommended.
114 *
115 * @param value The state to set the relay.
116 */
117void Relay::Set(Relay::Value value) {
118 if (StatusIsFatal()) return;
119
120 int32_t status = 0;
121
122 switch (value) {
123 case kOff:
124 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
125 HAL_SetRelay(m_forwardHandle, false, &status);
126 }
127 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
128 HAL_SetRelay(m_reverseHandle, false, &status);
129 }
130 break;
131 case kOn:
132 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
133 HAL_SetRelay(m_forwardHandle, true, &status);
134 }
135 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
136 HAL_SetRelay(m_reverseHandle, true, &status);
137 }
138 break;
139 case kForward:
140 if (m_direction == kReverseOnly) {
141 wpi_setWPIError(IncompatibleMode);
142 break;
143 }
144 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
145 HAL_SetRelay(m_forwardHandle, true, &status);
146 }
147 if (m_direction == kBothDirections) {
148 HAL_SetRelay(m_reverseHandle, false, &status);
149 }
150 break;
151 case kReverse:
152 if (m_direction == kForwardOnly) {
153 wpi_setWPIError(IncompatibleMode);
154 break;
155 }
156 if (m_direction == kBothDirections) {
157 HAL_SetRelay(m_forwardHandle, false, &status);
158 }
159 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
160 HAL_SetRelay(m_reverseHandle, true, &status);
161 }
162 break;
163 }
164
165 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
166}
167
168/**
169 * Get the Relay State
170 *
171 * Gets the current state of the relay.
172 *
173 * When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not
174 * kForward/kReverse (per the recommendation in Set)
175 *
176 * @return The current state of the relay as a Relay::Value
177 */
178Relay::Value Relay::Get() const {
179 int32_t status;
180
181 if (HAL_GetRelay(m_forwardHandle, &status)) {
182 if (HAL_GetRelay(m_reverseHandle, &status)) {
183 return kOn;
184 } else {
185 if (m_direction == kForwardOnly) {
186 return kOn;
187 } else {
188 return kForward;
189 }
190 }
191 } else {
192 if (HAL_GetRelay(m_reverseHandle, &status)) {
193 if (m_direction == kReverseOnly) {
194 return kOn;
195 } else {
196 return kReverse;
197 }
198 } else {
199 return kOff;
200 }
201 }
202
203 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
204}
205
206int Relay::GetChannel() const { return m_channel; }