DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
Turnout.cpp
1 /**********************************************************************
2 
3 Turnout.cpp, renamed from Accessories.cpp
4 COPYRIGHT (c) 2013-2016 Gregg E. Berman
5 
6 Part of DCC++ BASE STATION for the Arduino
7 
8 **********************************************************************/
9 
10 #include "DCCpp.h"
11 
12 #ifdef USE_TURNOUT
13 
14 #include "Turnout.h"
15 #include "DCCpp_Uno.h"
16 //#include "Comm.h"
17 
18 #ifdef USE_TEXTCOMMAND
19 #include "TextCommand.h"
20 #endif
21 
22 #ifdef USE_EEPROM
23 #include "EEStore.h"
24 #include "EEPROM.h"
25 #endif
26 
28 
29 void Turnout::begin(int id, int add, int subAdd) {
30 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
31 #ifdef DCCPP_DEBUG_MODE
32  if (EEStore::eeStore != NULL)
33  {
34  INTERFACE.println(F("Turnout::begin() must be called BEFORE DCCpp.begin() !"));
35  }
36 #endif
37  if (firstTurnout == NULL) {
38  firstTurnout = this;
39  }
40  else if (get(id) == NULL) {
41  Turnout *tt = firstTurnout;
42  while (tt->nextTurnout != NULL)
43  tt = tt->nextTurnout;
44  tt->nextTurnout = this;
45  }
46 #endif
47 
48  this->set(id, add, subAdd);
49 
50 #ifdef USE_TEXTCOMMAND
51  INTERFACE.print("<O>");
52 #if !defined(USE_ETHERNET)
53  INTERFACE.println("");
54 #endif
55 #endif
56 }
57 
59 
60 void Turnout::set(int id, int add, int subAdd) {
61  this->data.id = id;
62  this->data.address = add;
63  this->data.subAddress = subAdd;
64  this->data.tStatus = 0;
65 }
66 
68 
69 void Turnout::activate(int s) {
70  data.tStatus = (s>0); // if s>0 set turnout=ON, else if zero or negative set turnout=OFF
71  DCCppClass::mainRegs.setAccessory(this->data.address, this->data.subAddress, this->data.tStatus);
72 #ifdef USE_EEPROM
73  if (this->eepromPos>0)
74 #ifdef VISUALSTUDIO
75  EEPROM.put(this->eepromPos, (void *) &(this->data.tStatus), sizeof(int)); // ArduiEmulator version...
76 #else
77  EEPROM.put(this->eepromPos, this->data.tStatus);
78 #endif
79 #endif
80 #ifdef USE_TEXTCOMMAND
81  INTERFACE.print("<H");
82  INTERFACE.print(data.id);
83  if (data.tStatus == 0)
84  INTERFACE.print(" 0>");
85  else
86  INTERFACE.print(" 1>");
87 #if !defined(USE_ETHERNET)
88  INTERFACE.println("");
89 #endif
90 #endif
91 }
92 
93 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
94 
96 Turnout* Turnout::get(int id) {
97  Turnout *tt;
98  for (tt = firstTurnout; tt != NULL && tt->data.id != id; tt = tt->nextTurnout)
99  ;
100  return(tt);
101 }
102 
104 void Turnout::remove(int id) {
105  Turnout *tt, *pp;
106 
107  for (tt = firstTurnout; tt != NULL && tt->data.id != id; pp = tt, tt = tt->nextTurnout)
108  ;
109 
110  if (tt == NULL) {
111 #ifdef USE_TEXTCOMMAND
112  INTERFACE.print("<X>");
113 #if !defined(USE_ETHERNET)
114  INTERFACE.println("");
115 #endif
116 #endif
117  return;
118  }
119 
120  if (tt == firstTurnout)
121  firstTurnout = tt->nextTurnout;
122  else
123  pp->nextTurnout = tt->nextTurnout;
124 
125  free(tt);
126 
127 #ifdef USE_TEXTCOMMAND
128  INTERFACE.print("<O>");
129 #if !defined(USE_ETHERNET)
130  INTERFACE.println("");
131 #endif
132 #endif
133 }
134 
136 
137 int Turnout::count() {
138  int count = 0;
139  Turnout *tt;
140  for (tt = firstTurnout; tt != NULL; tt = tt->nextTurnout)
141  count++;
142  return count;
143 }
144 
146 
147 #ifdef USE_EEPROM
148 void Turnout::load() {
149  struct TurnoutData data;
150  Turnout *tt;
151 
152  for (int i = 0; i<EEStore::eeStore->data.nTurnouts; i++) {
153 #ifdef VISUALSTUDIO
154  EEPROM.get(EEStore::pointer(), (void *)&data, sizeof(TurnoutData));
155 #else
156  EEPROM.get(EEStore::pointer(), data);
157 #endif
158 #if defined(USE_TEXTCOMMAND)
159  tt = create(data.id, data.address, data.subAddress);
160 #else
161  tt = get(data.id);
162 #ifdef DCCPP_DEBUG_MODE
163  if (tt == NULL)
164  INTERFACE.println(F("Turnout::begin() must be called BEFORE Turnout::load() !"));
165  else
166 #endif
167  tt->set(data.id, data.address, data.subAddress);
168 #endif
169  tt->data.tStatus = data.tStatus;
170  tt->eepromPos = EEStore::pointer();
171  EEStore::advance(sizeof(tt->data));
172  }
173 }
174 
176 
177 void Turnout::store() {
178  Turnout *tt;
179 
180  tt = firstTurnout;
181  EEStore::eeStore->data.nTurnouts = 0;
182 
183  while (tt != NULL) {
184  tt->eepromPos = EEStore::pointer();
185 #ifdef VISUALSTUDIO
186  EEPROM.put(EEStore::pointer(), (void *) &(tt->data), sizeof(TurnoutData)); // ArduiEmulator version...
187 #else
188  EEPROM.put(EEStore::pointer(), tt->data);
189 #endif
190  EEStore::advance(sizeof(tt->data));
191  tt = tt->nextTurnout;
192  EEStore::eeStore->data.nTurnouts++;
193  }
194 }
195 #endif
196 
197 #endif
198 
199 #if defined(USE_TEXTCOMMAND)
200 
202 void Turnout::parse(char *c){
203  int n,s,m;
204  Turnout *t;
205 
206  switch(sscanf(c,"%d %d %d",&n,&s,&m)){
207 
208  case 2: // argument is string with id number of turnout followed by zero (not thrown) or one (thrown)
209  t=get(n);
210  if(t!=NULL)
211  t->activate(s);
212 #ifdef USE_TEXTCOMMAND
213  else
214  {
215  INTERFACE.print("<X>");
216 #if !defined(USE_ETHERNET)
217  INTERFACE.println("");
218 #endif
219  }
220 #endif
221  break;
222 
223  case 3: // argument is string with id number of turnout followed by an address and subAddress
224  create(n,s,m);
225  break;
226 
227  case 1: // argument is a string with id number only
228  remove(n);
229  break;
230 
231 #ifdef DCCPP_PRINT_DCCPP
232  case -1: // no arguments
233  show();
234  break;
235 #endif
236  }
237 }
238 
239 Turnout *Turnout::create(int id, int add, int subAdd) {
240  Turnout *tt = new Turnout();
241 
242  if (tt == NULL) { // problem allocating memory
243 #ifdef DCCPP_DEBUG_MODE
244  INTERFACE.print("<X>");
245 #if !defined(USE_ETHERNET)
246  INTERFACE.println("");
247 #endif
248 #endif
249  return(tt);
250  }
251 
252  tt->begin(id, add, subAdd);
253 
254  return(tt);
255 }
256 
257 #endif USE_TEXTCOMMAND
258 
259 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
260 #ifdef DCCPP_PRINT_DCCPP
261 
263 
264 void Turnout::show() {
265  Turnout *tt;
266 
267  if (firstTurnout == NULL) {
268  INTERFACE.print("<X>");
269 #if !defined(USE_ETHERNET)
270  INTERFACE.println("");
271 #endif
272  return;
273  }
274 
275  for (tt = firstTurnout; tt != NULL; tt = tt->nextTurnout) {
276  INTERFACE.print("<H");
277  INTERFACE.print(tt->data.id);
278  INTERFACE.print(" ");
279  INTERFACE.print(tt->data.address);
280  INTERFACE.print(" ");
281  INTERFACE.print(tt->data.subAddress);
282  if (tt->data.tStatus == 0)
283  INTERFACE.print(" 0>");
284  else
285  INTERFACE.print(" 1>");
286 #if !defined(USE_ETHERNET)
287  INTERFACE.println("");
288 #endif
289  }
290 }
291 #endif
292 
294 
295 Turnout *Turnout::firstTurnout = NULL;
296 #endif
297 
298 #endif USE_TURNOUT
299 
300