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 DCCPP_DEBUG_MODE
51  INTERFACE.println("<O>");
52 #endif
53 }
54 
56 
57 void Turnout::set(int id, int add, int subAdd) {
58  this->data.id = id;
59  this->data.address = add;
60  this->data.subAddress = subAdd;
61  this->data.tStatus = 0;
62 }
63 
65 
66 void Turnout::activate(int s) {
67  data.tStatus = (s>0); // if s>0 set turnout=ON, else if zero or negative set turnout=OFF
68  DCCppClass::mainRegs.setAccessory(this->data.address, this->data.subAddress, this->data.tStatus);
69 #ifdef USE_EEPROM
70  if (this->eepromPos>0)
71 #ifdef VISUALSTUDIO
72  EEPROM.put(this->eepromPos, (void *) &(this->data.tStatus), sizeof(int)); // ArduiEmulator version...
73 #else
74  EEPROM.put(this->eepromPos, this->data.tStatus);
75 #endif
76 #endif
77 #ifdef DCCPP_DEBUG_MODE
78  INTERFACE.print("<H");
79  INTERFACE.print(data.id);
80  if (data.tStatus == 0)
81  INTERFACE.println(" 0>");
82  else
83  INTERFACE.println(" 1>");
84 #endif
85 }
86 
87 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
88 
90 Turnout* Turnout::get(int id) {
91  Turnout *tt;
92  for (tt = firstTurnout; tt != NULL && tt->data.id != id; tt = tt->nextTurnout)
93  ;
94  return(tt);
95 }
96 
98 void Turnout::remove(int id) {
99  Turnout *tt, *pp;
100 
101  for (tt = firstTurnout; tt != NULL && tt->data.id != id; pp = tt, tt = tt->nextTurnout)
102  ;
103 
104  if (tt == NULL) {
105 #ifdef DCCPP_DEBUG_MODE
106  INTERFACE.println("<X>");
107 #endif
108  return;
109  }
110 
111  if (tt == firstTurnout)
112  firstTurnout = tt->nextTurnout;
113  else
114  pp->nextTurnout = tt->nextTurnout;
115 
116  free(tt);
117 
118 #ifdef DCCPP_DEBUG_MODE
119  INTERFACE.println("<O>");
120 #endif
121 }
122 
124 
125 int Turnout::count() {
126  int count = 0;
127  Turnout *tt;
128  for (tt = firstTurnout; tt != NULL; tt = tt->nextTurnout)
129  count++;
130  return count;
131 }
132 
134 
135 #ifdef USE_EEPROM
136 void Turnout::load() {
137  struct TurnoutData data;
138  Turnout *tt;
139 
140  for (int i = 0; i<EEStore::eeStore->data.nTurnouts; i++) {
141 #ifdef VISUALSTUDIO
142  EEPROM.get(EEStore::pointer(), (void *)&data, sizeof(TurnoutData));
143 #else
144  EEPROM.get(EEStore::pointer(), data);
145 #endif
146 #if defined(USE_TEXTCOMMAND)
147  tt = create(data.id, data.address, data.subAddress);
148 #else
149  tt = get(data.id);
150 #ifdef DCCPP_DEBUG_MODE
151  if (tt == NULL)
152  INTERFACE.println(F("Turnout::begin() must be called BEFORE Turnout::load() !"));
153  else
154 #endif
155  tt->set(data.id, data.address, data.subAddress);
156 #endif
157  tt->data.tStatus = data.tStatus;
158  tt->eepromPos = EEStore::pointer();
159  EEStore::advance(sizeof(tt->data));
160  }
161 }
162 
164 
165 void Turnout::store() {
166  Turnout *tt;
167 
168  tt = firstTurnout;
169  EEStore::eeStore->data.nTurnouts = 0;
170 
171  while (tt != NULL) {
172  tt->eepromPos = EEStore::pointer();
173 #ifdef VISUALSTUDIO
174  EEPROM.put(EEStore::pointer(), (void *) &(tt->data), sizeof(TurnoutData)); // ArduiEmulator version...
175 #else
176  EEPROM.put(EEStore::pointer(), tt->data);
177 #endif
178  EEStore::advance(sizeof(tt->data));
179  tt = tt->nextTurnout;
180  EEStore::eeStore->data.nTurnouts++;
181  }
182 }
183 #endif
184 
185 #endif
186 
187 #if defined(USE_TEXTCOMMAND)
188 
190 void Turnout::parse(char *c){
191  int n,s,m;
192  Turnout *t;
193 
194  switch(sscanf(c,"%d %d %d",&n,&s,&m)){
195 
196  case 2: // argument is string with id number of turnout followed by zero (not thrown) or one (thrown)
197  t=get(n);
198  if(t!=NULL)
199  t->activate(s);
200 #ifdef DCCPP_DEBUG_MODE
201  else
202  INTERFACE.println("<X>");
203 #endif
204  break;
205 
206  case 3: // argument is string with id number of turnout followed by an address and subAddress
207  create(n,s,m,1);
208  break;
209 
210  case 1: // argument is a string with id number only
211  remove(n);
212  break;
213 
214 #ifdef DCCPP_DEBUG_MODE
215  case -1: // no arguments
216  show();
217  break;
218 #endif
219  }
220 }
221 
222 Turnout *Turnout::create(int id, int add, int subAdd) {
223  Turnout *tt = new Turnout();
224 
225  if (tt == NULL) { // problem allocating memory
226 #ifdef DCCPP_DEBUG_MODE
227  INTERFACE.println("<X>");
228 #endif
229  return(tt);
230  }
231 
232  tt->begin(id, add, subadd);
233 
234  return(tt);
235 }
236 
237 #endif USE_TEXTCOMMAND
238 
239 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
240 #ifdef DCCPP_PRINT_DCCPP
241 
243 
244 void Turnout::show() {
245  Turnout *tt;
246 
247  if (firstTurnout == NULL) {
248  INTERFACE.println("<X>");
249  return;
250  }
251 
252  for (tt = firstTurnout; tt != NULL; tt = tt->nextTurnout) {
253  INTERFACE.print("<H");
254  INTERFACE.print(tt->data.id);
255  INTERFACE.print(" ");
256  INTERFACE.print(tt->data.address);
257  INTERFACE.print(" ");
258  INTERFACE.print(tt->data.subAddress);
259  if (tt->data.tStatus == 0)
260  INTERFACE.println(" 0>");
261  else
262  INTERFACE.println(" 1>");
263  }
264 }
265 #endif
266 
268 
269 Turnout *Turnout::firstTurnout = NULL;
270 #endif
271 
272 #endif USE_TURNOUT
273 
274