blob: 86678aac591bc46fb3a024d9e0e68597ec5b9134 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. 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
8#include "frc/DoubleSolenoid.h"
9
10#include <utility>
11
12#include <hal/HAL.h>
13#include <hal/Ports.h>
14#include <hal/Solenoid.h>
15
16#include "frc/SensorUtil.h"
17#include "frc/WPIErrors.h"
18#include "frc/smartdashboard/SendableBuilder.h"
19
20using namespace frc;
21
22DoubleSolenoid::DoubleSolenoid(int forwardChannel, int reverseChannel)
23 : DoubleSolenoid(SensorUtil::GetDefaultSolenoidModule(), forwardChannel,
24 reverseChannel) {}
25
26DoubleSolenoid::DoubleSolenoid(int moduleNumber, int forwardChannel,
27 int reverseChannel)
28 : SolenoidBase(moduleNumber),
29 m_forwardChannel(forwardChannel),
30 m_reverseChannel(reverseChannel) {
31 if (!SensorUtil::CheckSolenoidModule(m_moduleNumber)) {
32 wpi_setWPIErrorWithContext(ModuleIndexOutOfRange,
33 "Solenoid Module " + wpi::Twine(m_moduleNumber));
34 return;
35 }
36 if (!SensorUtil::CheckSolenoidChannel(m_forwardChannel)) {
37 wpi_setWPIErrorWithContext(
38 ChannelIndexOutOfRange,
39 "Solenoid Channel " + wpi::Twine(m_forwardChannel));
40 return;
41 }
42 if (!SensorUtil::CheckSolenoidChannel(m_reverseChannel)) {
43 wpi_setWPIErrorWithContext(
44 ChannelIndexOutOfRange,
45 "Solenoid Channel " + wpi::Twine(m_reverseChannel));
46 return;
47 }
48 int32_t status = 0;
49 m_forwardHandle = HAL_InitializeSolenoidPort(
50 HAL_GetPortWithModule(moduleNumber, m_forwardChannel), &status);
51 if (status != 0) {
52 wpi_setErrorWithContextRange(status, 0, HAL_GetNumSolenoidChannels(),
53 forwardChannel, HAL_GetErrorMessage(status));
54 m_forwardHandle = HAL_kInvalidHandle;
55 m_reverseHandle = HAL_kInvalidHandle;
56 return;
57 }
58
59 m_reverseHandle = HAL_InitializeSolenoidPort(
60 HAL_GetPortWithModule(moduleNumber, m_reverseChannel), &status);
61 if (status != 0) {
62 wpi_setErrorWithContextRange(status, 0, HAL_GetNumSolenoidChannels(),
63 reverseChannel, HAL_GetErrorMessage(status));
64 // free forward solenoid
65 HAL_FreeSolenoidPort(m_forwardHandle);
66 m_forwardHandle = HAL_kInvalidHandle;
67 m_reverseHandle = HAL_kInvalidHandle;
68 return;
69 }
70
71 m_forwardMask = 1 << m_forwardChannel;
72 m_reverseMask = 1 << m_reverseChannel;
73
74 HAL_Report(HALUsageReporting::kResourceType_Solenoid, m_forwardChannel,
75 m_moduleNumber);
76 HAL_Report(HALUsageReporting::kResourceType_Solenoid, m_reverseChannel,
77 m_moduleNumber);
78 SetName("DoubleSolenoid", m_moduleNumber, m_forwardChannel);
79}
80
81DoubleSolenoid::~DoubleSolenoid() {
82 HAL_FreeSolenoidPort(m_forwardHandle);
83 HAL_FreeSolenoidPort(m_reverseHandle);
84}
85
86DoubleSolenoid::DoubleSolenoid(DoubleSolenoid&& rhs)
87 : SolenoidBase(std::move(rhs)),
88 m_forwardChannel(std::move(rhs.m_forwardChannel)),
89 m_reverseChannel(std::move(rhs.m_reverseChannel)),
90 m_forwardMask(std::move(rhs.m_forwardMask)),
91 m_reverseMask(std::move(rhs.m_reverseMask)) {
92 std::swap(m_forwardHandle, rhs.m_forwardHandle);
93 std::swap(m_reverseHandle, rhs.m_reverseHandle);
94}
95
96DoubleSolenoid& DoubleSolenoid::operator=(DoubleSolenoid&& rhs) {
97 SolenoidBase::operator=(std::move(rhs));
98
99 m_forwardChannel = std::move(rhs.m_forwardChannel);
100 m_reverseChannel = std::move(rhs.m_reverseChannel);
101 m_forwardMask = std::move(rhs.m_forwardMask);
102 m_reverseMask = std::move(rhs.m_reverseMask);
103 std::swap(m_forwardHandle, rhs.m_forwardHandle);
104 std::swap(m_reverseHandle, rhs.m_reverseHandle);
105
106 return *this;
107}
108
109void DoubleSolenoid::Set(Value value) {
110 if (StatusIsFatal()) return;
111
112 bool forward = false;
113 bool reverse = false;
114 switch (value) {
115 case kOff:
116 forward = false;
117 reverse = false;
118 break;
119 case kForward:
120 forward = true;
121 reverse = false;
122 break;
123 case kReverse:
124 forward = false;
125 reverse = true;
126 break;
127 }
128 int fstatus = 0;
129 HAL_SetSolenoid(m_forwardHandle, forward, &fstatus);
130 int rstatus = 0;
131 HAL_SetSolenoid(m_reverseHandle, reverse, &rstatus);
132
133 wpi_setErrorWithContext(fstatus, HAL_GetErrorMessage(fstatus));
134 wpi_setErrorWithContext(rstatus, HAL_GetErrorMessage(rstatus));
135}
136
137DoubleSolenoid::Value DoubleSolenoid::Get() const {
138 if (StatusIsFatal()) return kOff;
139 int fstatus = 0;
140 int rstatus = 0;
141 bool valueForward = HAL_GetSolenoid(m_forwardHandle, &fstatus);
142 bool valueReverse = HAL_GetSolenoid(m_reverseHandle, &rstatus);
143
144 wpi_setErrorWithContext(fstatus, HAL_GetErrorMessage(fstatus));
145 wpi_setErrorWithContext(rstatus, HAL_GetErrorMessage(rstatus));
146
147 if (valueForward) return kForward;
148 if (valueReverse) return kReverse;
149 return kOff;
150}
151
152bool DoubleSolenoid::IsFwdSolenoidBlackListed() const {
153 int blackList = GetPCMSolenoidBlackList(m_moduleNumber);
154 return (blackList & m_forwardMask) != 0;
155}
156
157bool DoubleSolenoid::IsRevSolenoidBlackListed() const {
158 int blackList = GetPCMSolenoidBlackList(m_moduleNumber);
159 return (blackList & m_reverseMask) != 0;
160}
161
162void DoubleSolenoid::InitSendable(SendableBuilder& builder) {
163 builder.SetSmartDashboardType("Double Solenoid");
164 builder.SetActuator(true);
165 builder.SetSafeState([=]() { Set(kOff); });
166 builder.AddSmallStringProperty(
167 "Value",
168 [=](wpi::SmallVectorImpl<char>& buf) -> wpi::StringRef {
169 switch (Get()) {
170 case kForward:
171 return "Forward";
172 case kReverse:
173 return "Reverse";
174 default:
175 return "Off";
176 }
177 },
178 [=](wpi::StringRef value) {
179 Value lvalue = kOff;
180 if (value == "Forward")
181 lvalue = kForward;
182 else if (value == "Reverse")
183 lvalue = kReverse;
184 Set(lvalue);
185 });
186}