blob: 9bec566d12c145d5d1321a6d978bc911363e9a7d [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "frc/Relay.h"
6
7#include <utility>
8
Austin Schuh812d0d12021-11-04 20:16:48 -07009#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include <hal/FRCUsageReporting.h>
11#include <hal/HALBase.h>
12#include <hal/Ports.h>
13#include <hal/Relay.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070014#include <wpi/StackTrace.h>
15#include <wpi/sendable/SendableBuilder.h>
16#include <wpi/sendable/SendableRegistry.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080017
Austin Schuh812d0d12021-11-04 20:16:48 -070018#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080019#include "frc/SensorUtil.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080020
21using namespace frc;
22
23Relay::Relay(int channel, Relay::Direction direction)
24 : m_channel(channel), m_direction(direction) {
25 if (!SensorUtil::CheckRelayChannel(m_channel)) {
Austin Schuh812d0d12021-11-04 20:16:48 -070026 throw FRC_MakeError(err::ChannelIndexOutOfRange, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080027 return;
28 }
29
30 HAL_PortHandle portHandle = HAL_GetPort(channel);
31
32 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
33 int32_t status = 0;
Austin Schuh812d0d12021-11-04 20:16:48 -070034 std::string stackTrace = wpi::GetStackTrace(1);
35 m_forwardHandle =
36 HAL_InitializeRelayPort(portHandle, true, stackTrace.c_str(), &status);
37 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080038 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 1);
39 }
40 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
41 int32_t status = 0;
Austin Schuh812d0d12021-11-04 20:16:48 -070042 std::string stackTrace = wpi::GetStackTrace(1);
43 m_reverseHandle =
44 HAL_InitializeRelayPort(portHandle, false, stackTrace.c_str(), &status);
45 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080046 HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 128);
47 }
48
49 int32_t status = 0;
50 if (m_forwardHandle != HAL_kInvalidHandle) {
51 HAL_SetRelay(m_forwardHandle, false, &status);
Austin Schuh812d0d12021-11-04 20:16:48 -070052 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080053 }
54 if (m_reverseHandle != HAL_kInvalidHandle) {
55 HAL_SetRelay(m_reverseHandle, false, &status);
Austin Schuh812d0d12021-11-04 20:16:48 -070056 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080057 }
58
Austin Schuh812d0d12021-11-04 20:16:48 -070059 wpi::SendableRegistry::AddLW(this, "Relay", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080060}
61
62Relay::~Relay() {
63 int32_t status = 0;
64 HAL_SetRelay(m_forwardHandle, false, &status);
65 HAL_SetRelay(m_reverseHandle, false, &status);
66 // ignore errors, as we want to make sure a free happens.
Austin Schuh812d0d12021-11-04 20:16:48 -070067 if (m_forwardHandle != HAL_kInvalidHandle) {
68 HAL_FreeRelayPort(m_forwardHandle);
69 }
70 if (m_reverseHandle != HAL_kInvalidHandle) {
71 HAL_FreeRelayPort(m_reverseHandle);
72 }
Brian Silverman8fce7482020-01-05 13:18:21 -080073}
74
75void Relay::Set(Relay::Value value) {
Brian Silverman8fce7482020-01-05 13:18:21 -080076 int32_t status = 0;
77
78 switch (value) {
79 case kOff:
80 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
81 HAL_SetRelay(m_forwardHandle, false, &status);
82 }
83 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
84 HAL_SetRelay(m_reverseHandle, false, &status);
85 }
86 break;
87 case kOn:
88 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
89 HAL_SetRelay(m_forwardHandle, true, &status);
90 }
91 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
92 HAL_SetRelay(m_reverseHandle, true, &status);
93 }
94 break;
95 case kForward:
96 if (m_direction == kReverseOnly) {
Austin Schuh812d0d12021-11-04 20:16:48 -070097 FRC_ReportError(err::IncompatibleMode, "channel {} setting {}",
98 m_channel, "forward");
Brian Silverman8fce7482020-01-05 13:18:21 -080099 break;
100 }
101 if (m_direction == kBothDirections || m_direction == kForwardOnly) {
102 HAL_SetRelay(m_forwardHandle, true, &status);
103 }
104 if (m_direction == kBothDirections) {
105 HAL_SetRelay(m_reverseHandle, false, &status);
106 }
107 break;
108 case kReverse:
109 if (m_direction == kForwardOnly) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700110 FRC_ReportError(err::IncompatibleMode, "channel {} setting {}",
111 m_channel, "reverse");
Brian Silverman8fce7482020-01-05 13:18:21 -0800112 break;
113 }
114 if (m_direction == kBothDirections) {
115 HAL_SetRelay(m_forwardHandle, false, &status);
116 }
117 if (m_direction == kBothDirections || m_direction == kReverseOnly) {
118 HAL_SetRelay(m_reverseHandle, true, &status);
119 }
120 break;
121 }
122
Austin Schuh812d0d12021-11-04 20:16:48 -0700123 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
Brian Silverman8fce7482020-01-05 13:18:21 -0800124}
125
126Relay::Value Relay::Get() const {
Austin Schuh812d0d12021-11-04 20:16:48 -0700127 Relay::Value value = kOff;
128 int32_t status = 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800129
130 if (m_direction == kForwardOnly) {
131 if (HAL_GetRelay(m_forwardHandle, &status)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700132 value = kOn;
Brian Silverman8fce7482020-01-05 13:18:21 -0800133 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700134 value = kOff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800135 }
136 } else if (m_direction == kReverseOnly) {
137 if (HAL_GetRelay(m_reverseHandle, &status)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700138 value = kOn;
Brian Silverman8fce7482020-01-05 13:18:21 -0800139 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700140 value = kOff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800141 }
142 } else {
143 if (HAL_GetRelay(m_forwardHandle, &status)) {
144 if (HAL_GetRelay(m_reverseHandle, &status)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700145 value = kOn;
Brian Silverman8fce7482020-01-05 13:18:21 -0800146 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700147 value = kForward;
Brian Silverman8fce7482020-01-05 13:18:21 -0800148 }
149 } else {
150 if (HAL_GetRelay(m_reverseHandle, &status)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700151 value = kReverse;
Brian Silverman8fce7482020-01-05 13:18:21 -0800152 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700153 value = kOff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800154 }
155 }
156 }
157
Austin Schuh812d0d12021-11-04 20:16:48 -0700158 FRC_CheckErrorStatus(status, "Channel {}", m_channel);
159
160 return value;
Brian Silverman8fce7482020-01-05 13:18:21 -0800161}
162
Austin Schuh812d0d12021-11-04 20:16:48 -0700163int Relay::GetChannel() const {
164 return m_channel;
Brian Silverman8fce7482020-01-05 13:18:21 -0800165}
166
Austin Schuh812d0d12021-11-04 20:16:48 -0700167void Relay::StopMotor() {
168 Set(kOff);
169}
170
171std::string Relay::GetDescription() const {
172 return fmt::format("Relay {}", GetChannel());
173}
174
175void Relay::InitSendable(wpi::SendableBuilder& builder) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800176 builder.SetSmartDashboardType("Relay");
177 builder.SetActuator(true);
Austin Schuh812d0d12021-11-04 20:16:48 -0700178 builder.SetSafeState([=] { Set(kOff); });
Brian Silverman8fce7482020-01-05 13:18:21 -0800179 builder.AddSmallStringProperty(
180 "Value",
Austin Schuh812d0d12021-11-04 20:16:48 -0700181 [=](wpi::SmallVectorImpl<char>& buf) -> std::string_view {
Brian Silverman8fce7482020-01-05 13:18:21 -0800182 switch (Get()) {
183 case kOn:
184 return "On";
185 case kForward:
186 return "Forward";
187 case kReverse:
188 return "Reverse";
189 default:
190 return "Off";
191 }
192 },
Austin Schuh812d0d12021-11-04 20:16:48 -0700193 [=](std::string_view value) {
194 if (value == "Off") {
Brian Silverman8fce7482020-01-05 13:18:21 -0800195 Set(kOff);
Austin Schuh812d0d12021-11-04 20:16:48 -0700196 } else if (value == "Forward") {
Brian Silverman8fce7482020-01-05 13:18:21 -0800197 Set(kForward);
Austin Schuh812d0d12021-11-04 20:16:48 -0700198 } else if (value == "Reverse") {
Brian Silverman8fce7482020-01-05 13:18:21 -0800199 Set(kReverse);
Austin Schuh812d0d12021-11-04 20:16:48 -0700200 } else if (value == "On") {
Brian Silverman8fce7482020-01-05 13:18:21 -0800201 Set(kOn);
Austin Schuh812d0d12021-11-04 20:16:48 -0700202 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800203 });
204}