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