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