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