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 #if defined(USE_ETHERNET)
129  INTERFACE.print("<Q");
130  INTERFACE.print(tt->data.snum);
131  INTERFACE.print(">");
132 #endif
133  } else if(tt->active && tt->signal>0.9){
134  tt->active=false;
135 #if defined(USE_ETHERNET)
136  INTERFACE.print("<q");
137  INTERFACE.print(tt->data.snum);
138  INTERFACE.print(">");
139 #endif
140  }
141  } // loop over all sensors
142 
143 } // Sensor::check
144 
145 #ifdef DCCPP_PRINT_DCCPP
146 
148 void Sensor::show() {
149  Sensor *tt;
150 
151  if (firstSensor == NULL) {
152  INTERFACE.print("<X>");
153 #if !defined(USE_ETHERNET)
154  INTERFACE.println("");
155 #endif
156  return;
157  }
158 
159  for (tt = firstSensor; tt != NULL; tt = tt->nextSensor) {
160  INTERFACE.print("<Q");
161  INTERFACE.print(tt->data.snum);
162  INTERFACE.print(" ");
163  INTERFACE.print(tt->data.pin);
164  INTERFACE.print(" ");
165  INTERFACE.print(tt->data.pullUp);
166  INTERFACE.print(">");
167 #if !defined(USE_ETHERNET)
168  INTERFACE.println("");
169 #endif
170  }
171 }
172 
174 
175 void Sensor::status() {
176  Sensor *tt;
177 
178  if (firstSensor == NULL) {
179  INTERFACE.print("<X>");
180 #if !defined(USE_ETHERNET)
181  INTERFACE.println("");
182 #endif
183  return;
184  }
185 
186  for (tt = firstSensor; tt != NULL; tt = tt->nextSensor) {
187  INTERFACE.print(tt->active ? "<Q" : "<q");
188  INTERFACE.print(tt->data.snum);
189  INTERFACE.print(">");
190 #if !defined(USE_ETHERNET)
191  INTERFACE.println("");
192 #endif
193  }
194 }
195 
196 #endif
197 
198 #ifdef USE_EEPROM
199 
201 void Sensor::load() {
202  struct SensorData data;
203  Sensor *tt;
204 
205  for (int i = 0; i<EEStore::data.nSensors; i++) {
206 #ifdef VISUALSTUDIO
207  EEPROM.get(EEStore::pointer(), (void *)&(data), sizeof(SensorData)); // ArduiEmulator version...
208 #else
209  EEPROM.get(EEStore::pointer(), data);
210 #endif
211 #if defined(USE_TEXTCOMMAND)
212  tt = create(data.snum, data.pin, data.pullUp);
213 #else
214  tt = get(data.snum);
215 #ifdef DCCPP_DEBUG_MODE
216  if (tt == NULL)
217  INTERFACE.println(F("Sensor::begin() must be called BEFORE Sensor::load() !"));
218  else
219 #endif
220  tt->set(data.snum, data.pin, data.pullUp);
221 #endif
222  EEStore::advance(sizeof(tt->data));
223  }
224 }
225 
227 
228 void Sensor::store() {
229  Sensor *tt;
230 
231  tt = firstSensor;
232  EEStore::data.nSensors = 0;
233 
234  while (tt != NULL) {
235 #ifdef VISUALSTUDIO
236  EEPROM.put(EEStore::pointer(), (void *)&(tt->data), sizeof(SensorData)); // ArduiEmulator version...
237 #else
238  EEPROM.put(EEStore::pointer(), tt->data);
239 #endif
240  EEStore::advance(sizeof(tt->data));
241  tt = tt->nextSensor;
242  EEStore::data.nSensors++;
243  }
244 }
245 #endif
246 
247 #if defined(USE_TEXTCOMMAND)
248 
250 void Sensor::parse(char *c) {
251  int n, s, m;
252  // Sensor *t;
253 
254  switch (sscanf(c, "%d %d %d", &n, &s, &m)) {
255 
256  case 3: // argument is string with id number of sensor followed by a pin number and pullUp indicator (0=LOW/1=HIGH)
257  create(n, s, m);
258  break;
259 
260  case 1: // argument is a string with id number only
261  remove(n);
262  break;
263 
264 #ifdef DCCPP_PRINT_DCCPP
265  case -1: // no arguments
266  show();
267  break;
268 #endif
269 #ifdef USE_TEXTCOMMAND
270  case 2: // invalid number of arguments
271  INTERFACE.print("<X>");
272 #if !defined(USE_ETHERNET)
273  INTERFACE.println("");
274 #endif
275  break;
276 #endif
277  }
278 }
279 
281 
282 Sensor *Sensor::create(int snum, int pin, int pullUp) {
283  Sensor *tt = new Sensor();
284 
285  if (tt == NULL) { // problem allocating memory
286 #ifdef USE_TEXTCOMMAND
287  INTERFACE.print("<X>");
288 #if !defined(USE_ETHERNET)
289  INTERFACE.println("");
290 #endif
291 #endif
292  return(tt);
293  }
294 
295  tt->begin(snum, pin, pullUp);
296 
297  return(tt);
298 }
299 
300 #endif
301 
303 
304 Sensor *Sensor::firstSensor=NULL;
305 
306 #endif