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