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