DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
Sensor.cpp
1 /**********************************************************************
2 
3 Sensor.cpp
4 COPYRIGHT (c) 2013-2016 Gregg E. Berman
5 
6 Part of DCC++ BASE STATION for the Arduino
7 
8 **********************************************************************/
9 
10 #include "Sensor.h"
11 #ifdef USE_SENSOR
12 #ifdef VISUALSTUDIO
13 #include "string.h"
14 #endif
15 #include "DCCpp_Uno.h"
16 #include "EEStore.h"
17 #ifdef USE_EEPROM
18 #include "EEPROM.h"
19 #endif
20 #include "Comm.h"
21 
23 
24 void Sensor::begin(int snum, int pin, int pullUp) {
25 #if defined(USE_EEPROM) && defined(DCCPP_DEBUG_MODE)
26  if (strncmp(EEStore::data.id, EESTORE_ID, sizeof(EESTORE_ID)) != 0) { // check to see that eeStore contains valid DCC++ ID
27  INTERFACE.println(F("Sensor::begin() must be called BEFORE DCCpp.begin() !"));
28  }
29 #endif
30 
31  if (firstSensor == NULL) {
32  firstSensor = this;
33  }
34  else if (get(snum) == NULL) {
35  Sensor *tt = firstSensor;
36  while (tt->nextSensor != NULL)
37  tt = tt->nextSensor;
38  tt->nextSensor = this;
39  }
40 
41  this->set(snum, pin, pullUp);
42 
43 #ifdef USE_TEXTCOMMAND
44  INTERFACE.print("<O>");
45 #if !defined(USE_ETHERNET)
46  INTERFACE.println("");
47 #endif
48 #endif
49 }
50 
52 
53 void Sensor::set(int snum, int pin, int pullUp) {
54  this->data.snum = snum;
55  this->data.pin = pin;
56  this->data.pullUp = (pullUp == 0 ? LOW : HIGH);
57  this->active = false;
58  this->signal = 1;
59 #ifdef VISUALSTUDIO
60  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
61 #endif
62  digitalWrite(pin, pullUp); // don't use Arduino's internal pull-up resistors for external infrared sensors --- each sensor must have its own 1K external pull-up resistor
63 #ifdef VISUALSTUDIO
64  ArduiEmulator::Arduino::dontCheckNextPinAccess = true;
65 #endif
66  pinMode(pin, INPUT); // force mode to input
67 }
68 
70 
71 Sensor* Sensor::get(int n) {
72  Sensor *tt;
73  for (tt = firstSensor; tt != NULL && tt->data.snum != n; tt = tt->nextSensor);
74  return(tt);
75 }
77 
78 void Sensor::remove(int n) {
79  Sensor *tt, *pp;
80 
81  for (tt = firstSensor; tt != NULL && tt->data.snum != n; pp = tt, tt = tt->nextSensor);
82 
83  if (tt == NULL) {
84 #ifdef USE_TEXTCOMMAND
85  INTERFACE.print("<X>");
86 #if !defined(USE_ETHERNET)
87  INTERFACE.println("");
88 #endif
89 #endif
90  return;
91  }
92 
93  if (tt == firstSensor)
94  firstSensor = tt->nextSensor;
95  else
96  pp->nextSensor = tt->nextSensor;
97 
98  free(tt);
99 
100 #ifdef USE_TEXTCOMMAND
101  INTERFACE.print("<O>");
102 #if !defined(USE_ETHERNET)
103  INTERFACE.println("");
104 #endif
105 #endif
106 }
107 
109 
110 int Sensor::count() {
111  int count = 0;
112  Sensor *tt;
113  for (tt = firstSensor; tt != NULL; tt = tt->nextSensor)
114  count++;
115  return count;
116 }
117 
119 
120 void Sensor::check(){
121  Sensor *tt;
122 
123  for(tt = firstSensor; tt != NULL; tt = tt->nextSensor){
124  tt->signal = (float)(tt->signal * (1.0 - SENSOR_DECAY) + digitalRead(tt->data.pin) * SENSOR_DECAY);
125 
126  if(!tt->active && tt->signal<0.5){
127  tt->active=true;
128  INTERFACE.print("<Q");
129  INTERFACE.print(tt->data.snum);
130  INTERFACE.print(">");
131 #if !defined(USE_ETHERNET)
132  INTERFACE.println("");
133 #endif
134  } else if(tt->active && tt->signal>0.9){
135  tt->active=false;
136  INTERFACE.print("<q");
137  INTERFACE.print(tt->data.snum);
138  INTERFACE.print(">");
139 #if !defined(USE_ETHERNET)
140  INTERFACE.println("");
141 #endif
142  }
143  } // loop over all sensors
144 
145 } // Sensor::check
146 
147 #ifdef DCCPP_PRINT_DCCPP
148 
150 void Sensor::show() {
151  Sensor *tt;
152 
153  if (firstSensor == NULL) {
154  INTERFACE.print("<X>");
155 #if !defined(USE_ETHERNET)
156  INTERFACE.println("");
157 #endif
158  return;
159  }
160 
161  for (tt = firstSensor; tt != NULL; tt = tt->nextSensor) {
162  INTERFACE.print("<Q");
163  INTERFACE.print(tt->data.snum);
164  INTERFACE.print(" ");
165  INTERFACE.print(tt->data.pin);
166  INTERFACE.print(" ");
167  INTERFACE.print(tt->data.pullUp);
168  INTERFACE.print(">");
169 #if !defined(USE_ETHERNET)
170  INTERFACE.println("");
171 #endif
172  }
173 }
174 
176 
177 void Sensor::status() {
178  Sensor *tt;
179 
180  if (firstSensor == NULL) {
181  INTERFACE.print("<X>");
182 #if !defined(USE_ETHERNET)
183  INTERFACE.println("");
184 #endif
185  return;
186  }
187 
188  for (tt = firstSensor; tt != NULL; tt = tt->nextSensor) {
189  INTERFACE.print(tt->active ? "<Q" : "<q");
190  INTERFACE.print(tt->data.snum);
191  INTERFACE.print(">");
192 #if !defined(USE_ETHERNET)
193  INTERFACE.println("");
194 #endif
195  }
196 }
197 
198 #endif
199 
200 #ifdef USE_EEPROM
201 
203 void Sensor::load() {
204  struct SensorData data;
205  Sensor *tt;
206 
207  for (int i = 0; i<EEStore::data.nSensors; i++) {
208 #ifdef VISUALSTUDIO
209  EEPROM.get(EEStore::pointer(), (void *)&(data), sizeof(SensorData)); // ArduiEmulator version...
210 #else
211  EEPROM.get(EEStore::pointer(), data);
212 #endif
213 #if defined(USE_TEXTCOMMAND)
214  tt = create(data.snum, data.pin, data.pullUp);
215 #else
216  tt = get(data.snum);
217 #ifdef DCCPP_DEBUG_MODE
218  if (tt == NULL)
219  INTERFACE.println(F("Sensor::begin() must be called BEFORE Sensor::load() !"));
220  else
221 #endif
222  tt->set(data.snum, data.pin, data.pullUp);
223 #endif
224  EEStore::advance(sizeof(tt->data));
225  }
226 }
227 
229 
230 void Sensor::store() {
231  Sensor *tt;
232 
233  tt = firstSensor;
234  EEStore::data.nSensors = 0;
235 
236  while (tt != NULL) {
237 #ifdef VISUALSTUDIO
238  EEPROM.put(EEStore::pointer(), (void *)&(tt->data), sizeof(SensorData)); // ArduiEmulator version...
239 #else
240  EEPROM.put(EEStore::pointer(), tt->data);
241 #endif
242  EEStore::advance(sizeof(tt->data));
243  tt = tt->nextSensor;
244  EEStore::data.nSensors++;
245  }
246 }
247 #endif
248 
249 #if defined(USE_TEXTCOMMAND)
250 
252 void Sensor::parse(char *c) {
253  int n, s, m;
254  // Sensor *t;
255 
256  switch (sscanf(c, "%d %d %d", &n, &s, &m)) {
257 
258  case 3: // argument is string with id number of sensor followed by a pin number and pullUp indicator (0=LOW/1=HIGH)
259  create(n, s, m);
260  break;
261 
262  case 1: // argument is a string with id number only
263  remove(n);
264  break;
265 
266 #ifdef DCCPP_PRINT_DCCPP
267  case -1: // no arguments
268  show();
269  break;
270 #endif
271 #ifdef USE_TEXTCOMMAND
272  case 2: // invalid number of arguments
273  INTERFACE.print("<X>");
274 #if !defined(USE_ETHERNET)
275  INTERFACE.println("");
276 #endif
277  break;
278 #endif
279  }
280 }
281 
283 
284 Sensor *Sensor::create(int snum, int pin, int pullUp) {
285  Sensor *tt = new Sensor();
286 
287  if (tt == NULL) { // problem allocating memory
288 #ifdef USE_TEXTCOMMAND
289  INTERFACE.print("<X>");
290 #if !defined(USE_ETHERNET)
291  INTERFACE.println("");
292 #endif
293 #endif
294  return(tt);
295  }
296 
297  tt->begin(snum, pin, pullUp);
298 
299  return(tt);
300 }
301 
302 #endif
303 
305 
306 Sensor *Sensor::firstSensor=NULL;
307 
308 #endif