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