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(LIBRARY_VERSION));
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  _eventLog(_T("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 
208  unsigned char actionIndex = ActionsStack::Actions.GetActionToExecute();
209  if (actionIndex != 255)
210  {
211  Action *act = ActionsStack::Actions[actionIndex];
212  Accessory::ExecuteEvent(act->Id, act->Event, act->Data);
213  ActionsStack::Actions.Delete(actionIndex);
214  }
215 
216  // If nothing more to do, Save EEPROM if needed.
217 
218 #ifndef NO_EEPROM
219  if (EEPROMStartingDelay > 0)
220  EEPROMSaveRaw();
221 #endif
222 
223  return false;
224 }
225 
226 void Accessories::wait(unsigned long inWaitDelay)
227 {
228  unsigned long start = millis();
229  while (millis() < start + inWaitDelay)
231 }
232 
233 #ifndef NO_EEPROM
234 
235 /* EEPROM format
236 
237 The EEPROM area starting from EEPROMStart, will be filled with the current version number (a byte),
238 and the total number of accessories and groups. The fourth byte will be the checksum of the three
239 starting bytes...
240 If any of these four bytes are different from the actual values, the EEPROM will be considered as free.
241 Two bytes are then added to store the size of one complete record, in order to be able to configure the CircularBuffer.
242 
243 Following these bytes, there is the CircularBuffer of accessories.
244 For each one the current state, the current position and the current speed will be saved.
245 After that, each group save its current item id.
246 
247  +-+
248 Version |V|
249 Accessory number |A|
250 Group number |G|
251 header checksum |C|
252 size byte 1 |s1]
253 size byte 2 |s2]
254  +-+
255 Circular buffer | |
256  +-+
257  End of file.
258 
259 One record of the Circular buffer is :
260 
261  +-+
262 Acc 1 : State |S|
263 Acc 1 : Position |P|
264 Acc 1 : Speed |s|
265  +-+
266 Acc 2 : State |S|
267 Acc 2 : Position |P|
268 Acc 2 : Speed |s|
269  +-+
270 Acc 3 : State |S|
271 Acc 3 : Position |P|
272 Acc 3 : Speed |s|
273 ... +-+
274 Group 1 : current ID |I|
275 Group 3 : current ID |I|
276 Group 3 : current ID |I|
277  +-+
278  End of record.
279 */
280 
281 // this version is used to know if the form have changed. During reloading, if the version is not equal to the
282 // actual version EEPROM_VERSION, the file will be considered as empty !
283 #define EEPROM_VERSION 0
284 
285 void Accessories::EEPROMSave()
286 {
287  if (EEPROMStart == -1 || EEPROMSize == -1)
288  return;
289 
290  if (EEPROMStartingDelay == 0)
291  EEPROMStartingDelay = millis();
292 }
293 
294 void Accessories::EEPROMSaveRaw()
295 {
296  unsigned long mill = millis();
297  if (mill - EEPROMStartingDelay < EEPROM_SAVE_DELAY)
298  return;
299 
300  int pos = EEPROMStart;
301 
302  uint8_t accCount = Accessory::GetCount();
303 #ifndef NO_GROUP
304  uint8_t grpCount = AccessoryGroup::GetCount();
305 #endif
306 
307  EEPROM.update(pos++, EEPROM_VERSION);
308  EEPROM.update(pos++, accCount);
309 #ifndef NO_GROUP
310  EEPROM.update(pos++, grpCount);
311 #endif
312 
313  EEPROM.update(pos++, EEPROMSize / 256);
314  EEPROM.update(pos++, EEPROMSize % 256);
315 
316  if (EEPROMRecordSize == 0)
317  {
318  // Compute the size to save it for the first time.
320 
321  while (pCurr != NULL)
322  {
323  EEPROMRecordSize = pCurr->EEPROMSave(EEPROMRecordSize, true);
324  pCurr = pCurr->GetNextAccessory();
325  }
326 
327 #ifndef NO_GROUP
328  EEPROMRecordSize = AccessoryGroup::EEPROMSaveAll(EEPROMRecordSize, true);
329 #endif
330 
331  circularBuffer.begin(pos+3, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
332  circularBuffer.clear();
333  }
334 
335  EEPROM.update(pos++, EEPROMRecordSize / 256);
336  EEPROM.update(pos++, EEPROMRecordSize % 256);
337 
338  EEPROM.update(pos++, (uint8_t) (EEPROM_VERSION + accCount +
339 #ifndef NO_GROUP
340  grpCount +
341 #endif
342  EEPROMSize + EEPROMRecordSize));
343 
344  pos = circularBuffer.startWrite();
346 
347  while (pCurr != NULL)
348  {
349  pos = pCurr->EEPROMSave(pos);
350  pCurr = pCurr->GetNextAccessory();
351  }
352 
353 #ifndef NO_GROUP
355 #endif
356  EEPROMStartingDelay = 0;
357 }
358 
359 bool Accessories::EEPROMLoad()
360 {
361  if (EEPROMStart == -1 || EEPROMSize == -1)
362  return false;
363 
364  int pos = EEPROMStart;
365  uint8_t accCount = Accessory::GetCount();
366 #ifndef NO_GROUP
367  uint8_t grpCount = AccessoryGroup::GetCount();
368 #endif
369 
370  if (EEPROM.read(pos++) != EEPROM_VERSION)
371  return false;
372 
373  if (EEPROM.read(pos++) != accCount)
374  return false;
375 
376 #ifndef NO_GROUP
377  if (EEPROM.read(pos++) != grpCount)
378 #endif
379  if (EEPROM.read(pos++) != accCount)
380  return false;
381 
382  byte b1, b2;
383  b1 = EEPROM.read(pos++);
384  b2 = EEPROM.read(pos++);
385  if (EEPROMSize != b1 * 256 + b2)
386  return false;
387 
388  b1 = EEPROM.read(pos++);
389  b2 = EEPROM.read(pos++);
390  EEPROMRecordSize = b1 * 256 + b2;
391 
392  if (EEPROM.read(pos++) != (uint8_t)(EEPROM_VERSION + accCount +
393 #ifndef NO_GROUP
394  grpCount +
395 #endif
396  EEPROMSize + EEPROMRecordSize))
397  {
398  EEPROMRecordSize = 0;
399  return false;
400  }
401 
402  circularBuffer.begin(pos, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
403 
404  // Start circular buffer just after the header.
405  pos = circularBuffer.getStartRead();
407 
408  while (pCurr != NULL)
409  {
410  pos = pCurr->EEPROMLoad(pos);
411  pCurr = pCurr->GetNextAccessory();
412  }
413 
414 #ifndef NO_GROUP
416 #endif
417  EEPROMStartingDelay = 0;
418 
419  return true;
420 }
421 #endif
static int EEPROMLoadAll(int inPos)
virtual int EEPROMLoad(int inPos)
#define NO_GROUP
Definition: Accessories.h:433
static int EEPROMSaveAll(int inPos, bool inSimulate = false)
static uint8_t GetCount()
static void wait(unsigned long inDelay)
static void printAccessories()
static void EventAll(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static bool IsActionPending()
Definition: Accessory.cpp:321
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:462
static void begin(int inEEPROMStart = -1, int inEEPROMSize = -1)
Definition: Accessories.cpp:24
static void ReceiveEvent(unsigned long inID, ACCESSORIES_EVENT_TYPE lastEventType, int inData)
static void RaiseEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static Accessory * GetFirstAccessory()
Definition: Accessory.hpp:381
static bool loop()
static void printEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEventType, int inEventData)
Definition: Accessories.cpp:57
static ActionsStack Actions
unsigned char GetActionToExecute()
Accessory * GetNextAccessory() const
Definition: Accessory.hpp:386
static bool loops()
unsigned long Id
bool loop()
Definition: Accessory.hpp:271
ACCESSORIES_EVENT_TYPE Event
static uint8_t GetCount()
Definition: Accessory.cpp:294
void Delete(int inIndex)