Accessories
Arduino for motors and lights library.
AccessoryGroup.cpp
1 /*************************************************************
2 project: <Accessories>
3 author: <Thierry PARIS>
4 description: <Class for a group of accessories>
5 *************************************************************/
6 
7 #include "Accessories.h"
8 #ifndef NO_EEPROM
9 #include "EEPROM.h"
10 #endif
11 
12 #ifndef NO_GROUP
13 #include "ActionsStack.hpp"
14 
15 #ifdef VISUALSTUDIO
16 #include<stdarg.h>
17 #endif
18 
19 #ifdef ACCESSORIES_DEBUG_MODE
20 #define CHECKINDEX(val, text) CheckIndex(val, F(text))
21 #define CHECKINDEXITEM(val, text) CheckIndex(val, F(text))
22 #else
23 #define CHECKINDEX(val, text)
24 #define CHECKINDEXITEM(val, text)
25 #endif
26 
27 /***********************************************************
28 * GroupStateItem
29 ************************************************************/
30 
31 #ifdef ACCESSORIES_PRINT_ACCESSORIES
32 void GroupStateItem::printAccessory()
33 {
34  Serial.print(F(" Acc : ID "));
35  Serial.print(this->pAccessory->GetMovingPositionIdByIndex(0));
36  Serial.print(F(" / State "));
37  Serial.print(this->State);
38  Serial.print(F(" / AssyncDelay "));
39  Serial.println(this->Delay);
40 }
41 #endif
42 
43 /***********************************************************
44 * GroupState
45 ************************************************************/
46 
47 GroupState::GroupState(unsigned long inId, bool inSynchrone)
48 {
49  this->Id = inId;
50  this->Synchronous = inSynchrone;
51  this->Items.HasCurrentNull = true;
52 }
53 
55 {
56 #ifdef ACCESSORIES_DEBUG_MODE
57  Serial.println(F(" GroupState begin"));
58 #endif
59 }
60 
61 /*void GroupState::begin(GroupStateItem *inpFirstItem, ...)
62 {
63  va_list argList;
64  this->Items.AddItem(*inpFirstItem);
65 
66  va_start(argList, inpFirstItem);
67  GroupStateItem *item = NULL;
68  do {
69  if (item != NULL)
70  this->Items.AddItem(*item);
71  item = va_arg(argList, GroupStateItem *);
72  } while (item != NULL);
73  va_end(argList);
74 } */
75 
76 void GroupState::Add(Accessory *inpAccessory, ACC_STATE inState, unsigned int inDelay)
77 {
78  this->Items.AddItem(new GroupStateItem(inpAccessory, inState, inDelay));
79 }
80 
82 {
83  if (this->IsActionItemPending())
84  {
85  this->Items.ResetCurrent();
86  return;
87  }
88 
89  this->startActionTime = 0;
90 
91  if (this->Synchronous)
92  {
93  ACCSCHAINEDLISTITEM<GroupStateItem> *pCurr = this->Items.pFirst;
94 
95  while (pCurr != NULL)
96  {
97  pCurr->Obj->pAccessory->StartAction(pCurr->Obj->State);
98  pCurr = pCurr->pNext;
99  }
100 
101  this->Items.ResetCurrent();
102  return;
103  }
104 
105  this->Items.StartCurrent();
106  if (this->Items.pCurrentItem->Obj->Delay != 0)
107  this->startActionTime = millis();
108 
109  this->Items.pCurrentItem->Obj->pAccessory->StartAction(this->Items.pCurrentItem->Obj->State);
110 }
111 
113 {
114  if (!this->IsActionItemPending())
115  return;
116 
117  if (this->Items.pCurrentItem->Obj->pAccessory->IsGroupActionPending())
118  return;
119 
120  if (this->startActionTime != 0)
121  if (millis() - this->startActionTime < this->Items.pCurrentItem->Obj->Delay)
122  return;
123 
124 #ifdef ACCESSORIES_DEBUG_MODE
125  Serial.print(F("AccessoryGroupState next action state accessory "));
126 #endif
127 
128  this->Items.NextCurrent();
129 
130  if (this->Items.HasCurrent())
131  this->Items.pCurrentItem->Obj->pAccessory->StartAction(this->Items.pCurrentItem->Obj->State);
132 }
133 
134 #ifdef ACCESSORIES_PRINT_ACCESSORIES
135 void GroupState::printAccessory()
136 {
137  Serial.print(F(" State : ID "));
138  Serial.println(this->Id);
139 
140  ACCSCHAINEDLISTITEM<GroupStateItem> *pCurr = this->Items.pFirst;
141 
142  while (pCurr != NULL)
143  {
144  pCurr->Obj->printAccessory();
145  pCurr = pCurr->pNext;
146  }
147 }
148 #endif
149 
150 /***********************************************************
151 * AccessoryGroup
152 ************************************************************/
153 
154 AccessoryGroup *AccessoryGroup::pFirstGroup = NULL;
155 
156 AccessoryGroup::AccessoryGroup()
157 {
158  this->States.HasCurrentNull = true;
159  this->pNextGroup = NULL;
160 
161  AddGroup(this);
162 }
163 
165 {
166 #ifdef ACCESSORIES_DEBUG_MODE
167  Serial.println(F(" AccessoryGroup begin"));
168 #endif
169 }
170 
171 void AccessoryGroup::AddStateItem(unsigned long inId, Accessory &inAccessory, ACC_STATE inState, unsigned int inDelay)
172 {
173  GroupState *pState = this->GetByID(inId);
174 
175  if (pState == NULL)
176  {
177 #ifdef ACCESSORIES_DEBUG_MODE
178  Serial.println(F(" AccessoryGroup wrong state id !"));
179 #endif
180  return;
181  }
182 
183  pState->Add(&inAccessory, inState, inDelay);
184 }
185 
186 void AccessoryGroup::AddGroup(AccessoryGroup *inGroup)
187 {
188  if (AccessoryGroup::pFirstGroup == NULL)
189  {
190  AccessoryGroup::pFirstGroup = inGroup;
191  inGroup->SetNextGroup(NULL);
192  return;
193  }
194 
195  AccessoryGroup *pCurr = AccessoryGroup::pFirstGroup;
196 
197  while (pCurr->GetNextGroup() != NULL)
198  pCurr = pCurr->GetNextGroup();
199 
200  pCurr->SetNextGroup(inGroup);
201  inGroup->SetNextGroup(NULL);
202 }
203 
205 {
206  ACCSCHAINEDLISTITEM<GroupState> *pCurr = inGroup.States.pFirst;
207 
208  while (pCurr != NULL)
209  {
210  this->States.AddItem(pCurr->Obj);
211  pCurr = pCurr->pNext;
212  }
213 }
214 
216 {
217  uint8_t count = 0;
218  AccessoryGroup *pCurr = AccessoryGroup::pFirstGroup;
219  while (pCurr != NULL)
220  {
221  count++;
222  pCurr = pCurr->GetNextGroup();
223  }
224 
225  return count;
226 }
227 
228 GroupState *AccessoryGroup::GetByID(unsigned long inId) const
229 {
230  ACCSCHAINEDLISTITEM<GroupState> *pItem = this->GetItemByID(inId);
231 
232  if (pItem == NULL)
233  return NULL;
234 
235  return pItem->Obj;
236 }
237 
239 {
240  ACCSCHAINEDLISTITEM<GroupState> *pCurr = this->States.pFirst;
241 
242  while (pCurr != NULL)
243  {
244  if (pCurr->Obj->GetId() == inId)
245  return pCurr;
246  pCurr = pCurr->pNext;
247  }
248 
249  return NULL;
250 }
251 
253 {
254  return (this->States.HasCurrent());
255 }
256 
258 {
259 #ifdef ACCESSORIES_DEBUG_MODE
260  Serial.print(F("AccessoryGroup start action state "));
261  Serial.println(inpState->GetId());
262 #endif
263 
264  ACCSCHAINEDLISTITEM<GroupState> *pCurr = this->States.pFirst;
265 
266  while (pCurr != NULL)
267  {
268  if (pCurr->Obj == inpState)
269  {
270  this->States.pCurrentItem = pCurr;
271 #ifndef NO_EEPROM
272  Accessories::EEPROMSave();
273 #endif
274  pCurr->Obj->StartAction();
275  return;
276  }
277  pCurr = pCurr->pNext;
278  }
279 }
280 
282 {
283  if (!this->IsActionItemPending())
284  return false; // nothing done !
285 
286  this->States.pCurrentItem->Obj->loop();
287  if (!this->States.pCurrentItem->Obj->IsActionItemPending())
288  this->States.ResetCurrent();
289  return true;
290 }
291 
292 static AccessoryGroup *pLoopGroup = NULL;
293 
295 {
296  if (pLoopGroup == NULL)
297  {
298  pLoopGroup = AccessoryGroup::pFirstGroup;
299  }
300  else
301  {
302  if (pLoopGroup->GetNextGroup() == NULL)
303  pLoopGroup = AccessoryGroup::pFirstGroup;
304  else
305  pLoopGroup = pLoopGroup->GetNextGroup();
306  }
307 
308  if (pLoopGroup == NULL)
309  return false;
310 
311  return pLoopGroup->loop();
312 }
313 
314 void AccessoryGroup::EventAll(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData)
315 {
316  AccessoryGroup *pCurr = AccessoryGroup::pFirstGroup;
317 
318  while (pCurr != NULL)
319  {
320  ACCSCHAINEDLISTITEM<GroupState> *pCurrState = pCurr->States.pFirst;
321 
322  while (pCurrState != NULL)
323  {
324  if (pCurrState->Obj->GetId() == inId)
325  break;
326  pCurrState = pCurrState->pNext;
327  }
328 
329  if (pCurrState != NULL)
330  break;
331 
332  pCurr = pCurr->GetNextGroup();
333  }
334 
335  if (pCurr != NULL)
336  pCurr->Event(inId, inEvent, inData);
337 }
338 
339 void AccessoryGroup::Event(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData)
340 {
341  this->Toggle(inId);
342 }
343 
344 bool AccessoryGroup::Toggle(unsigned long inId)
345 {
346  ACCSCHAINEDLISTITEM<GroupState> *pCurr = this->States.pFirst;
347 
348  while (pCurr != NULL)
349  {
350  if (pCurr->Obj->GetId() == inId)
351  break;
352  pCurr = pCurr->pNext;
353  }
354 
355  if (pCurr == NULL)
356  return false;
357 
359  {
360  ActionsStack::Actions.Add(inId, ACCESSORIES_EVENT_MOVEPOSITIONID);
361  return true;
362  }
363 
364 #ifdef ACCESSORIES_DEBUG_MODE
365  Serial.print(F("AccessoryGroup moved "));
366  Serial.println(inId);
367 #endif
368  if (!this->IsActionItemPending())
369  {
370 #ifdef ACCESSORIES_DEBUG_MODE
371  Serial.println(F("No action item pending..."));
372 #endif
373  this->States.pCurrentItem = pCurr;
374 #ifndef NO_EEPROM
375  Accessories::EEPROMSave();
376 #endif
377  pCurr->Obj->StartAction();
378  }
379 
380  return true;
381 }
382 
383 #ifndef NO_EEPROM
384 int AccessoryGroup::EEPROMSave(int inPos, bool inSimulate)
385 {
386  if (!inSimulate)
387  {
388  if (this->States.pCurrentItem != NULL)
389  {
390  unsigned long id = this->States.pCurrentItem->Obj->GetId();
391  byte *pEvent = (byte *)&id;
392  EEPROM.write(inPos, *pEvent);
393  EEPROM.write(inPos+1, *(pEvent + 1));
394  EEPROM.write(inPos+2, *(pEvent + 2));
395  EEPROM.write(inPos+3, *(pEvent + 3));
396  }
397  else
398  {
399  EEPROM.write(inPos, 0);
400  EEPROM.write(inPos+1, 0);
401  EEPROM.write(inPos+2, 0);
402  EEPROM.write(inPos+3, 0);
403  }
404  }
405 
406  inPos += sizeof(unsigned long);
407 
408  return inPos;
409 }
410 
411 int AccessoryGroup::EEPROMLoad(int inPos)
412 {
413  long four = EEPROM.read(inPos++);
414  long three = EEPROM.read(inPos++);
415  long two = EEPROM.read(inPos++);
416  long one = EEPROM.read(inPos++);
417 
418  if (one+two+three+four > 0)
419  {
420  //Rebuild the recomposed long by using bitshift.
421  unsigned long ID = ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
422 
424  this->States.pCurrentItem = grp;
425  }
426  else
427  {
428  this->States.pCurrentItem = NULL;
429  }
430 
431  return inPos;
432 }
433 
434 int AccessoryGroup::EEPROMSaveAll(int inPos, bool inSimulate)
435 {
436  AccessoryGroup *pCurr = pFirstGroup;
437 
438  while (pCurr != NULL)
439  {
440  inPos = pCurr->EEPROMSave(inPos, inSimulate);
441  pCurr = pCurr->pNextGroup;
442  }
443 
444  return inPos;
445 }
446 
447 int AccessoryGroup::EEPROMLoadAll(int inPos)
448 {
449  AccessoryGroup *pCurr = pFirstGroup;
450 
451  while (pCurr != NULL)
452  {
453  inPos = pCurr->EEPROMLoad(inPos);
454  pCurr = pCurr->pNextGroup;
455  }
456 
457  return inPos;
458 }
459 #endif
460 
461 #ifdef ACCESSORIES_PRINT_ACCESSORIES
462 void AccessoryGroup::printGroups()
463 {
464  AccessoryGroup *pCurr = pFirstGroup;
465 
466  while (pCurr != NULL)
467  {
468  pCurr->printAccessory();
469  pCurr = pCurr->pNextGroup;
470  }
471 }
472 
473 void AccessoryGroup::printAccessory()
474 {
475  Serial.println(F(" Group : "));
476 
477  ACCSCHAINEDLISTITEM<GroupState> *pCurr = this->States.pFirst;
478 
479  while (pCurr != NULL)
480  {
481  pCurr->Obj->printAccessory();
482  pCurr = pCurr->pNext;
483  }
484 }
485 #endif
486 #endif
static int EEPROMLoadAll(int inPos)
static int EEPROMSaveAll(int inPos, bool inSimulate = false)
int EEPROMLoad(int inPos)
unsigned char Add(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData = 0)
static ActionsStack Actions
static bool FillingStack
void Event(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
static void EventAll(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
unsigned long GetId() const
void StartAction(GroupState *inpState)
bool IsActionItemPending()
static uint8_t GetCount()
void AddRange(const AccessoryGroup &inGroup)
GroupState * GetByID(unsigned long inId) const
void AddStateItem(unsigned long inId, Accessory &inAccessory, ACC_STATE inState, unsigned int inDelay = 0)
bool HasCurrent()
Definition: Chain.hpp:59
void NextCurrent()
Definition: Chain.hpp:99
ACCSCHAINEDLISTITEM< T > * pCurrentItem
Definition: Chain.hpp:39
virtual bool IsGroupActionPending() const
Definition: Accessory.hpp:430
void StartCurrent()
Definition: Chain.hpp:55
virtual void StartAction()
Definition: Accessory.cpp:136
ACCSCHAINEDLISTITEM * pNext
Definition: Chain.hpp:13
static bool loops()
ACCSCHAINEDLISTITEM< T > * pFirst
Definition: Chain.hpp:37
ACCSCHAINEDLISTITEM< GroupState > * GetItemByID(unsigned long inId) const
void ResetCurrent()
Definition: Chain.hpp:53
bool IsActionItemPending()
void StartAction()
bool Toggle(unsigned long inId)
void AddItem(T *t)
Definition: Chain.hpp:71
void Add(Accessory *inpAccessory, ACC_STATE inState, unsigned int inDelay = 0)
bool HasCurrentNull
Definition: Chain.hpp:41
int EEPROMSave(int inPos, bool inSimulate = false)
unsigned long GetMovingPositionIdByIndex(uint8_t inIndex) const
Definition: Accessory.hpp:339