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