DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
Outputs.cpp
1 /**********************************************************************
2 
3 Outputs.cpp
4 COPYRIGHT (c) 2013-2016 Gregg E. Berman
5 
6 Part of DCC++ BASE STATION for the Arduino
7 
8 **********************************************************************/
9 #include "Outputs.h"
10 
11 #ifdef USE_TURNOUT
12 #include "TextCommand.h"
13 #include "DCCpp_Uno.h"
14 #include "EEStore.h"
15 #ifdef USE_EEPROM
16 #include "EEPROM.h"
17 #endif
18 #include "Comm.h"
19 
21 
22 void Output::begin(int id, int pin, int iFlag) {
23 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
24 #ifdef DCCPP_DEBUG_MODE
25  if (EEStore::eeStore != NULL)
26  {
27  INTERFACE.println(F("Output::begin() must be called BEFORE DCCpp.begin() !"));
28  }
29 #endif
30  if (firstOutput == NULL) {
31  firstOutput = this;
32  }
33  else if ((get(id)) == NULL) {
34  Output *tt = firstOutput;
35  while (tt->nextOutput != NULL)
36  tt = tt->nextOutput;
37  tt->nextOutput = this;
38  }
39 #endif
40 
41  this->set(id, pin, iFlag);
42 
43 #ifdef DCCPP_DEBUG_MODE
44  INTERFACE.println("<O>");
45 #endif
46 }
47 
49 
50 void Output::set(int id, int pin, int iFlag) {
51  this->data.id = id;
52  this->data.pin = pin;
53  this->data.iFlag = iFlag;
54  this->data.oStatus = 0;
55 
56  // sets status to 0 (INACTIVE) is bit 1 of iFlag=0, otherwise set to value of bit 2 of iFlag
57  this->data.oStatus = bitRead(this->data.iFlag, 1) ? bitRead(this->data.iFlag, 2) : 0;
58 #ifdef VISUALSTUDIO
59  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
60 #endif
61  digitalWrite(this->data.pin, this->data.oStatus ^ bitRead(this->data.iFlag, 0));
62 #ifdef VISUALSTUDIO
63  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
64 #endif
65  pinMode(this->data.pin, OUTPUT);
66 }
67 
69 
70 void Output::activate(int s){
71  data.oStatus=(s>0); // if s>0, set status to active, else inactive
72  digitalWrite(data.pin,data.oStatus ^ bitRead(data.iFlag,0)); // set state of output pin to HIGH or LOW depending on whether bit zero of iFlag is set to 0 (ACTIVE=HIGH) or 1 (ACTIVE=LOW)
73 #ifdef USE_EEPROM
74  if(num>0)
75 #ifdef VISUALSTUDIO
76  EEPROM.put(num, (void *)&data.oStatus, 1);
77 #else
78  EEPROM.put(num, data.oStatus);
79 #endif
80 #endif
81 #ifdef DCCPP_DEBUG_MODE
82  INTERFACE.print("<Y");
83  INTERFACE.print(data.id);
84  if(data.oStatus==0)
85  INTERFACE.println(" 0>");
86  else
87  INTERFACE.println(" 1>");
88 #endif
89 }
90 
91 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
92 
94 Output* Output::get(int n){
95  Output *tt;
96  for(tt=firstOutput;tt!=NULL && tt->data.id!=n;tt=tt->nextOutput);
97  return(tt);
98 }
100 
101 void Output::remove(int n){
102  Output *tt,*pp;
103 
104  for(tt=firstOutput;tt!=NULL && tt->data.id!=n;pp=tt,tt=tt->nextOutput);
105 
106  if(tt==NULL){
107 #ifdef DCCPP_DEBUG_MODE
108  INTERFACE.println("<X>");
109 #endif
110  return;
111  }
112 
113  if(tt==firstOutput)
114  firstOutput=tt->nextOutput;
115  else
116  pp->nextOutput=tt->nextOutput;
117 
118  free(tt);
119 
120 #ifdef DCCPP_DEBUG_MODE
121  INTERFACE.println("<O>");
122 #endif
123 }
124 
126 
127 int Output::count() {
128  int count = 0;
129  Output *tt;
130  for (tt = firstOutput; tt != NULL; tt = tt->nextOutput)
131  count++;
132  return count;
133 }
134 
136 
137 #ifdef USE_EEPROM
138 void Output::load() {
139  struct OutputData data;
140  Output *tt;
141 
142  for (int i = 0; i<EEStore::eeStore->data.nOutputs; i++) {
143 #ifdef VISUALSTUDIO
144  EEPROM.get(EEStore::pointer(), (void *)&data, sizeof(OutputData)); // ArduiEmulator version...
145 #else
146  EEPROM.get(EEStore::pointer(), data);
147 #endif
148  tt = get(data.id);
149  tt->set(data.id, data.pin, data.iFlag);
150  tt->data.oStatus = bitRead(tt->data.iFlag, 1) ? bitRead(tt->data.iFlag, 2) : data.oStatus; // restore status to EEPROM value is bit 1 of iFlag=0, otherwise set to value of bit 2 of iFlag
151 #ifdef VISUALSTUDIO
152  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
153 #endif
154  digitalWrite(tt->data.pin, tt->data.oStatus ^ bitRead(tt->data.iFlag, 0));
155 #ifdef VISUALSTUDIO
156  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
157 #endif
158  pinMode(tt->data.pin, OUTPUT);
159  tt->num = EEStore::pointer();
160  EEStore::advance(sizeof(tt->data));
161  }
162 }
163 
165 
166 void Output::store() {
167  Output *tt;
168 
169  tt = firstOutput;
170  EEStore::eeStore->data.nOutputs = 0;
171 
172  while (tt != NULL) {
173  tt->num = EEStore::pointer();
174 #ifdef VISUALSTUDIO
175  EEPROM.put(EEStore::pointer(), (void *)&(tt->data), sizeof(OutputData)); // ArduiEmulator version...
176 #else
177  EEPROM.put(EEStore::pointer(), tt->data);
178 #endif
179  EEStore::advance(sizeof(tt->data));
180  tt = tt->nextOutput;
181  EEStore::eeStore->data.nOutputs++;
182  }
183 }
184 #endif
185 
186 #endif
187 
188 #if defined(USE_TEXTCOMMAND)
189 
191 void Output::parse(char *c){
192  int n,s,m;
193  Output *t;
194 
195  switch(sscanf(c,"%d %d %d",&n,&s,&m)){
196 
197  case 2: // argument is string with id number of output followed by zero (LOW) or one (HIGH)
198  t=get(n);
199  if(t!=NULL)
200  t->activate(s);
201 #ifdef DCCPP_PRINT_DCCPP
202  else
203  INTERFACE.println("<X>");
204 #endif
205  break;
206 
207  case 3: // argument is string with id number of output followed by a pin number and invert flag
208  create(n,s,m,1);
209  break;
210 
211  case 1: // argument is a string with id number only
212  remove(n);
213  break;
214 
215 #ifdef DCCPP_PRINT_DCCPP
216  case -1: // no arguments
217  show(1); // verbose show
218 #endif
219  break;
220  }
221 }
222 
224 
225 Output *Output::create(int id, int pin, int iFlag){
226  Output *tt = new Output();
227 
228  if (tt == NULL) { // problem allocating memory
229 #ifdef DCCPP_PRINT_DCCPP
230  INTERFACE.println("<X>");
231 #endif
232  return(tt);
233  }
234 
235  tt->begin(id, pin, iFlag);
236 
237  return(tt);
238 }
239 
240 #endif USE_TEXTCOMMAND
241 
242 #if defined(USE_EEPROM) || defined(USE_TEXTCOMMAND)
243 #ifdef DCCPP_PRINT_DCCPP
244 
246 
247 void Output::show() {
248  Output *tt;
249 
250  if (firstOutput == NULL) {
251  INTERFACE.print("<X>");
252  return;
253  }
254 
255  for (tt = firstOutput; tt != NULL; tt = tt->nextOutput) {
256  INTERFACE.print("<Y");
257  INTERFACE.print(tt->data.id);
258  INTERFACE.print(" ");
259  INTERFACE.print(tt->data.pin);
260  INTERFACE.print(" ");
261  INTERFACE.print(tt->data.iFlag);
262 
263  if (tt->data.oStatus == 0)
264  INTERFACE.println(" 0>");
265  else
266  INTERFACE.println(" 1>");
267  }
268 }
269 #endif
270 
272 
273 Output *Output::firstOutput=NULL;
274 
275 #endif
276 
277 #endif USE_OUTPUT