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.0.1"));
40  Serial.println(F("Developed by Thierry Paris."));
41  Serial.println(F("(c) Locoduino 2016-2017"));
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  //case ACCESSORIES_EVENT_SETSTARTPOSITION:
103  default:
104  break;
105  }
106 }
107 #endif
108 
109 void Accessories::RaiseEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData)
110 {
111  ReceiveEvent(inId, inEvent, inData);
112 }
113 
114 void Accessories::ReceiveEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEventType, int inEventData)
115 {
116 #ifdef VISUALSTUDIO
117  ArduiEmulator::ArduinoForm::_eventLog("Received", inId, inEventType, inEventData);
118 #endif
119 
120  Accessory::ExecuteEvent(inId, inEventType, inEventData);
121 #ifndef NO_GROUP
122  AccessoryGroup::EventAll(inId, inEventType, inEventData);
123 #endif
124 }
125 
126 #ifdef ACCESSORIES_PRINT_ACCESSORIES
127 void Accessories::printAccessories()
128 {
129  Serial.println(F("********* Accessories List"));
131 
132  while (pCurr != NULL)
133  {
134  pCurr->printAccessory();
135  pCurr = pCurr->GetNextAccessory();
136  }
137  Serial.println(F("********* End of Accessories"));
138 
139  Serial.println(F("********* Groups"));
140  AccessoryGroup::printGroups();
141  Serial.println(F("********* End of groups"));
142 }
143 #endif
144 
145 static Accessory *pLoopAccessory = NULL;
146 
148 {
149 #ifndef NO_GROUP
151 #endif
152 
153  if (pLoopAccessory == NULL)
154  {
155 #ifdef ACCESSORIES_DEBUG_MODE
156  Serial.println(F("*** Setup Accessories Finished."));
157 
159 
160  while (pCurr != NULL)
161  {
162  pCurr->CheckPort();
163  pCurr = pCurr->GetNextAccessory();
164  }
165 
166 #endif
167  pLoopAccessory = Accessory::GetFirstAccessory();
168 
169 #ifndef NO_EEPROM
170  // Do not take account of the modified states during setup !
171  EEPROMStartingDelay = 0;
172 
173 #ifdef ACCESSORIES_DEBUG_MODE
174  bool good = Accessories::EEPROMLoad();
175  if (!good)
176  Serial.println(F("EEPROM loading aborted !"));
177 #else
178  Accessories::EEPROMLoad();
179 #endif
180 #endif
181  }
182  else
183  {
184  if (pLoopAccessory->GetNextAccessory() == NULL)
185  pLoopAccessory = Accessory::GetFirstAccessory();
186  else
187  pLoopAccessory = pLoopAccessory->GetNextAccessory();
188  }
189 
190  if (pLoopAccessory == NULL)
191  return false;
192 
193  pLoopAccessory->loop();
194 
195  // Look for action stack pending...
197  return true;
198 
200  if (act != NULL)
201  Accessory::ExecuteEvent(act->Id, act->Event, act->Data);
202 
203  // If nothing more to do, Save EEPROM if needed.
204 
205 #ifndef NO_EEPROM
206  if (EEPROMStartingDelay > 0)
207  EEPROMSaveRaw();
208 #endif
209 
210  return false;
211 }
212 
213 void Accessories::wait(unsigned long inWaitDelay)
214 {
215  unsigned long start = millis();
216  while (millis() < start + inWaitDelay)
218 }
219 
220 #ifndef NO_EEPROM
221 
222 /* EEPROM format
223 
224 The EEPROM area starting from EEPROMStart, will be filled with the current version number (a byte),
225 and the total number of accessories and groups. The fourth byte will be the checksum of the three
226 starting bytes...
227 If any of these four bytes are different from the actual values, the EEPROM will be considered as free.
228 Two bytes are then added to store the size of one complete record, in order to be able to configurate the CircularBuffer.
229 
230 Following these bytes, there is the CircularBuffer of accessories.
231 For each one the current state, the current position and the current speed will be saved.
232 After that, each group save its current item id.
233 
234  +-+
235 Version |V|
236 Accessory number |A|
237 Group number |G|
238 header checksum |C|
239 size byte 1 |s1]
240 size byte 2 |s2]
241  +-+
242 Circular buffer | |
243  +-+
244  End of file.
245 
246 One record of the Circular buffer is :
247 
248  +-+
249 Acc 1 : State |S|
250 Acc 1 : Position |P|
251 Acc 1 : Speed |s|
252  +-+
253 Acc 2 : State |S|
254 Acc 2 : Position |P|
255 Acc 2 : Speed |s|
256  +-+
257 Acc 3 : State |S|
258 Acc 3 : Position |P|
259 Acc 3 : Speed |s|
260 ... +-+
261 Group 1 : current ID |I|
262 Group 3 : current ID |I|
263 Group 3 : current ID |I|
264  +-+
265  End of record.
266 */
267 
268 // this version is used to know if the form have changed. During reloading, if the version is not equal to the
269 // actual version EEPROM_VERSION, the file will be considered as empty !
270 #define EEPROM_VERSION 0
271 
272 void Accessories::EEPROMSave()
273 {
274  if (EEPROMStart == -1 || EEPROMSize == -1)
275  return;
276 
277  if (EEPROMStartingDelay == 0)
278  EEPROMStartingDelay = millis();
279 }
280 
281 void Accessories::EEPROMSaveRaw()
282 {
283  unsigned long mill = millis();
284  if (mill - EEPROMStartingDelay < EEPROM_SAVE_DELAY)
285  return;
286 
287  int pos = EEPROMStart;
288 
289  uint8_t accCount = Accessory::GetCount();
290  uint8_t grpCount = AccessoryGroup::GetCount();
291 
292  EEPROM.update(pos++, EEPROM_VERSION);
293  EEPROM.update(pos++, accCount);
294  EEPROM.update(pos++, grpCount);
295 
296  EEPROM.update(pos++, EEPROMSize / 256);
297  EEPROM.update(pos++, EEPROMSize % 256);
298 
299  if (EEPROMRecordSize == 0)
300  {
301  // Compute the size to save it for the first time.
303 
304  while (pCurr != NULL)
305  {
306  EEPROMRecordSize = pCurr->EEPROMSave(EEPROMRecordSize, true);
307  pCurr = pCurr->GetNextAccessory();
308  }
309 
310  EEPROMRecordSize = AccessoryGroup::EEPROMSaveAll(EEPROMRecordSize, true);
311 
312  circularBuffer.begin(pos+3, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
313  circularBuffer.clear();
314  }
315 
316  EEPROM.update(pos++, EEPROMRecordSize / 256);
317  EEPROM.update(pos++, EEPROMRecordSize % 256);
318 
319  EEPROM.update(pos++, (uint8_t) (EEPROM_VERSION + accCount + grpCount + EEPROMSize + EEPROMRecordSize));
320 
321  pos = circularBuffer.startWrite();
323 
324  while (pCurr != NULL)
325  {
326  pos = pCurr->EEPROMSave(pos);
327  pCurr = pCurr->GetNextAccessory();
328  }
329 
331  EEPROMStartingDelay = 0;
332 }
333 
334 bool Accessories::EEPROMLoad()
335 {
336  if (EEPROMStart == -1 || EEPROMSize == -1)
337  return false;
338 
339  int pos = EEPROMStart;
340  uint8_t accCount = Accessory::GetCount();
341  uint8_t grpCount = AccessoryGroup::GetCount();
342 
343  if (EEPROM.read(pos++) != EEPROM_VERSION)
344  return false;
345 
346  if (EEPROM.read(pos++) != accCount)
347  return false;
348 
349  if (EEPROM.read(pos++) != grpCount)
350  if (EEPROM.read(pos++) != accCount)
351  return false;
352 
353  byte b1, b2;
354  b1 = EEPROM.read(pos++);
355  b2 = EEPROM.read(pos++);
356  if (EEPROMSize != b1 * 256 + b2)
357  return false;
358 
359  b1 = EEPROM.read(pos++);
360  b2 = EEPROM.read(pos++);
361  EEPROMRecordSize = b1 * 256 + b2;
362 
363  if (EEPROM.read(pos++) != (uint8_t)(EEPROM_VERSION + accCount + grpCount + EEPROMSize + EEPROMRecordSize))
364  {
365  EEPROMRecordSize = 0;
366  return false;
367  }
368 
369  circularBuffer.begin(pos, EEPROMRecordSize, (EEPROMSize - 10) / EEPROMRecordSize);
370 
371  // Start circular buffer just after the header.
372  pos = circularBuffer.getStartRead();
374 
375  while (pCurr != NULL)
376  {
377  pos = pCurr->EEPROMLoad(pos);
378  pCurr = pCurr->GetNextAccessory();
379  }
380 
382  EEPROMStartingDelay = 0;
383 
384  return true;
385 }
386 #endif
static int EEPROMSaveAll(int inPos, bool inSimulate = false)
virtual int EEPROMSave(int inPos, bool inSimulate = false)
virtual int EEPROMLoad(int inPos)
static bool loop()
static Accessory * GetFirstAccessory()
Definition: Accessory.hpp:355
static void wait(unsigned long inDelay)
Accessory * GetNextAccessory() const
Definition: Accessory.hpp:360
static void EventAll(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static void ExecuteEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
Definition: Accessory.cpp:388
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 uint8_t GetCount()
ACCESSORIES_EVENT_TYPE Event
Action * GetActionToExecute()
static int EEPROMLoadAll(int inPos)
static uint8_t GetCount()
Definition: Accessory.cpp:233
static bool loops()
bool loop()
Definition: Accessory.hpp:259
static bool IsActionPending()
Definition: Accessory.cpp:260
unsigned long Id
static ActionsStack Actions