Accessories
Arduino for motors and lights library.
Accessory.cpp
1 /*************************************************************
2 project: <Accessories>
3 author: <Thierry PARIS>
4 description: <Class for a generic accessory>
5 *************************************************************/
6 
7 #include "Accessories.h"
8 #include "ActionsStack.hpp"
9 #ifndef NO_EEPROM
10 #include "EEPROM.h"
11 #endif
12 
13 Accessory *Accessory::pFirstAccessory = NULL;
14 
16 {
17  this->pPort = NULL;
18  this->movingPositionsSize = 0;
19  this->movingPositionsAddCounter = 0;
20  this->pMovingPositions = NULL;
21  this->pMovingPositions_P = NULL;
22  this->lastMovingPosition = 255;
23  this->debounceDelay = 50;
24  this->SetLastMoveTime();
25 
26  this->duration = 0;
27  this->startingMillis = 0;
28  Accessory::Add(this);
29 }
30 
31 void Accessory::AdjustMovingPositionsSize(uint8_t inNewSize)
32 {
33 #ifdef ACCESSORIES_DEBUG_MODE
34  if (this->pMovingPositions_P != NULL)
35  {
36  Serial.println(F("Warning : a PROGMEM Moving position list is already defined !"));
37  }
38 #endif
39 
40  if (inNewSize <= this->movingPositionsSize)
41  return;
42 
43  MovingPosition *pNewList = new MovingPosition[inNewSize];
44  int i = 0;
45  for (; i < this->movingPositionsSize; i++)
46  pNewList[i] = this->pMovingPositions[i];
47 
48  for (; i < inNewSize; i++)
49  pNewList[i].Id = UNDEFINED_ID; //empty
50 
51  this->movingPositionsSize = inNewSize;
52  if (this->pMovingPositions != NULL)
53  delete[] this->pMovingPositions;
54  this->pMovingPositions = pNewList;
55 }
56 
57 // Returns the index of the new added position.
58 uint8_t Accessory::AddMovingPosition(unsigned long inId, int inPosition)
59 {
60  Accessory::AdjustMovingPositionsSize(this->movingPositionsAddCounter + 1);
61 
62  this->pMovingPositions[this->movingPositionsAddCounter].Id = inId;
63  this->pMovingPositions[this->movingPositionsAddCounter++].Position = inPosition;
64 
65  return this->movingPositionsAddCounter - 1;
66 }
67 
68 // Returns the number of positions.
69 uint8_t Accessory::AddMovingPositions(const MovingPosition *inMovingPositions_P)
70 {
71 #ifdef ACCESSORIES_DEBUG_MODE
72  if (this->pMovingPositions != NULL)
73  {
74  Serial.println(F("Warning : a Moving position list is already defined !"));
75  }
76 #endif
77 
78  this->pMovingPositions_P = inMovingPositions_P;
79 
80  MovingPosition local;
81 
82  int i = 0;
83  for (; i < 256; i++)
84  {
85  if (GetMovingPositionByIndex(i, &local)->Id == -1)
86  break;
87  }
88 
89  this->movingPositionsSize = i;
90  this->movingPositionsAddCounter = -1;
91 
92  return this->movingPositionsSize;
93 }
94 
95 uint8_t Accessory::IndexOfMovingPositionById(unsigned long inId) const
96 {
97  MovingPosition local;
98  for (int i = 0; i < this->movingPositionsSize; i++)
99  {
100  this->GetMovingPositionByIndex(i, &local);
101  if (local.Id == inId)
102  return i;
103  }
104 
105  return 255;
106 }
107 
108 MovingPosition *Accessory::GetMovingPositionByIndex(uint8_t inIndex, MovingPosition *apPosition) const
109 {
110  if (this->pMovingPositions != NULL)
111  {
112  apPosition->Id = this->pMovingPositions[inIndex].Id;
113  apPosition->Position = this->pMovingPositions[inIndex].Position;
114  }
115 
116  if (this->pMovingPositions_P != NULL)
117  {
118  memcpy_P(apPosition, this->pMovingPositions_P + inIndex, sizeof(MovingPosition));
119  }
120 
121  return apPosition;
122 }
123 
124 MovingPosition *Accessory::GetMovingPositionById(unsigned long inId, MovingPosition *apPosition) const
125 {
126  for (int i = 0; i < this->movingPositionsSize; i++)
127  {
128  this->GetMovingPositionByIndex(i, apPosition);
129  if (apPosition->Id == inId)
130  break;
131  }
132 
133  return apPosition;
134 }
135 
137 {
138  if (this->duration > 0)
139  this->startingMillis = millis();
140 
141 #ifdef ACCESSORIES_DEBUG_MODE
142 #ifdef ACCESSORIES_DEBUG_VERBOSE_MODE
143  Serial.print(F("Accessory start action "));
144  Serial.println(this->startingMillis);
145 #endif
146 #endif
147 }
148 
149 void Accessory::StartAction(ACC_STATE inState)
150 {
151  if (this->duration > 0)
152  this->startingMillis = millis();
153  this->SetState(inState);
154 
155 #ifdef ACCESSORIES_DEBUG_MODE
156 #ifdef ACCESSORIES_DEBUG_VERBOSE_MODE
157  Serial.print(F("Accessory start action at "));
158  Serial.print(this->startingMillis);
159  Serial.print(F("ms for state "));
160  Serial.print(inState);
161 
162  if (this->startingMillis == 0)
163  Serial.println(" ended");
164  else
165  Serial.println("");
166 #endif
167 #endif
168 }
169 
170 #ifdef ACCESSORIES_DEBUG_MODE
171 void Accessory::CheckPort() const
172 {
173  if (this->GetPort() == NULL)
174  {
175  Serial.println(F("One accessory have no port !"));
176  }
177 }
178 #endif
179 
180 #ifdef ACCESSORIES_DEBUG_VERBOSE_MODE
182 {
183  Serial.print(F("End (reset) action at "));
184  Serial.print(millis() - this->startingMillis);
185  Serial.print(F("ms for "));
186  Serial.print(this->duration);
187  Serial.println(F("ms"));
188 
189  this->startingMillis = 0;
190 }
191 #endif
192 
194 {
195  if (this->startingMillis <= 0)
196  return false;
197 
198  if ((unsigned long)(millis() - this->startingMillis) > this->duration)
199  {
200 #ifdef ACCESSORIES_DEBUG_MODE
201 #ifdef ACCESSORIES_DEBUG_VERBOSE_MODE
202  Serial.print(F("End action at "));
203  Serial.print(millis() - this->startingMillis);
204  Serial.print(F("ms for "));
205  Serial.print(this->duration);
206  Serial.println(F("ms"));
207 #endif
208 #endif
209  this->startingMillis = 0;
210  return true;
211  }
212 
213  return false;
214 }
215 
216 void Accessory::SetLastMovingPosition(uint8_t inLastPositionIndex)
217 {
218  this->lastMovingPosition = inLastPositionIndex;
219 #ifndef NO_EEPROM
220  Accessories::EEPROMSave();
221 #endif
222 }
223 
224 void Accessory::SetStateRaw(ACC_STATE inNewState)
225 {
226  if (this->state != inNewState)
227  {
228  this->state = inNewState;
229 #ifndef NO_EEPROM
230  Accessories::EEPROMSave();
231 #endif
232  }
233 }
234 
235 #ifndef NO_EEPROM
236 int Accessory::EEPROMSave(int inPos, bool inSimulate)
237 {
238  if (!inSimulate)
239  {
240  EEPROM.write(inPos, this->state);
241  EEPROM.write(inPos+1, this->GetLastMovingPosition());
242  EEPROM.write(inPos+2, this->pPort->GetSpeed());
243  }
244 
245  return inPos + 3;
246 }
247 
248 int Accessory::EEPROMLoad(int inPos)
249 {
250  this->state = (ACC_STATE)EEPROM.read(inPos++);
251  this->SetLastMovingPosition(EEPROM.read(inPos++));
252  this->pPort->SetSpeed(EEPROM.read(inPos++));
253 
254  return inPos;
255 }
256 #endif
257 
258 #ifdef ACCESSORIES_PRINT_ACCESSORIES
259 void Accessory::printMovingPositions()
260 {
261  MovingPosition local;
262  for (int i = 0; i < this->movingPositionsSize; i++)
263  {
264  this->GetMovingPositionByIndex(i, &local);
265  Serial.print(i);
266  Serial.print(F(": id "));
267  Serial.print(local.Id);
268  Serial.print(F(" / pos "));
269  Serial.println(local.Position);
270  }
271 }
272 #endif
273 
274 // Accessory list part
275 
276 void Accessory::Add(Accessory *inpAccessory)
277 {
278  if (Accessory::pFirstAccessory == NULL)
279  {
280  Accessory::pFirstAccessory = inpAccessory;
281  inpAccessory->SetNextAccessory(NULL);
282  return;
283  }
284 
285  Accessory *pCurr = Accessory::pFirstAccessory;
286 
287  while (pCurr->GetNextAccessory() != NULL)
288  pCurr = pCurr->GetNextAccessory();
289 
290  pCurr->SetNextAccessory(inpAccessory);
291  inpAccessory->SetNextAccessory(NULL);
292 }
293 
295 {
296  uint8_t accCount = 0;
297  Accessory *pCurr = Accessory::pFirstAccessory;
298  while (pCurr != NULL)
299  {
300  accCount++;
301  pCurr = pCurr->GetNextAccessory();
302  }
303 
304  return accCount;
305 }
306 
307 Accessory *Accessory::GetById(unsigned long inId)
308 {
309  Accessory *pCurr = Accessory::pFirstAccessory;
310 
311  while (pCurr != NULL)
312  {
313  if (pCurr->IndexOfMovingPositionById(inId) != (uint8_t)-1)
314  return pCurr;
315  pCurr = pCurr->GetNextAccessory();
316  }
317 
318  return NULL;
319 }
320 
322 {
323  Accessory *pCurr = Accessory::pFirstAccessory;
324 
325  while (pCurr != NULL)
326  {
327  if (pCurr->IsActionDelayPending())
328  return true;
329  pCurr = pCurr->GetNextAccessory();
330  }
331 
332  return false;
333 }
334 
335 bool Accessory::CanMove(unsigned long inId)
336 {
337  Accessory *acc = GetById(inId);
338 
339  if (acc == NULL)
340  return false;
341 
342  // Move if there is more than one MovingPosition (no toggle id), and moving ids are the same than
343  // previous time...
344  if (acc->GetMovingPositionSize() > 1)
345  {
346  bool move = acc->IndexOfMovingPositionById(inId) != acc->GetLastMovingPosition();
347 #ifdef ACCESSORIES_DEBUG_MODE
348  if (!move)
349  Serial.println(F("Same position : Cant move !"));
350 #endif
351  return move;
352  }
353 
354  return true;
355 }
356 
357 bool Accessory::IsMovementPending()
358 {
359  if (this->IsActionDelayPending())
360  {
361 #ifdef ACCESSORIES_DEBUG_MODE
362  Serial.println(F("ActionPending : Cant move !"));
363 #endif
364  return true;
365  }
366 
367  if (millis() - this->GetLastMoveTime() <= this->GetDebounceDelay())
368  {
369 #ifdef ACCESSORIES_DEBUG_MODE
370  Serial.println(F("Debounce : Cant move !"));
371 #endif
372  return true;
373  }
374 
375  this->SetLastMoveTime();
376  return false;
377 }
378 
379 bool Accessory::Toggle(unsigned long inId)
380 {
382  {
383 #ifdef ACCESSORIES_DEBUG_MODE
384  Serial.print(F(" ---- Stack id "));
385  Serial.println(inId);
386 #endif
387  ActionsStack::Actions.Add(inId, ACCESSORIES_EVENT_MOVEPOSITIONID);
388  return false;
389  }
390 
391  Accessory *acc = GetById(inId);
392 
393  if (acc == NULL)
394  {
395  return false;
396  }
397 
398  if (!CanMove(inId))
399  {
400  return true;
401  }
402 
403  uint8_t pos = acc->IndexOfMovingPositionById(inId);
404 
405  if (pos == 255)
406  {
407  return false;
408  }
409 
410  acc->SetLastMovingPosition(pos);
411 
412 #ifdef ACCESSORIES_DEBUG_MODE
413  Serial.print(F("Toggle : Accessory id "));
414  Serial.println(inId);
415 #endif
416 
417  acc->Move(inId);
418 
419  return true;
420 }
421 
422 bool Accessory::MovePosition(unsigned long inId)
423 {
424  Accessory *acc = GetById(inId);
425 
426  if (acc == NULL)
427  {
428  return false;
429  }
430 
431  uint8_t pos = acc->IndexOfMovingPositionById(inId);
432 
433  if (pos == 255)
434  {
435  return false;
436  }
437 
439  {
440 #ifdef ACCESSORIES_DEBUG_MODE
441  Serial.print(F(" ---- Stack id "));
442  Serial.println(inId);
443 #endif
444  ActionsStack::Actions.Add(inId, ACCESSORIES_EVENT_MOVEPOSITIONINDEX, pos);
445  return false;
446  }
447 
448  acc->SetLastMovingPosition(pos);
449 
450 #ifdef ACCESSORIES_DEBUG_MODE
451  Serial.print(F("MovePosition : Accessory id "));
452  Serial.print(inId);
453  Serial.print(F(" to position "));
454  Serial.println(acc->GetMovingPositionValueById(inId));
455 #endif
456 
457  acc->MovePosition(acc->GetMovingPositionValueById(inId));
458 
459  return true;
460 }
461 
462 void Accessory::ExecuteEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData)
463 {
464  Accessory *acc = GetById(inId);
465 
466  if (acc != NULL)
467  {
468  if (acc->IsMovementPending() || (ActionsStack::FillingStack && inEvent != ACCESSORIES_EVENT_EXTERNALMOVE))
469  {
470  ActionsStack::Actions.Add(inId, inEvent, inData);
471  return;
472  }
473 
474  if (inEvent == ACCESSORIES_EVENT_MOVEPOSITIONINDEX && (inData < 0 || inData >= acc->GetMovingPositionSize()))
475  {
476 #ifdef ACCESSORIES_DEBUG_MODE
477  Serial.print(F("Accessory id "));
478  Serial.print(inId);
479  Serial.print(F(" bad MovePositionIndex event "));
480  Serial.println(inData);
481 #endif
482  return;
483  }
484 
485  acc->Event(inId, inEvent, inData);
486  }
487 }
static ActionsStack Actions
static bool FillingStack
virtual ACC_STATE Toggle() = 0
static uint8_t GetCount()
Definition: Accessory.cpp:294
Accessory * GetNextAccessory() const
Definition: Accessory.hpp:386
void SetNextAccessory(Accessory *inAccessory)
Definition: Accessory.hpp:376
unsigned int GetDebounceDelay() const
Definition: Accessory.hpp:255
virtual int SetSpeed(int inSpeed)
Definition: Port.cpp:190
unsigned long GetLastMoveTime() const
Definition: Accessory.hpp:261
virtual int EEPROMLoad(int inPos)
const uint8_t GetLastMovingPosition() const
Definition: Accessory.hpp:344
void SetStateRaw(ACC_STATE inNewState)
Definition: Accessory.cpp:224
void SetLastMovingPosition(uint8_t inLastPositionIndex)
Definition: Accessory.cpp:216
virtual bool ActionEnded()
Definition: Accessory.cpp:193
int GetMovingPositionValueById(unsigned long inId) const
Definition: Accessory.hpp:327
virtual int EEPROMSave(int inPos, bool inSimulate = false)
virtual void ResetAction()
Definition: Accessory.hpp:411
const uint8_t GetMovingPositionSize() const
Definition: Accessory.hpp:349
virtual void SetState(ACC_STATE inNewState)
Definition: Accessory.hpp:456
virtual void Event(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
Definition: Accessory.hpp:278
uint8_t IndexOfMovingPositionById(unsigned long inId) const
Definition: Accessory.cpp:95
bool IsActionDelayPending() const
Definition: Accessory.hpp:424
int GetSpeed() const
Definition: Port.hpp:129
uint8_t AddMovingPositions(const MovingPosition *inMovingPositions_P)
Definition: Accessory.cpp:69
unsigned long Id
Definition: Accessory.hpp:77
virtual void Move(unsigned long inMovingPositionId) = 0
static bool IsActionPending()
Definition: Accessory.cpp:321
void AdjustMovingPositionsSize(uint8_t inNewSize)
Definition: Accessory.cpp:31
static void ExecuteEvent(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent = ACCESSORIES_EVENT_MOVEPOSITIONID, int inData = 0)
Definition: Accessory.cpp:462
void SetLastMoveTime()
Definition: Accessory.hpp:365
Port * pPort
Definition: Accessory.hpp:187
unsigned char Add(unsigned long inId, ACCESSORIES_EVENT_TYPE inEvent, int inData = 0)
Port * GetPort() const
Definition: Accessory.hpp:205
uint8_t AddMovingPosition(unsigned long inId, int inPosition)
Definition: Accessory.cpp:58
virtual void StartAction()
Definition: Accessory.cpp:136