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 "delegate.h"
35#include "error_handler.h"
36#include "placement_new.h"
37#include "static_assert.h"
38#include "timer.h"
39
40#include <stdint.h>
41
42namespace etl
43{
44 //***************************************************************************
46 //***************************************************************************
48 {
49 public:
50
51 typedef etl::delegate<void(void)> callback_type;
52 typedef etl::delegate<bool(void)> try_lock_type;
53 typedef etl::delegate<void(void)> lock_type;
54 typedef etl::delegate<void(void)> unlock_type;
55
56 typedef etl::delegate<void(etl::timer::id::type)> event_callback_type;
57
58 //*******************************************
60 //*******************************************
61 etl::timer::id::type register_timer(const callback_type& callback_, uint32_t period_, bool repeating_)
62 {
63 etl::timer::id::type id = etl::timer::id::NO_TIMER;
64
65 bool is_space = (number_of_registered_timers < Max_Timers);
66
67 if (is_space)
68 {
69 // Search for the free space.
70 for (uint_least8_t i = 0U; i < Max_Timers; ++i)
71 {
72 timer_data& timer = timer_array[i];
73
74 if (timer.id == etl::timer::id::NO_TIMER)
75 {
76 // Create in-place.
77 new (&timer) timer_data(i, callback_, period_, repeating_);
78 ++number_of_registered_timers;
79 id = i;
80 break;
81 }
82 }
83 }
84
85 return id;
86 }
87
88 //*******************************************
90 //*******************************************
91 bool unregister_timer(etl::timer::id::type id_)
92 {
93 bool result = false;
94
95 if (id_ != etl::timer::id::NO_TIMER)
96 {
97 timer_data& timer = timer_array[id_];
98
99 if (timer.id != etl::timer::id::NO_TIMER)
100 {
101 if (timer.is_active())
102 {
103 lock();
104 active_list.remove(timer.id, false);
105 remove_callback.call_if(timer.id);
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 virtual bool tick(uint32_t count) = 0;
160
161 //*******************************************
163 //*******************************************
164 bool start(etl::timer::id::type id_, bool immediate_ = false)
165 {
166 bool result = false;
167
168 // Valid timer id?
169 if (id_ != etl::timer::id::NO_TIMER)
170 {
171 timer_data& timer = timer_array[id_];
172
173 // Registered timer?
174 if (timer.id != etl::timer::id::NO_TIMER)
175 {
176 // Has a valid period.
177 if (timer.period != etl::timer::state::Inactive)
178 {
179 lock();
180 if (timer.is_active())
181 {
182 active_list.remove(timer.id, false);
183 remove_callback.call_if(timer.id);
184 }
185
186 timer.delta = immediate_ ? 0U : timer.period;
187 active_list.insert(timer.id);
188 insert_callback.call_if(timer.id);
189 unlock();
190
191 result = true;
192 }
193 }
194 }
195
196 return result;
197 }
198
199 //*******************************************
201 //*******************************************
202 bool stop(etl::timer::id::type id_)
203 {
204 bool result = false;
205
206 // Valid timer id?
207 if (id_ != etl::timer::id::NO_TIMER)
208 {
209 timer_data& timer = timer_array[id_];
210
211 // Registered timer?
212 if (timer.id != etl::timer::id::NO_TIMER)
213 {
214 if (timer.is_active())
215 {
216 lock();
217 active_list.remove(timer.id, false);
218 remove_callback.call_if(timer.id);
219 unlock();
220 }
221
222 result = true;
223 }
224 }
225
226 return result;
227 }
228
229 //*******************************************
231 //*******************************************
232 bool set_period(etl::timer::id::type id_, uint32_t period_)
233 {
234 if (stop(id_))
235 {
236 timer_array[id_].period = period_;
237 return true;
238 }
239
240 return false;
241 }
242
243 //*******************************************
245 //*******************************************
246 bool set_mode(etl::timer::id::type id_, bool repeating_)
247 {
248 if (stop(id_))
249 {
250 timer_array[id_].repeating = repeating_;
251 return true;
252 }
253
254 return false;
255 }
256
257 //*******************************************
259 //*******************************************
260 void set_locks(try_lock_type try_lock_, lock_type lock_, lock_type unlock_)
261 {
262 try_lock = try_lock_;
263 lock = lock_;
264 unlock = unlock_;
265 }
266
267 //*******************************************
269 //*******************************************
270 bool has_active_timer() const
271 {
272 lock();
273 bool result = !active_list.empty();
274 unlock();
275
276 return result;
277 }
278
279 //*******************************************
283 //*******************************************
284 uint32_t time_to_next() const
285 {
286 uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
287
288 lock();
289 if (!active_list.empty())
290 {
291 delta = active_list.front().delta;
292 }
293 unlock();
294
295 return delta;
296 }
297
298 //*******************************************
301 //*******************************************
302 bool is_active(etl::timer::id::type id_) const
303 {
304 bool result = false;
305
306 // Valid timer id?
307 if (is_valid_timer_id(id_))
308 {
309 if (has_active_timer())
310 {
311 lock();
312 const timer_data& timer = timer_array[id_];
313
314 // Registered timer?
315 if (timer.id != etl::timer::id::NO_TIMER)
316 {
317 result = timer.is_active();
318 }
319 unlock();
320 }
321 }
322
323 return result;
324 }
325
326 //*******************************************
328 //*******************************************
329 void set_insert_callback(event_callback_type insert_)
330 {
331 insert_callback = insert_;
332 }
333
334 //*******************************************
336 //*******************************************
337 void set_remove_callback(event_callback_type remove_)
338 {
339 remove_callback = remove_;
340 }
341
342 //*******************************************
343 void clear_insert_callback()
344 {
345 insert_callback.clear();
346 }
347
348 //*******************************************
349 void clear_remove_callback()
350 {
351 remove_callback.clear();
352 }
353
354 protected:
355
356 class callback_node
357 {
358 public:
359
360 callback_node(callback_type& callback_, uint_least8_t priority_)
361 : callback(callback_)
362 , priority(priority_)
363 {
364 }
365
366 bool operator<(const callback_node& p) const
367 {
368 return this->priority > p.priority; // comparison was inverted here to
369 // easy the code design
370 }
371
372 callback_type callback;
373 uint_least8_t priority;
374 };
375
376 //*************************************************************************
378 struct timer_data
379 {
380 //*******************************************
381 timer_data()
382 : callback()
383 , period(0U)
384 , delta(etl::timer::state::Inactive)
385 , id(etl::timer::id::NO_TIMER)
386 , previous(etl::timer::id::NO_TIMER)
387 , next(etl::timer::id::NO_TIMER)
388 , repeating(true)
389 {
390 }
391
392 //*******************************************
394 //*******************************************
395 timer_data(etl::timer::id::type id_, callback_type callback_, uint32_t period_, bool repeating_)
396 : callback(callback_)
397 , period(period_)
398 , delta(etl::timer::state::Inactive)
399 , id(id_)
400 , previous(etl::timer::id::NO_TIMER)
401 , next(etl::timer::id::NO_TIMER)
402 , repeating(repeating_)
403 {
404 }
405
406 //*******************************************
408 //*******************************************
409 bool is_active() const
410 {
411 return delta != etl::timer::state::Inactive;
412 }
413
414 //*******************************************
416 //*******************************************
418 {
419 delta = etl::timer::state::Inactive;
420 }
421
422 callback_type callback;
423 uint32_t period;
424 uint32_t delta;
425 etl::timer::id::type id;
426 uint_least8_t previous;
427 uint_least8_t next;
428 bool repeating;
429
430 private:
431
432 // Disabled.
433 timer_data(const timer_data& other) ETL_DELETE;
434 timer_data& operator=(const timer_data& other) ETL_DELETE;
435 };
436
437 //*******************************************
439 //*******************************************
440 icallback_timer_locked(timer_data* const timer_array_, const uint_least8_t Max_Timers_)
441 : timer_array(timer_array_)
442 , active_list(timer_array_)
443 , enabled(false)
444 , number_of_registered_timers(0U)
445 , Max_Timers(Max_Timers_)
446 {
447 }
448
449 private:
450
451 //*************************************************************************
453 //*************************************************************************
454 class timer_list
455 {
456 public:
457
458 //*******************************
459 timer_list(timer_data* ptimers_)
460 : head(etl::timer::id::NO_TIMER)
461 , tail(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 //*******************************
588 etl::timer::id::type begin()
589 {
590 return head;
591 }
592
593 //*******************************
594 etl::timer::id::type next(etl::timer::id::type last)
595 {
596 return ptimers[last].next;
597 }
598
599 //*******************************
600 void clear()
601 {
602 etl::timer::id::type id = begin();
603
604 while (id != etl::timer::id::NO_TIMER)
605 {
606 timer_data& timer = ptimers[id];
607 id = next(id);
608 timer.next = etl::timer::id::NO_TIMER;
609 }
610
611 head = etl::timer::id::NO_TIMER;
612 tail = etl::timer::id::NO_TIMER;
613 }
614
615 private:
616
617 etl::timer::id::type head;
618 etl::timer::id::type tail;
619
620 timer_data* const ptimers;
621 };
622
623 //*******************************************
625 //*******************************************
626 bool is_valid_timer_id(etl::timer::id::type id_) const
627 {
628 return (id_ < Max_Timers);
629 }
630
631 // The array of timer data structures.
632 timer_data* const timer_array;
633
634 // The list of active timers.
635 timer_list active_list;
636
637 bool enabled;
638 uint_least8_t number_of_registered_timers;
639
640 try_lock_type try_lock;
641 lock_type lock;
642 unlock_type unlock;
643
644 event_callback_type insert_callback;
645 event_callback_type remove_callback;
646
647 public:
648
649 template <uint_least8_t>
650 friend class callback_timer_locked;
651
652 template <uint_least8_t, uint32_t>
653 friend class callback_timer_deferred_locked;
654
655 const uint_least8_t Max_Timers;
656 };
657
658 //***************************************************************************
660 //***************************************************************************
661 template <uint_least8_t Max_Timers_>
663 {
664 public:
665
666 ETL_STATIC_ASSERT(Max_Timers_ <= 254U, "No more than 254 timers are allowed");
667
668 typedef icallback_timer_locked::callback_type callback_type;
669 typedef icallback_timer_locked::try_lock_type try_lock_type;
670 typedef icallback_timer_locked::lock_type lock_type;
671 typedef icallback_timer_locked::unlock_type unlock_type;
672
673 private:
674
675 typedef icallback_timer_locked::callback_node callback_node;
676
677 public:
678
679 //*******************************************
681 //*******************************************
683 : icallback_timer_locked(timer_array, Max_Timers_)
684 {
685 }
686
687 //*******************************************
689 //*******************************************
690 callback_timer_locked(try_lock_type try_lock_, lock_type lock_, unlock_type unlock_)
691 : icallback_timer_locked(timer_array, Max_Timers_)
692 {
693 this->set_locks(try_lock_, lock_, unlock_);
694 }
695
696 //*******************************************
698 //*******************************************
699 bool tick(uint32_t count) ETL_FINAL
700 {
701 if (enabled)
702 {
703 if (try_lock())
704 {
705 // We have something to do?
706 bool has_active = !active_list.empty();
707
708 if (has_active)
709 {
710 while (has_active && (count >= active_list.front().delta))
711 {
712 timer_data& timer = active_list.front();
713
714 count -= timer.delta;
715
716 active_list.remove(timer.id, true);
717 remove_callback.call_if(timer.id);
718
719 if (timer.callback.is_valid())
720 {
721 timer.callback();
722 }
723
724 if (timer.repeating)
725 {
726 // Reinsert the timer.
727 timer.delta = timer.period;
728 active_list.insert(timer.id);
729 insert_callback.call_if(timer.id);
730 }
731
732 has_active = !active_list.empty();
733 }
734
735 if (has_active)
736 {
737 // Subtract any remainder from the next due timeout.
738 active_list.front().delta -= count;
739 }
740 }
741
742 unlock();
743
744 return true;
745 }
746 }
747
748 return false;
749 }
750
751 private:
752
753 timer_data timer_array[Max_Timers_];
754 };
755} // namespace etl
756
757#endif
callback_timer_locked()
Constructor.
Definition callback_timer_locked.h:682
bool tick(uint32_t count) ETL_FINAL
Handle the tick call.
Definition callback_timer_locked.h:699
callback_timer_locked(try_lock_type try_lock_, lock_type lock_, unlock_type unlock_)
Constructor.
Definition callback_timer_locked.h:690
Definition callback.h:46
Declaration.
Definition delegate_cpp03.h:191
Definition callback_timer_locked.h:357
Interface for callback timer.
Definition callback_timer_locked.h:48
bool has_active_timer() const
Check if there is an active timer.
Definition callback_timer_locked.h:270
void set_insert_callback(event_callback_type insert_)
Set a callback when a timer is inserted on list.
Definition callback_timer_locked.h:329
void set_remove_callback(event_callback_type remove_)
Set a callback when a timer is removed from list.
Definition callback_timer_locked.h:337
icallback_timer_locked(timer_data *const timer_array_, const uint_least8_t Max_Timers_)
Constructor.
Definition callback_timer_locked.h:440
bool stop(etl::timer::id::type id_)
Stops a timer.
Definition callback_timer_locked.h:202
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:260
uint32_t time_to_next() const
Definition callback_timer_locked.h:284
etl::timer::id::type register_timer(const callback_type &callback_, uint32_t period_, bool repeating_)
Register a timer.
Definition callback_timer_locked.h:61
bool set_period(etl::timer::id::type id_, uint32_t period_)
Sets a timer's period.
Definition callback_timer_locked.h:232
bool set_mode(etl::timer::id::type id_, bool repeating_)
Sets a timer's mode.
Definition callback_timer_locked.h:246
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
bool unregister_timer(etl::timer::id::type id_)
Unregister a timer.
Definition callback_timer_locked.h:91
bool start(etl::timer::id::type id_, bool immediate_=false)
Starts a timer.
Definition callback_timer_locked.h:164
bool is_active(etl::timer::id::type id_) const
Definition callback_timer_locked.h:302
Definition circular_iterator.h:599
Definition absolute.h:40
The configuration of a timer.
Definition callback_timer_locked.h:379
timer_data(etl::timer::id::type id_, callback_type callback_, uint32_t period_, bool repeating_)
ETL delegate callback.
Definition callback_timer_locked.h:395
void set_inactive()
Sets the timer to the inactive state.
Definition callback_timer_locked.h:417
bool is_active() const
Returns true if the timer is active.
Definition callback_timer_locked.h:409
Definition timer.h:88
Common definitions for the timer framework.
Definition timer.h:55