blob: 51241bead99f326deb437c67afa772abc9ff50c4 [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#include "frc971/wpilib/ahal/Relay.h"
10
11#include <sstream>
12
Austin Schuhf6b94632019-02-02 22:11:27 -080013#include "hal/HAL.h"
14#include "hal/Ports.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080015#include "frc971/wpilib/ahal/WPIErrors.h"
16
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;
Austin Schuh9950f682021-11-06 15:27:58 -070054 m_reverseHandle = HAL_InitializeRelayPort(portHandle, false, nullptr, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080055 if (status != 0) {
56 wpi_setErrorWithContextRange(status, 0, HAL_GetNumRelayChannels(),
57 channel, HAL_GetErrorMessage(status));
58 m_forwardHandle = HAL_kInvalidHandle;
59 m_reverseHandle = HAL_kInvalidHandle;
60 return;
61 }
62
63 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 128);
64 }
65
66 int32_t status = 0;
67 if (m_forwardHandle != HAL_kInvalidHandle) {
68 HAL_SetRelay(m_forwardHandle, false, &status);
69 if (status != 0) {
70 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
71 m_forwardHandle = HAL_kInvalidHandle;
72 m_reverseHandle = HAL_kInvalidHandle;
73 return;
74 }
75 }
76 if (m_reverseHandle != HAL_kInvalidHandle) {
77 HAL_SetRelay(m_reverseHandle, false, &status);
78 if (status != 0) {
79 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
80 m_forwardHandle = HAL_kInvalidHandle;
81 m_reverseHandle = HAL_kInvalidHandle;
82 return;
83 }
84 }
85}
86
87/**
88 * Free the resource associated with a relay.
89 *
90 * The relay channels are set to free and the relay output is turned off.
91 */
92Relay::~Relay() {
93 int32_t status = 0;
94 HAL_SetRelay(m_forwardHandle, false, &status);
95 HAL_SetRelay(m_reverseHandle, false, &status);
96 // ignore errors, as we want to make sure a free happens.
97 if (m_forwardHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_forwardHandle);
98 if (m_reverseHandle != HAL_kInvalidHandle) HAL_FreeRelayPort(m_reverseHandle);
99}
100
101/**
102 * Set the relay state.
103 *
104 * Valid values depend on which directions of the relay are controlled by the
105 * object.
106 *
107 * When set to kBothDirections, the relay can be any of the four states:
108 * 0v-0v, 0v-12v, 12v-0v, 12v-12v
109 *
110 * When set to kForwardOnly or kReverseOnly, you can specify the constant for
111 * the direction or you can simply specify kOff and kOn. Using only kOff and
112 * kOn is recommended.
113 *
114 * @param value The state to set the relay.
115 */
116void Relay::Set(Relay::Value value) {
117 if (StatusIsFatal()) return;
118
119 int32_t status = 0;
120
121 switch (value) {
122 case kOff:
123 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
124 HAL_SetRelay(m_forwardHandle, false, &status);
125 }
126 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
127 HAL_SetRelay(m_reverseHandle, false, &status);
128 }
129 break;
130 case kOn:
131 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
132 HAL_SetRelay(m_forwardHandle, true, &status);
133 }
134 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
135 HAL_SetRelay(m_reverseHandle, true, &status);
136 }
137 break;
138 case kForward:
139 if (m_direction == kReverseOnly) {
140 wpi_setWPIError(IncompatibleMode);
141 break;
142 }
143 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
144 HAL_SetRelay(m_forwardHandle, true, &status);
145 }
146 if (m_direction == kBothDirections) {
147 HAL_SetRelay(m_reverseHandle, false, &status);
148 }
149 break;
150 case kReverse:
151 if (m_direction == kForwardOnly) {
152 wpi_setWPIError(IncompatibleMode);
153 break;
154 }
155 if (m_direction == kBothDirections) {
156 HAL_SetRelay(m_forwardHandle, false, &status);
157 }
158 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
159 HAL_SetRelay(m_reverseHandle, true, &status);
160 }
161 break;
162 }
163
164 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
165}
166
167/**
168 * Get the Relay State
169 *
170 * Gets the current state of the relay.
171 *
172 * When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not
173 * kForward/kReverse (per the recommendation in Set)
174 *
175 * @return The current state of the relay as a Relay::Value
176 */
177Relay::Value Relay::Get() const {
178 int32_t status;
179
180 if (HAL_GetRelay(m_forwardHandle, &status)) {
181 if (HAL_GetRelay(m_reverseHandle, &status)) {
182 return kOn;
183 } else {
184 if (m_direction == kForwardOnly) {
185 return kOn;
186 } else {
187 return kForward;
188 }
189 }
190 } else {
191 if (HAL_GetRelay(m_reverseHandle, &status)) {
192 if (m_direction == kReverseOnly) {
193 return kOn;
194 } else {
195 return kReverse;
196 }
197 } else {
198 return kOff;
199 }
200 }
201
202 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
203}
204
205int Relay::GetChannel() const { return m_channel; }