Embedded Template Library 1.0
Loading...
Searching...
No Matches
callback_timer_locked.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2021 John Wellbelove
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files(the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions :
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27******************************************************************************/
28
29#ifndef ETL_CALLBACK_TIMER_LOCKED_INCLUDED
30#define ETL_CALLBACK_TIMER_LOCKED_INCLUDED
31
32#include "platform.h"
33#include "algorithm.h"
34#include "nullptr.h"
35#include "delegate.h"
36#include "static_assert.h"
37#include "timer.h"
38#include "error_handler.h"
39#include "placement_new.h"
40
41#include <stdint.h>
42
43namespace etl
44{
45 //***************************************************************************
47 //***************************************************************************
49 {
50 public:
51
52 typedef etl::delegate<void(void)> callback_type;
53 typedef etl::delegate<bool(void)> try_lock_type;
54 typedef etl::delegate<void(void)> lock_type;
55 typedef etl::delegate<void(void)> unlock_type;
56
57 //*******************************************
59 //*******************************************
62 bool repeating_)
63 {
64 etl::timer::id::type id = etl::timer::id::NO_TIMER;
65
66 bool is_space = (number_of_registered_timers < MAX_TIMERS);
67
68 if (is_space)
69 {
70 // Search for the free space.
71 for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i)
72 {
73 timer_data& timer = timer_array[i];
74
75 if (timer.id == etl::timer::id::NO_TIMER)
76 {
77 // Create in-place.
79 ++number_of_registered_timers;
80 id = i;
81 break;
82 }
83 }
84 }
85
86 return id;
87 }
88
89 //*******************************************
91 //*******************************************
93 {
94 bool result = false;
95
96 if (id_ != etl::timer::id::NO_TIMER)
97 {
98 timer_data& timer = timer_array[id_];
99
100 if (timer.id != etl::timer::id::NO_TIMER)
101 {
102 if (timer.is_active())
103 {
104 lock();
105 active_list.remove(timer.id, false);
106 unlock();
107 }
108
109 // Reset in-place.
110 new (&timer) timer_data();
111 --number_of_registered_timers;
112
113 result = true;
114 }
115 }
116
117 return result;
118 }
119
120 //*******************************************
122 //*******************************************
123 void enable(bool state_)
124 {
125 enabled = state_;
126 }
127
128 //*******************************************
130 //*******************************************
131 bool is_running() const
132 {
133 return enabled;
134 }
135
136 //*******************************************
138 //*******************************************
139 void clear()
140 {
141 lock();
142 active_list.clear();
143 unlock();
144
145 for (uint8_t i = 0U; i < MAX_TIMERS; ++i)
146 {
147 ::new (&timer_array[i]) timer_data();
148 }
149
150 number_of_registered_timers = 0;
151 }
152
153 //*******************************************
154 // Called by the timer service to indicate the
155 // amount of time that has elapsed since the last successful call to 'tick'.
156 // Returns true if the tick was processed,
157 // false if not.
158 //*******************************************
159 bool tick(uint32_t count)
160 {
161 if (enabled)
162 {
163 if (try_lock())
164 {
165 // We have something to do?
166 bool has_active = !active_list.empty();
167
168 if (has_active)
169 {
170 while (has_active && (count >= active_list.front().delta))
171 {
172 timer_data& timer = active_list.front();
173
174 count -= timer.delta;
175
176 active_list.remove(timer.id, true);
177
178 if (timer.callback.is_valid())
179 {
180 timer.callback();
181 }
182
183 if (timer.repeating)
184 {
185 // Reinsert the timer.
186 timer.delta = timer.period;
187 active_list.insert(timer.id);
188 }
189
190 has_active = !active_list.empty();
191 }
192
193 if (has_active)
194 {
195 // Subtract any remainder from the next due timeout.
196 active_list.front().delta -= count;
197 }
198 }
199
200 unlock();
201
202 return true;
203 }
204 }
205
206 return false;
207 }
208
209 //*******************************************
211 //*******************************************
213 {
214 bool result = false;
215
216 // Valid timer id?
217 if (id_ != etl::timer::id::NO_TIMER)
218 {
219 timer_data& timer = timer_array[id_];
220
221 // Registered timer?
222 if (timer.id != etl::timer::id::NO_TIMER)
223 {
224 // Has a valid period.
225 if (timer.period != etl::timer::state::Inactive)
226 {
227 lock();
228 if (timer.is_active())
229 {
230 active_list.remove(timer.id, false);
231 }
232
233 timer.delta = immediate_ ? 0U : timer.period;
234 active_list.insert(timer.id);
235 unlock();
236
237 result = true;
238 }
239 }
240 }
241
242 return result;
243 }
244
245 //*******************************************
247 //*******************************************
249 {
250 bool result = false;
251
252 // Valid timer id?
253 if (id_ != etl::timer::id::NO_TIMER)
254 {
255 timer_data& timer = timer_array[id_];
256
257 // Registered timer?
258 if (timer.id != etl::timer::id::NO_TIMER)
259 {
260 if (timer.is_active())
261 {
262 lock();
263 active_list.remove(timer.id, false);
264 unlock();
265 }
266
267 result = true;
268 }
269 }
270
271 return result;
272 }
273
274 //*******************************************
276 //*******************************************
278 {
279 if (stop(id_))
280 {
281 timer_array[id_].period = period_;
282 return true;
283 }
284
285 return false;
286 }
287
288 //*******************************************
290 //*******************************************
292 {
293 if (stop(id_))
294 {
295 timer_array[id_].repeating = repeating_;
296 return true;
297 }
298
299 return false;
300 }
301
302 //*******************************************
304 //*******************************************
306 {
307 try_lock = try_lock_;
308 lock = lock_;
309 unlock = unlock_;
310 }
311
312 //*******************************************
314 //*******************************************
315 bool has_active_timer() const
316 {
317 lock();
318 bool result = !active_list.empty();
319 unlock();
320
321 return result;
322 }
323
324 //*******************************************
327 //*******************************************
329 {
330 uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
331
332 lock();
333 if (!active_list.empty())
334 {
335 delta = active_list.front().delta;
336 }
337 unlock();
338
339 return delta;
340 }
341
342 //*******************************************
345 //*******************************************
347 {
348 bool result = false;
349
350 // Valid timer id?
351 if (is_valid_timer_id(id_))
352 {
353 if (has_active_timer())
354 {
355 lock();
356 const timer_data& timer = timer_array[id_];
357
358 // Registered timer?
359 if (timer.id != etl::timer::id::NO_TIMER)
360 {
361 result = timer.is_active();
362 }
363 unlock();
364 }
365 }
366
367 return result;
368 }
369
370 protected:
371
372 //*************************************************************************
375 {
376 //*******************************************
377 timer_data()
378 : callback()
379 , period(0U)
380 , delta(etl::timer::state::Inactive)
381 , id(etl::timer::id::NO_TIMER)
382 , previous(etl::timer::id::NO_TIMER)
383 , next(etl::timer::id::NO_TIMER)
384 , repeating(true)
385 {
386 }
387
388 //*******************************************
390 //*******************************************
394 bool repeating_)
396 , period(period_)
397 , delta(etl::timer::state::Inactive)
398 , id(id_)
399 , previous(etl::timer::id::NO_TIMER)
400 , next(etl::timer::id::NO_TIMER)
401 , repeating(repeating_)
402 {
403 }
404
405 //*******************************************
407 //*******************************************
408 bool is_active() const
409 {
410 return delta != etl::timer::state::Inactive;
411 }
412
413 //*******************************************
415 //*******************************************
417 {
418 delta = etl::timer::state::Inactive;
419 }
420
422 uint32_t period;
423 uint32_t delta;
425 uint_least8_t previous;
426 uint_least8_t next;
427 bool repeating;
428
429 private:
430
431 // Disabled.
432 timer_data(const timer_data& other) ETL_DELETE;
433 timer_data& operator =(const timer_data& other) ETL_DELETE;
434 };
435
436 //*******************************************
438 //*******************************************
440 : timer_array(timer_array_),
441 active_list(timer_array_),
442 enabled(false),
443 number_of_registered_timers(0U),
444 MAX_TIMERS(MAX_TIMERS_)
445 {
446 }
447
448 private:
449
450 //*************************************************************************
452 //*************************************************************************
453 class timer_list
454 {
455 public:
456
457 //*******************************
458 timer_list(timer_data* ptimers_)
459 : head(etl::timer::id::NO_TIMER)
460 , tail(etl::timer::id::NO_TIMER)
461 , current(etl::timer::id::NO_TIMER)
462 , ptimers(ptimers_)
463 {
464 }
465
466 //*******************************
467 bool empty() const
468 {
469 return head == etl::timer::id::NO_TIMER;
470 }
471
472 //*******************************
473 // Inserts the timer at the correct delta position
474 //*******************************
475 void insert(etl::timer::id::type id_)
476 {
477 timer_data& timer = ptimers[id_];
478
479 if (head == etl::timer::id::NO_TIMER)
480 {
481 // No entries yet.
482 head = id_;
483 tail = id_;
484 timer.previous = etl::timer::id::NO_TIMER;
485 timer.next = etl::timer::id::NO_TIMER;
486 }
487 else
488 {
489 // We already have entries.
490 etl::timer::id::type test_id = begin();
491
492 while (test_id != etl::timer::id::NO_TIMER)
493 {
494 timer_data& test = ptimers[test_id];
495
496 // Find the correct place to insert.
497 if (timer.delta <= test.delta)
498 {
499 if (test.id == head)
500 {
501 head = timer.id;
502 }
503
504 // Insert before test.
505 timer.previous = test.previous;
506 test.previous = timer.id;
507 timer.next = test.id;
508
509 // Adjust the next delta to compensate.
510 test.delta -= timer.delta;
511
512 if (timer.previous != etl::timer::id::NO_TIMER)
513 {
514 ptimers[timer.previous].next = timer.id;
515 }
516 break;
517 }
518 else
519 {
520 timer.delta -= test.delta;
521 }
522
523 test_id = next(test_id);
524 }
525
526 // Reached the end?
527 if (test_id == etl::timer::id::NO_TIMER)
528 {
529 // Tag on to the tail.
530 ptimers[tail].next = timer.id;
531 timer.previous = tail;
532 timer.next = etl::timer::id::NO_TIMER;
533 tail = timer.id;
534 }
535 }
536 }
537
538 //*******************************
539 void remove(etl::timer::id::type id_, bool has_expired)
540 {
541 timer_data& timer = ptimers[id_];
542
543 if (head == id_)
544 {
545 head = timer.next;
546 }
547 else
548 {
549 ptimers[timer.previous].next = timer.next;
550 }
551
552 if (tail == id_)
553 {
554 tail = timer.previous;
555 }
556 else
557 {
558 ptimers[timer.next].previous = timer.previous;
559 }
560
561 if (!has_expired)
562 {
563 // Adjust the next delta.
564 if (timer.next != etl::timer::id::NO_TIMER)
565 {
566 ptimers[timer.next].delta += timer.delta;
567 }
568 }
569
570 timer.previous = etl::timer::id::NO_TIMER;
571 timer.next = etl::timer::id::NO_TIMER;
572 timer.delta = etl::timer::state::Inactive;
573 }
574
575 //*******************************
576 timer_data& front()
577 {
578 return ptimers[head];
579 }
580
581 //*******************************
582 const timer_data& front() const
583 {
584 return ptimers[head];
585 }
586
587 //*******************************
589 {
590 current = head;
591 return current;
592 }
593
594 //*******************************
596 {
597 current = ptimers[last].previous;
598 return current;
599 }
600
601 //*******************************
603 {
604 current = ptimers[last].next;
605 return current;
606 }
607
608 //*******************************
609 void clear()
610 {
612
613 while (id != etl::timer::id::NO_TIMER)
614 {
615 timer_data& timer = ptimers[id];
616 id = next(id);
617 timer.next = etl::timer::id::NO_TIMER;
618 }
619
620 head = etl::timer::id::NO_TIMER;
621 tail = etl::timer::id::NO_TIMER;
622 current = etl::timer::id::NO_TIMER;
623 }
624
625 private:
626
629 etl::timer::id::type current;
630
631 timer_data* const ptimers;
632 };
633
634 //*******************************************
636 //*******************************************
637 bool is_valid_timer_id(etl::timer::id::type id_) const
638 {
639 return (id_ < MAX_TIMERS);
640 }
641
642 // The array of timer data structures.
643 timer_data* const timer_array;
644
645 // The list of active timers.
646 timer_list active_list;
647
648 bool enabled;
649 uint_least8_t number_of_registered_timers;
650
651 try_lock_type try_lock;
652 lock_type lock;
653 unlock_type unlock;
654
655 public:
656
657 const uint_least8_t MAX_TIMERS;
658 };
659
660 //***************************************************************************
662 //***************************************************************************
663 template <uint_least8_t MAX_TIMERS_>
665 {
666 public:
667
668 ETL_STATIC_ASSERT(MAX_TIMERS_ <= 254U, "No more than 254 timers are allowed");
669
674
675 //*******************************************
677 //*******************************************
682
683 //*******************************************
685 //*******************************************
691
692 private:
693
694 timer_data timer_array[MAX_TIMERS_];
695 };
696}
697
698#endif
The callback timer.
Definition callback_timer_locked.h:665
callback_timer_locked(try_lock_type try_lock_, lock_type lock_, unlock_type unlock_)
Constructor.
Definition callback_timer_locked.h:686
callback_timer_locked()
Constructor.
Definition callback_timer_locked.h:678
Definition callback.h:45
Declaration.
Definition delegate_cpp03.h:175
Interface for callback timer.
Definition callback_timer_locked.h:49
bool has_active_timer() const
Check if there is an active timer.
Definition callback_timer_locked.h:315
bool stop(etl::timer::id::type id_)
Stops a timer.
Definition callback_timer_locked.h:248
void clear()
Clears the timer of data.
Definition callback_timer_locked.h:139
void set_locks(try_lock_type try_lock_, lock_type lock_, lock_type unlock_)
Sets the lock and unlock delegates.
Definition callback_timer_locked.h:305
uint32_t time_to_next() const
Definition callback_timer_locked.h:328
etl::timer::id::type register_timer(const callback_type &callback_, uint32_t period_, bool repeating_)
Register a timer.
Definition callback_timer_locked.h:60
bool set_period(etl::timer::id::type id_, uint32_t period_)
Sets a timer's period.
Definition callback_timer_locked.h:277
bool set_mode(etl::timer::id::type id_, bool repeating_)
Sets a timer's mode.
Definition callback_timer_locked.h:291
bool is_running() const
Get the enable/disable state.
Definition callback_timer_locked.h:131
void enable(bool state_)
Enable/disable the timer.
Definition callback_timer_locked.h:123
icallback_timer_locked(timer_data *const timer_array_, const uint_least8_t MAX_TIMERS_)
Constructor.
Definition callback_timer_locked.h:439
bool unregister_timer(etl::timer::id::type id_)
Unregister a timer.
Definition callback_timer_locked.h:92
bool start(etl::timer::id::type id_, bool immediate_=false)
Starts a timer.
Definition callback_timer_locked.h:212
bool is_active(etl::timer::id::type id_) const
Definition callback_timer_locked.h:346
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2180
bitset_ext
Definition absolute.h:38
ETL_CONSTEXPR TContainer::iterator begin(TContainer &container)
Definition iterator.h:962
The configuration of a timer.
Definition callback_timer_locked.h:375
timer_data(etl::timer::id::type id_, callback_type callback_, uint32_t period_, bool repeating_)
ETL delegate callback.
Definition callback_timer_locked.h:391
void set_inactive()
Sets the timer to the inactive state.
Definition callback_timer_locked.h:416
bool is_active() const
Returns true if the timer is active.
Definition callback_timer_locked.h:408
pair holds two objects of arbitrary type
Definition utility.h:164
Definition timer.h:88
Common definitions for the timer framework.
Definition timer.h:55