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