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