blob: e02cd319e24b794bba6b8f375869e303a8f52beb [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +00001/*----------------------------------------------------------------------------*/
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 "DigitalModule.h"
10#include "NetworkCommunication/UsageReporting.h"
11#include "Resource.h"
12#include "WPIErrors.h"
13#include "LiveWindow/LiveWindow.h"
14
15// Allocate each direction separately.
16static Resource *relayChannels = NULL;
17
18/**
19 * Common relay intitialization methode.
20 * This code is common to all Relay constructors and initializes the relay and reserves
21 * all resources that need to be locked. Initially the relay is set to both lines at 0v.
22 * @param slot The module slot number this relay is connected to.
23 *
24 * @param moduleNumber The digital module this relay is connected to (1 or 2).
25 */
26void Relay::InitRelay (UINT8 moduleNumber)
27{
28 char buf[64];
29 Resource::CreateResourceObject(&relayChannels, tDIO::kNumSystems * kRelayChannels * 2);
30 if (!SensorBase::CheckRelayModule(moduleNumber))
31 {
32 snprintf(buf, 64, "Digital Module %d", moduleNumber);
33 wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf);
34 return;
35 }
36 if (!SensorBase::CheckRelayChannel(m_channel))
37 {
38 snprintf(buf, 64, "Relay Channel %d", m_channel);
39 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf);
40 return;
41 }
42
43 if (m_direction == kBothDirections || m_direction == kForwardOnly)
44 {
45 snprintf(buf, 64, "Forward Relay %d (Module: %d)", m_channel, moduleNumber);
46 if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels + m_channel - 1) * 2, buf) == ~0ul)
47 {
48 CloneError(relayChannels);
49 return;
50 }
51
52 nUsageReporting::report(nUsageReporting::kResourceType_Relay, m_channel, moduleNumber - 1);
53 }
54 if (m_direction == kBothDirections || m_direction == kReverseOnly)
55 {
56 snprintf(buf, 64, "Reverse Relay %d (Module: %d)", m_channel, moduleNumber);
57 if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels + m_channel - 1) * 2 + 1, buf) == ~0ul)
58 {
59 CloneError(relayChannels);
60 return;
61 }
62
63 nUsageReporting::report(nUsageReporting::kResourceType_Relay, m_channel + 128, moduleNumber - 1);
64 }
65 m_module = DigitalModule::GetInstance(moduleNumber);
66 m_module->SetRelayForward(m_channel, false);
67 m_module->SetRelayReverse(m_channel, false);
68 LiveWindow::GetInstance()->AddActuator("Relay", moduleNumber, m_channel, this);
69}
70
71/**
72 * Relay constructor given the module and the channel.
73 *
74 * @param moduleNumber The digital module this relay is connected to (1 or 2).
75 * @param channel The channel number within the module for this relay.
76 * @param direction The direction that the Relay object will control.
77 */
78Relay::Relay(UINT8 moduleNumber, UINT32 channel, Relay::Direction direction)
79 : m_channel (channel)
80 , m_direction (direction)
81{
82 InitRelay(moduleNumber);
83}
84
85/**
86 * Relay constructor given a channel only where the default digital module is used.
87 * @param channel The channel number within the default module for this relay.
88 * @param direction The direction that the Relay object will control.
89 */
90Relay::Relay(UINT32 channel, Relay::Direction direction)
91 : m_channel (channel)
92 , m_direction (direction)
93{
94 InitRelay(GetDefaultDigitalModule());
95}
96
97/**
98 * Free the resource associated with a relay.
99 * The relay channels are set to free and the relay output is turned off.
100 */
101Relay::~Relay()
102{
103 m_module->SetRelayForward(m_channel, false);
104 m_module->SetRelayReverse(m_channel, false);
105
106 if (m_direction == kBothDirections || m_direction == kForwardOnly)
107 {
108 relayChannels->Free(((m_module->GetNumber() - 1) * kRelayChannels + m_channel - 1) * 2);
109 }
110 if (m_direction == kBothDirections || m_direction == kReverseOnly)
111 {
112 relayChannels->Free(((m_module->GetNumber() - 1) * kRelayChannels + m_channel - 1) * 2 + 1);
113 }
114}
115
116/**
117 * Set the relay state.
118 *
119 * Valid values depend on which directions of the relay are controlled by the object.
120 *
121 * When set to kBothDirections, the relay can be any of the four states:
122 * 0v-0v, 0v-12v, 12v-0v, 12v-12v
123 *
124 * When set to kForwardOnly or kReverseOnly, you can specify the constant for the
125 * direction or you can simply specify kOff and kOn. Using only kOff and kOn is
126 * recommended.
127 *
128 * @param value The state to set the relay.
129 */
130void Relay::Set(Relay::Value value)
131{
132 if (StatusIsFatal()) return;
133 switch (value)
134 {
135 case kOff:
136 if (m_direction == kBothDirections || m_direction == kForwardOnly)
137 {
138 m_module->SetRelayForward(m_channel, false);
139 }
140 if (m_direction == kBothDirections || m_direction == kReverseOnly)
141 {
142 m_module->SetRelayReverse(m_channel, false);
143 }
144 break;
145 case kOn:
146 if (m_direction == kBothDirections || m_direction == kForwardOnly)
147 {
148 m_module->SetRelayForward(m_channel, true);
149 }
150 if (m_direction == kBothDirections || m_direction == kReverseOnly)
151 {
152 m_module->SetRelayReverse(m_channel, true);
153 }
154 break;
155 case kForward:
156 if (m_direction == kReverseOnly)
157 {
158 wpi_setWPIError(IncompatibleMode);
159 break;
160 }
161 if (m_direction == kBothDirections || m_direction == kForwardOnly)
162 {
163 m_module->SetRelayForward(m_channel, true);
164 }
165 if (m_direction == kBothDirections)
166 {
167 m_module->SetRelayReverse(m_channel, false);
168 }
169 break;
170 case kReverse:
171 if (m_direction == kForwardOnly)
172 {
173 wpi_setWPIError(IncompatibleMode);
174 break;
175 }
176 if (m_direction == kBothDirections)
177 {
178 m_module->SetRelayForward(m_channel, false);
179 }
180 if (m_direction == kBothDirections || m_direction == kReverseOnly)
181 {
182 m_module->SetRelayReverse(m_channel, true);
183 }
184 break;
185 }
186}
187
188/**
189 * Get the Relay State
190 *
191 * Gets the current state of the relay.
192 *
193 * When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not
194 * kForward/kReverse (per the recommendation in Set)
195 *
196 * @return The current state of the relay as a Relay::Value
197 */
198Relay::Value Relay::Get() {
199 if(m_module->GetRelayForward(m_channel)) {
200 if(m_module->GetRelayReverse(m_channel)) {
201 return kOn;
202 } else {
203 if(m_direction == kForwardOnly) {
204 return kOn;
205 } else {
206 return kForward;
207 }
208 }
209 } else {
210 if(m_module->GetRelayReverse(m_channel)) {
211 if(m_direction == kReverseOnly) {
212 return kOn;
213 } else {
214 return kReverse;
215 }
216 } else {
217 return kOff;
218 }
219 }
220}
221
222void Relay::ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew) {
223 std::string *val = (std::string *) value.ptr;
224 if (*val == "Off") Set(kOff);
225 else if (*val == "Forward") Set(kForward);
226 else if (*val == "Reverse") Set(kReverse);
227}
228
229void Relay::UpdateTable() {
230 if(m_table != NULL){
231 if (Get() == kOn) {
232 m_table->PutString("Value", "On");
233 }
234 else if (Get() == kForward) {
235 m_table->PutString("Value", "Forward");
236 }
237 else if (Get() == kReverse) {
238 m_table->PutString("Value", "Reverse");
239 }
240 else {
241 m_table->PutString("Value", "Off");
242 }
243 }
244}
245
246void Relay::StartLiveWindowMode() {
247 m_table->AddTableListener("Value", this, true);
248}
249
250void Relay::StopLiveWindowMode() {
251 m_table->RemoveTableListener(this);
252}
253
254std::string Relay::GetSmartDashboardType() {
255 return "Relay";
256}
257
258void Relay::InitTable(ITable *subTable) {
259 m_table = subTable;
260 UpdateTable();
261}
262
263ITable * Relay::GetTable() {
264 return m_table;
265}
266
267