blob: f8ed2677ed03f96ff06f04ba14a54848cdc67e6b [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "DoubleSolenoid.h"
9#include "WPIErrors.h"
10#include "LiveWindow/LiveWindow.h"
11
12#include <sstream>
13
14/**
15 * Constructor.
16 * Uses the default PCM ID of 0
17 * @param forwardChannel The forward channel number on the PCM (0..7).
18 * @param reverseChannel The reverse channel number on the PCM (0..7).
19 */
20DoubleSolenoid::DoubleSolenoid(uint32_t forwardChannel, uint32_t reverseChannel)
21 : DoubleSolenoid(GetDefaultSolenoidModule(), forwardChannel, reverseChannel) {}
22
23/**
24 * Constructor.
25 *
26 * @param moduleNumber The CAN ID of the PCM.
27 * @param forwardChannel The forward channel on the PCM to control (0..7).
28 * @param reverseChannel The reverse channel on the PCM to control (0..7).
29 */
30DoubleSolenoid::DoubleSolenoid(uint8_t moduleNumber, uint32_t forwardChannel,
31 uint32_t reverseChannel)
32 : SolenoidBase(moduleNumber),
33 m_forwardChannel(forwardChannel),
34 m_reverseChannel(reverseChannel) {
35 std::stringstream buf;
36 if (!CheckSolenoidModule(m_moduleNumber)) {
37 buf << "Solenoid Module " << m_moduleNumber;
38 wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf.str());
39 return;
40 }
41 if (!CheckSolenoidChannel(m_forwardChannel)) {
42 buf << "Solenoid Module " << m_forwardChannel;
43 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
44 return;
45 }
46 if (!CheckSolenoidChannel(m_reverseChannel)) {
47 buf << "Solenoid Module " << m_reverseChannel;
48 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
49 return;
50 }
51 Resource::CreateResourceObject(
52 m_allocated, m_maxModules * m_maxPorts);
53
54 buf << "Solenoid " << m_forwardChannel << " (Module: " << m_moduleNumber
55 << ")";
56 if (m_allocated->Allocate(
57 m_moduleNumber * kSolenoidChannels + m_forwardChannel, buf.str()) ==
58 std::numeric_limits<uint32_t>::max()) {
59 CloneError(*m_allocated);
60 return;
61 }
62
63 buf << "Solenoid " << m_reverseChannel << " (Module: " << m_moduleNumber
64 << ")";
65 if (m_allocated->Allocate(
66 m_moduleNumber * kSolenoidChannels + m_reverseChannel, buf.str()) ==
67 std::numeric_limits<uint32_t>::max()) {
68 CloneError(*m_allocated);
69 return;
70 }
71
72 m_forwardMask = 1 << m_forwardChannel;
73 m_reverseMask = 1 << m_reverseChannel;
74 HALReport(HALUsageReporting::kResourceType_Solenoid, m_forwardChannel,
75 m_moduleNumber);
76 HALReport(HALUsageReporting::kResourceType_Solenoid, m_reverseChannel,
77 m_moduleNumber);
78 LiveWindow::GetInstance()->AddActuator("DoubleSolenoid", m_moduleNumber,
79 m_forwardChannel, this);
80}
81
82/**
83 * Destructor.
84 */
85DoubleSolenoid::~DoubleSolenoid() {
86 if (CheckSolenoidModule(m_moduleNumber)) {
87 m_allocated->Free(m_moduleNumber * kSolenoidChannels + m_forwardChannel);
88 m_allocated->Free(m_moduleNumber * kSolenoidChannels + m_reverseChannel);
89 }
90 if (m_table != nullptr) m_table->RemoveTableListener(this);
91}
92
93/**
94 * Set the value of a solenoid.
95 *
96 * @param value The value to set (Off, Forward or Reverse)
97 */
98void DoubleSolenoid::Set(Value value) {
99 if (StatusIsFatal()) return;
100 uint8_t rawValue = 0x00;
101
102 switch (value) {
103 case kOff:
104 rawValue = 0x00;
105 break;
106 case kForward:
107 rawValue = m_forwardMask;
108 break;
109 case kReverse:
110 rawValue = m_reverseMask;
111 break;
112 }
113
114 SolenoidBase::Set(rawValue, m_forwardMask | m_reverseMask, m_moduleNumber);
115}
116
117/**
118 * Read the current value of the solenoid.
119 *
120 * @return The current value of the solenoid.
121 */
122DoubleSolenoid::Value DoubleSolenoid::Get() const {
123 if (StatusIsFatal()) return kOff;
124 uint8_t value = GetAll(m_moduleNumber);
125
126 if (value & m_forwardMask) return kForward;
127 if (value & m_reverseMask) return kReverse;
128 return kOff;
129}
130/**
131 * Check if the forward solenoid is blacklisted.
132 * If a solenoid is shorted, it is added to the blacklist and
133 * disabled until power cycle, or until faults are cleared.
134 * @see ClearAllPCMStickyFaults()
135 *
136 * @return If solenoid is disabled due to short.
137 */
138bool DoubleSolenoid::IsFwdSolenoidBlackListed() const {
139 int blackList = GetPCMSolenoidBlackList(m_moduleNumber);
140 return (blackList & m_forwardMask) ? 1 : 0;
141}
142/**
143 * Check if the reverse solenoid is blacklisted.
144 * If a solenoid is shorted, it is added to the blacklist and
145 * disabled until power cycle, or until faults are cleared.
146 * @see ClearAllPCMStickyFaults()
147 *
148 * @return If solenoid is disabled due to short.
149 */
150bool DoubleSolenoid::IsRevSolenoidBlackListed() const {
151 int blackList = GetPCMSolenoidBlackList(m_moduleNumber);
152 return (blackList & m_reverseMask) ? 1 : 0;
153}
154
155void DoubleSolenoid::ValueChanged(ITable* source, llvm::StringRef key,
156 std::shared_ptr<nt::Value> value,
157 bool isNew) {
158 if (!value->IsString()) return;
159 Value lvalue = kOff;
160 if (value->GetString() == "Forward")
161 lvalue = kForward;
162 else if (value->GetString() == "Reverse")
163 lvalue = kReverse;
164 Set(lvalue);
165}
166
167void DoubleSolenoid::UpdateTable() {
168 if (m_table != nullptr) {
169 m_table->PutString(
170 "Value", (Get() == kForward ? "Forward"
171 : (Get() == kReverse ? "Reverse" : "Off")));
172 }
173}
174
175void DoubleSolenoid::StartLiveWindowMode() {
176 Set(kOff);
177 if (m_table != nullptr) {
178 m_table->AddTableListener("Value", this, true);
179 }
180}
181
182void DoubleSolenoid::StopLiveWindowMode() {
183 Set(kOff);
184 if (m_table != nullptr) {
185 m_table->RemoveTableListener(this);
186 }
187}
188
189std::string DoubleSolenoid::GetSmartDashboardType() const {
190 return "Double Solenoid";
191}
192
193void DoubleSolenoid::InitTable(std::shared_ptr<ITable> subTable) {
194 m_table = subTable;
195 UpdateTable();
196}
197
198std::shared_ptr<ITable> DoubleSolenoid::GetTable() const { return m_table; }