Accessories
Arduino for motors and lights library.
Accessories.cpp
1 /*************************************************************
2 project: <Accessories>
3 author: <Thierry PARIS>
4 description: <Base functions of the library>
5 *************************************************************/
6 
7 #include "Accessories.hpp"
8 #include "ActionsStack.hpp"
9 #ifndef NO_EEPROM
10 #include "EEPROM.h"
11 #include "AccessoriesCircularBuffer.hpp"
12 #endif
13 
14 bool Accessories::SerialStarted = false;
15 unsigned long Accessories::WaitEndDate = 0;
16 #ifndef NO_EEPROM
17 int Accessories::EEPROMStart = -1;
18 int Accessories::EEPROMSize = -1;
19 int Accessories::EEPROMRecordSize = 0;
20 unsigned long Accessories::EEPROMStartingDelay = 0;
21 AccessoriesCircularBuffer Accessories::circularBuffer;
22 #endif
23 
24 void Accessories::begin(int inEEPROMStart, int inEEPROMSize)
25 {
26  SerialStarted = true;
27 
28 #ifndef NO_EEPROM
29  Accessories::EEPROMStart = inEEPROMStart;
30  Accessories::EEPROMSize = inEEPROMSize;
31  Accessories::EEPROMStartingDelay = 0;
32 #endif
33 
34 #ifdef ACCESSORIES_DEBUG_MODE
35  // Just for let the time to the PIC to initialize internals...
36  delay(500);
37 
38  Serial.println(F(""));
39  Serial.println(F("Accessories V1.1.0"));
40  Serial.println(F("Developed by Thierry Paris."));
41  Serial.println(F("(c) Locoduino 2016-2018"));
42  Serial.println(F(""));
43 
44  Serial.println(F("*** Setup Accessories started."));
45 
46 #ifndef NO_EEPROM
47  if (EEPROMStart + EEPROMSize != -2 && (EEPROMSize == -1 || EEPROMStart == -1))
48  {
49  Serial.print(F(" Error : EEPROM will not be used : "));
50  Serial.println(F(" EEPROMSize or EEPROMStart is not defined by begin."));
51  }
52 #endif
53 #endif
54 }
55 
56 #ifdef ACCESSORIES_DEBUG_MODE
57 void Accessories::printEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEventType, int inEventData)
58 {
59  Serial.print(F("Commander event : Address : "));
60  Serial.print(inId, DEC);
61  Serial.print(F(" / "));
62  switch (inEventType)
63  {
64  case ACCESSORIES_EVENT_NONE: Serial.println(F("NONE")); break;
65  case ACCESSORIES_EVENT_TOGGLE: Serial.println(F("TOGGLE")); break;
66  case ACCESSORIES_EVENT_MOVE:
67  Serial.print(F("MOVE "));
68  switch ((ACCESSORIES_MOVE_TYPE)inEventData)
69  {
70  case ACCESSORIES_MOVE_MORE: Serial.println(F("MORE")); break;
71  case ACCESSORIES_MOVE_LESS: Serial.println(F("LESS")); break;
72  case ACCESSORIES_MOVE_STOP: Serial.println(F("STOP")); break;
73  case ACCESSORIES_MOVE_LEFT: Serial.println(F("LEFT")); break;
74  case ACCESSORIES_MOVE_RIGHT: Serial.println(F("RIGHT")); break;
75  case ACCESSORIES_MOVE_CENTER: Serial.println(F("CENTER")); break;
76  case ACCESSORIES_MOVE_TOP: Serial.println(F("TOP")); break;
77  case ACCESSORIES_MOVE_BOTTOM: Serial.println(F("BOTTOM")); break;
78  case ACCESSORIES_MOVE_STRAIGHT: Serial.println(F("STRAIGHT")); break;
79  case ACCESSORIES_MOVE_DIVERGE: Serial.println(F("DIVERGE")); break;
80  case ACCESSORIES_MOVE_ON: Serial.println(F("ON")); break;
81  case ACCESSORIES_MOVE_OFF: Serial.println(F("OFF")); break;
82  }
83  break;
84  case ACCESSORIES_EVENT_MOVEPOSITION:
85  Serial.print(F("MOVEPOSITION : "));
86  Serial.println(inEventData, DEC);
87  break;
88  case ACCESSORIES_EVENT_MOVEPOSITIONID:
89  Serial.println(F("MOVEPOSITIONID "));
90  break;
91  case ACCESSORIES_EVENT_MOVEPOSITIONINDEX:
92  Serial.print(F("MOVEPOSITIONINDEX : "));
93  Serial.println(inEventData, DEC);
94  break;
95  case ACCESSORIES_EVENT_CONFIG:
96  Serial.print(F("CONFIG : "));
97  Serial.print(ACCESSORIESCONFIGADDRESS(inEventData), DEC);
98  Serial.print(F(" / "));
99  Serial.println(ACCESSORIESCONFIGVALUE(inEventData), DEC);
100  break;
101  case ACCESSORIES_EVENT_SETSPEED:
102  Serial.print(F("SET SPEED : "));
103  Serial.println(inEventData);
104  break;
105  case ACCESSORIES_EVENT_SETDURATION:
106  Serial.print(F("SET DURATION : "));
107  Serial.println(inEventData);
108  break;
109  //case ACCESSORIES_EVENT_SETSTARTPOSITION:
110  default:
111  break;
112  }
113 }
114 #endif
115 
116 void Accessories::RaiseEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData)
117 {
118  ReceiveEvent(inId, inEvent, inData);
119 }
120 
121 void Accessories::ReceiveEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEventType, int inEventData)
122 {
123 #ifdef VISUALSTUDIO
124  ArduiEmulator::ArduinoForm::_eventLog("Received", inId, inEventType, inEventData);
125 #endif
126 
127  Accessory::ExecuteEvent(inId, inEventType, inEventData);
128 #ifndef NO_GROUP
129  AccessoryGroup::EventAll(inId, inEventType, inEventData);
130 #endif
131 }
132 
133 #ifdef ACCESSORIES_PRINT_ACCESSORIES
135 {
136  Serial.println(F("********* Accessories List"));
138 
139  while (pCurr != NULL)
140  {
141  pCurr->printAccessory();
142  pCurr = pCurr->GetNextAccessory();
143  }
144  Serial.println(F("********* End of Accessories"));
145 
146 #ifndef NO_GROUP
147  Serial.println(F("********* Groups"));
148  AccessoryGroup::printGroups();
149  Serial.println(F("********* End of groups"));
150 #endif
151 }
152 #endif
153 
154 static Accessory *pLoopAccessory = NULL;
155 
157 {
158 #ifndef NO_GROUP
160 #endif
161 
162  if (pLoopAccessory == NULL)
163  {
164 #ifdef ACCESSORIES_DEBUG_MODE
165  Serial.println(F("*** Setup Accessories Finished."));
166 
168 
169  while (pCurr != NULL)
170  {
171  pCurr->CheckPort();
172  pCurr = pCurr->GetNextAccessory();
173  }
174 
175 #endif
176  pLoopAccessory = Accessory::GetFirstAccessory();
177 
178 #ifndef NO_EEPROM
179  // Do not take account of the modified states during setup !
180  EEPROMStartingDelay = 0;
181 
182 #ifdef ACCESSORIES_DEBUG_MODE
183  bool good = Accessories::EEPROMLoad();
184  if (!good)
185  Serial.println(F("EEPROM loading aborted !"));
186 #else
187  Accessories::EEPROMLoad();
188 #endif
189 #endif
190  }
191  else
192  {
193  if (pLoopAccessory->GetNextAccessory() == NULL)
194  pLoopAccessory = Accessory::GetFirstAccessory();
195  else
196  pLoopAccessory = pLoopAccessory->GetNextAccessory();
197  }
198 
199  if (pLoopAccessory == NULL)
200  return false;
201 
202  pLoopAccessory->loop();
203 
204  // Look for action stack pending...
206  return true;
207 
209  if (act != NULL)
210  Accessory::ExecuteEvent(act->Id, act->Event, act->Data);
211 
212  // If nothing more to do, Save EEPROM if needed.
213 
214 #ifndef NO_EEPROM
215  if (EEPROMStartingDelay > 0)
216  EEPROMSaveRaw();
217 #endif
218 
219  return false;
220 }
221 
222 void Accessories::wait(unsigned long inWaitDelay)
223 {
224  unsigned long start = millis();
225  while (millis() < start + inWaitDelay)
227 }
228 
229 #ifndef NO_EEPROM
230 
231 /* EEPROM format
232 
233 The EEPROM area starting from EEPROMStart, will be filled with the current version number (a byte),
234 and the total number of accessories and groups. The fourth byte will be the checksum of the three
235 starting bytes...
236 If any of these four bytes are different from the actual values, the EEPROM will be considered as free.
237 Two bytes are then added to store the size of one complete record, in order to be able to configure the CircularBuffer.
238 
239 Following these bytes, there is the CircularBuffer of accessories.
240 For each one the current state, the current position and the current speed will be saved.
241 After that, each group save its current item id.
242 
243  +-+
244 Version |V|
245 Accessory number |A|
246 Group number |G|
247 header checksum |C|
248 size byte 1 |s1]
249 size byte 2 |s2]
250  +-+
251 Circular buffer | |
252  +-+
253  End of file.
254 
255 One record of the Circular buffer is :
256 
257  +-+
258 Acc 1 : State |S|
259 Acc 1 : Position |P|
260 Acc 1 : Speed |s|
261  +-+
262 Acc 2 : State |S|
263 Acc 2 : Position |P|
264 Acc 2 : Speed |s|
265  +-+
266 Acc 3 : State |S|
267 Acc 3 : Position |P|
268 Acc 3 : Speed |s|
269 ... +-+
270 Group 1 : current ID |I|
271 Group 3 : current ID |I|
272 Group 3 : current ID |I|
273  +-+
274  End of record.
275 */
276 
277 // this version is used to know if the form have changed. During reloading, if the version is not equal to the
278 // actual version EEPROM_VERSION, the file will be considered as empty !
279 #define EEPROM_VERSION 0
280 
281 void Accessories::EEPROMSave()
282 {
283  if (EEPROMStart == -1 || EEPROMSize == -1)
284  return;
285 
286  if (EEPROMStartingDelay == 0)
287  EEPROMStartingDelay = millis();
288 }
289 
290 void Accessories::EEPROMSaveRaw()
291 {
292  unsigned long mill = millis();
293  if (mill - EEPROMStartingDelay < EEPROM_SAVE_DELAY)
294  return;
295 
296  int pos = EEPROMStart;
297 
298  uint8_t accCount = Accessory::GetCount();
299 #ifndef NO_GROUP
300  uint8_t grpCount = AccessoryGroup::GetCount();
301 #endif
302 
303  EEPROM.update(pos++, EEPROM_VERSION);
304  EEPROM.update(pos++, accCount);
305 #ifndef NO_GROUP
306  EEPROM.update(pos++, grpCount);
307 #endif
308 
309  EEPROM.update(pos++, EEPROMSize / 256);
310  EEPROM.update(pos++, EEPROMSize % 256);
311 
312  if (EEPROMRecordSize == 0)
313  {
314  // Compute the size to save it for the first time.
316 
317  while (pCurr != NULL)
318  {
319  EEPROMRecordSize = pCurr->EEPROMSave(EEPROMRecordSize, true);
320  pCurr = pCurr->GetNextAccessory();
321  }
322 
323 #ifndef NO_GROUP
324  EEPROMRecordSize = AccessoryGroup::EEPROMSaveAll(EEPROMRecordSize, true);
325 #endif
326 
327  circularBuffer.begin(pos+3, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
328  circularBuffer.clear();
329  }
330 
331  EEPROM.update(pos++, EEPROMRecordSize / 256);
332  EEPROM.update(pos++, EEPROMRecordSize % 256);
333 
334  EEPROM.update(pos++, (uint8_t) (EEPROM_VERSION + accCount +
335 #ifndef NO_GROUP
336  grpCount +
337 #endif
338  EEPROMSize + EEPROMRecordSize));
339 
340  pos = circularBuffer.startWrite();
342 
343  while (pCurr != NULL)
344  {
345  pos = pCurr->EEPROMSave(pos);
346  pCurr = pCurr->GetNextAccessory();
347  }
348 
349 #ifndef NO_GROUP
351 #endif
352  EEPROMStartingDelay = 0;
353 }
354 
355 bool Accessories::EEPROMLoad()
356 {
357  if (EEPROMStart == -1 || EEPROMSize == -1)
358  return false;
359 
360  int pos = EEPROMStart;
361  uint8_t accCount = Accessory::GetCount();
362 #ifndef NO_GROUP
363  uint8_t grpCount = AccessoryGroup::GetCount();
364 #endif
365 
366  if (EEPROM.read(pos++) != EEPROM_VERSION)
367  return false;
368 
369  if (EEPROM.read(pos++) != accCount)
370  return false;
371 
372 #ifndef NO_GROUP
373  if (EEPROM.read(pos++) != grpCount)
374 #endif
375  if (EEPROM.read(pos++) != accCount)
376  return false;
377 
378  byte b1, b2;
379  b1 = EEPROM.read(pos++);
380  b2 = EEPROM.read(pos++);
381  if (EEPROMSize != b1 * 256 + b2)
382  return false;
383 
384  b1 = EEPROM.read(pos++);
385  b2 = EEPROM.read(pos++);
386  EEPROMRecordSize = b1 * 256 + b2;
387 
388  if (EEPROM.read(pos++) != (uint8_t)(EEPROM_VERSION + accCount +
389 #ifndef NO_GROUP
390  grpCount +
391 #endif
392  EEPROMSize + EEPROMRecordSize))
393  {
394  EEPROMRecordSize = 0;
395  return false;
396  }
397 
398  circularBuffer.begin(pos, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
399 
400  // Start circular buffer just after the header.
401  pos = circularBuffer.getStartRead();
403 
404  while (pCurr != NULL)
405  {
406  pos = pCurr->EEPROMLoad(pos);
407  pCurr = pCurr->GetNextAccessory();
408  }
409 
410 #ifndef NO_GROUP
412 #endif
413  EEPROMStartingDelay = 0;
414 
415  return true;
416 }
417 #endif
static int EEPROMLoadAll(int inPos)
virtual int EEPROMLoad(int inPos)
static int EEPROMSaveAll(int inPos, bool inSimulate = false)
static uint8_t GetCount()
static uint8_t GetCount()
Definition: Accessory.cpp:293
virtual int EEPROMSave(int inPos, bool inSimulate = false)
static void ExecuteEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
Definition: Accessory.cpp:461
static void printAccessories()
static void EventAll(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static void RaiseEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static void ReceiveEvent(unsigned long inID, ACCESSORIES_EVENT_TYPE lastEventType, int inData)
static void begin(int inEEPROMStart = -1, int inEEPROMSize = -1)
Definition: Accessories.cpp:24
static void printEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEventType, int inEventData)
Definition: Accessories.cpp:57
Accessory * GetNextAccessory() const
Definition: Accessory.hpp:386
static bool loop()
static bool loops()
static bool IsActionPending()
Definition: Accessory.cpp:320
static ActionsStack Actions
bool loop()
Definition: Accessory.hpp:271
Action * GetActionToExecute()
static Accessory * GetFirstAccessory()
Definition: Accessory.hpp:381
static void wait(unsigned long inDelay)
unsigned long Id
ACCESSORIES_EVENT_TYPE Event