blob: f35d782ebfc0a8e109ed57b7642d3a19f32e9403 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008. 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 $(WIND_BASE)/WPILib. */
5/*----------------------------------------------------------------------------*/
6
7#include "Relay.h"
8
9#include "MotorSafetyHelper.h"
10//#include "NetworkCommunication/UsageReporting.h"
11#include "WPIErrors.h"
12#include "LiveWindow/LiveWindow.h"
13
14/**
15 * Relay constructor given a channel.
16 *
17 * This code initializes the relay and reserves all resources that need to be
18 * locked. Initially the relay is set to both lines at 0v.
19 * @param channel The channel number (0-3).
20 * @param direction The direction that the Relay object will control.
21 */
22Relay::Relay(uint32_t channel, Relay::Direction direction)
23 : m_channel (channel)
24 , m_direction (direction)
25{
26 char buf[64];
27 if (!SensorBase::CheckRelayChannel(m_channel))
28 {
29 snprintf(buf, 64, "Relay Channel %d", m_channel);
30 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf);
31 return;
32 }
33
34 m_safetyHelper = std::make_unique<MotorSafetyHelper>(this);
35 m_safetyHelper->SetSafetyEnabled(false);
36
37 sprintf(buf, "relay/%d", m_channel);
38 impl = new SimContinuousOutput(buf); // TODO: Allow two different relays (targetting the different halves of a relay) to be combined to control one motor.
39 LiveWindow::GetInstance()->AddActuator("Relay", 1, m_channel, this);
40 go_pos = go_neg = false;
41}
42
43/**
44 * Free the resource associated with a relay.
45 * The relay channels are set to free and the relay output is turned off.
46 */
47Relay::~Relay()
48{
49 impl->Set(0);
50 if (m_table != nullptr) m_table->RemoveTableListener(this);
51}
52
53/**
54 * Set the relay state.
55 *
56 * Valid values depend on which directions of the relay are controlled by the object.
57 *
58 * When set to kBothDirections, the relay can be any of the four states:
59 * 0v-0v, 0v-12v, 12v-0v, 12v-12v
60 *
61 * When set to kForwardOnly or kReverseOnly, you can specify the constant for the
62 * direction or you can simply specify kOff and kOn. Using only kOff and kOn is
63 * recommended.
64 *
65 * @param value The state to set the relay.
66 */
67void Relay::Set(Relay::Value value)
68{
69 switch (value)
70 {
71 case kOff:
72 if (m_direction == kBothDirections || m_direction == kForwardOnly)
73 {
74 go_pos = false;
75 }
76 if (m_direction == kBothDirections || m_direction == kReverseOnly)
77 {
78 go_neg = false;
79 }
80 break;
81 case kOn:
82 if (m_direction == kBothDirections || m_direction == kForwardOnly)
83 {
84 go_pos = true;
85 }
86 if (m_direction == kBothDirections || m_direction == kReverseOnly)
87 {
88 go_neg = true;
89 }
90 break;
91 case kForward:
92 if (m_direction == kReverseOnly)
93 {
94 wpi_setWPIError(IncompatibleMode);
95 break;
96 }
97 if (m_direction == kBothDirections || m_direction == kForwardOnly)
98 {
99 go_pos = true;
100 }
101 if (m_direction == kBothDirections)
102 {
103 go_neg = false;
104 }
105 break;
106 case kReverse:
107 if (m_direction == kForwardOnly)
108 {
109 wpi_setWPIError(IncompatibleMode);
110 break;
111 }
112 if (m_direction == kBothDirections)
113 {
114 go_pos = false;
115 }
116 if (m_direction == kBothDirections || m_direction == kReverseOnly)
117 {
118 go_neg = true;
119 }
120 break;
121 }
122 impl->Set((go_pos ? 1 : 0) + (go_neg ? -1 : 0));
123}
124
125/**
126 * Get the Relay State
127 *
128 * Gets the current state of the relay.
129 *
130 * When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not
131 * kForward/kReverse (per the recommendation in Set)
132 *
133 * @return The current state of the relay as a Relay::Value
134 */
135Relay::Value Relay::Get() const {
136 // TODO: Don't assume that the go_pos and go_neg fields are correct?
137 if ((go_pos || m_direction == kReverseOnly) && (go_neg || m_direction == kForwardOnly)) {
138 return kOn;
139 } else if (go_pos) {
140 return kForward;
141 } else if (go_neg) {
142 return kReverse;
143 } else {
144 return kOff;
145 }
146}
147
148uint32_t Relay::GetChannel() const {
149 return m_channel;
150}
151
152/**
153 * Set the expiration time for the Relay object
154 * @param timeout The timeout (in seconds) for this relay object
155 */
156void Relay::SetExpiration(float timeout) {
157 m_safetyHelper->SetExpiration(timeout);
158}
159
160/**
161 * Return the expiration time for the relay object.
162 * @return The expiration time value.
163 */
164float Relay::GetExpiration() const { return m_safetyHelper->GetExpiration(); }
165
166/**
167 * Check if the relay object is currently alive or stopped due to a timeout.
168 * @returns a bool value that is true if the motor has NOT timed out and should
169 * still be running.
170 */
171bool Relay::IsAlive() const { return m_safetyHelper->IsAlive(); }
172
173/**
174 * Stop the motor associated with this PWM object.
175 * This is called by the MotorSafetyHelper object when it has a timeout for this
176 * relay and needs to stop it from running.
177 */
178void Relay::StopMotor() { Set(kOff); }
179
180/**
181 * Enable/disable motor safety for this device
182 * Turn on and off the motor safety option for this relay object.
183 * @param enabled True if motor safety is enforced for this object
184 */
185void Relay::SetSafetyEnabled(bool enabled) {
186 m_safetyHelper->SetSafetyEnabled(enabled);
187}
188
189/**
190 * Check if motor safety is enabled for this object
191 * @returns True if motor safety is enforced for this object
192 */
193bool Relay::IsSafetyEnabled() const {
194 return m_safetyHelper->IsSafetyEnabled();
195}
196
197void Relay::GetDescription(std::ostringstream& desc) const {
198 desc << "Relay " << GetChannel();
199}
200
201void Relay::ValueChanged(ITable* source, llvm::StringRef key,
202 std::shared_ptr<nt::Value> value, bool isNew) {
203 if (!value->IsString()) return;
204 if (value->GetString() == "Off") Set(kOff);
205 else if (value->GetString() == "Forward") Set(kForward);
206 else if (value->GetString() == "Reverse") Set(kReverse);
207}
208
209void Relay::UpdateTable() {
210 if(m_table != nullptr){
211 if (Get() == kOn) {
212 m_table->PutString("Value", "On");
213 }
214 else if (Get() == kForward) {
215 m_table->PutString("Value", "Forward");
216 }
217 else if (Get() == kReverse) {
218 m_table->PutString("Value", "Reverse");
219 }
220 else {
221 m_table->PutString("Value", "Off");
222 }
223 }
224}
225
226void Relay::StartLiveWindowMode() {
227 if(m_table != nullptr){
228 m_table->AddTableListener("Value", this, true);
229 }
230}
231
232void Relay::StopLiveWindowMode() {
233 if(m_table != nullptr){
234 m_table->RemoveTableListener(this);
235 }
236}
237
238std::string Relay::GetSmartDashboardType() const {
239 return "Relay";
240}
241
242void Relay::InitTable(std::shared_ptr<ITable> subTable) {
243 m_table = subTable;
244 UpdateTable();
245}
246
247std::shared_ptr<ITable> Relay::GetTable() const {
248 return m_table;
249}