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 //*******************************************
60 etl::timer::id::type register_timer(const callback_type& callback_,
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 //*******************************************
92 bool unregister_timer(etl::timer::id::type id_)
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 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 }
184
185 timer.delta = immediate_ ? 0U : timer.period;
186 active_list.insert(timer.id);
187 unlock();
188
189 result = true;
190 }
191 }
192 }
193
194 return result;
195 }
196
197 //*******************************************
199 //*******************************************
200 bool stop(etl::timer::id::type id_)
201 {
202 bool result = false;
203
204 // Valid timer id?
205 if (id_ != etl::timer::id::NO_TIMER)
206 {
207 timer_data& timer = timer_array[id_];
208
209 // Registered timer?
210 if (timer.id != etl::timer::id::NO_TIMER)
211 {
212 if (timer.is_active())
213 {
214 lock();
215 active_list.remove(timer.id, false);
216 unlock();
217 }
218
219 result = true;
220 }
221 }
222
223 return result;
224 }
225
226 //*******************************************
228 //*******************************************
229 bool set_period(etl::timer::id::type id_, uint32_t period_)
230 {
231 if (stop(id_))
232 {
233 timer_array[id_].period = period_;
234 return true;
235 }
236
237 return false;
238 }
239
240 //*******************************************
242 //*******************************************
243 bool set_mode(etl::timer::id::type id_, bool repeating_)
244 {
245 if (stop(id_))
246 {
247 timer_array[id_].repeating = repeating_;
248 return true;
249 }
250
251 return false;
252 }
253
254 //*******************************************
256 //*******************************************
258 {
259 try_lock = try_lock_;
260 lock = lock_;
261 unlock = unlock_;
262 }
263
264 //*******************************************
266 //*******************************************
267 bool has_active_timer() const
268 {
269 lock();
270 bool result = !active_list.empty();
271 unlock();
272
273 return result;
274 }
275
276 //*******************************************
279 //*******************************************
281 {
282 uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
283
284 lock();
285 if (!active_list.empty())
286 {
287 delta = active_list.front().delta;
288 }
289 unlock();
290
291 return delta;
292 }
293
294 //*******************************************
297 //*******************************************
298 bool is_active(etl::timer::id::type id_) const
299 {
300 bool result = false;
301
302 // Valid timer id?
303 if (is_valid_timer_id(id_))
304 {
305 if (has_active_timer())
306 {
307 lock();
308 const timer_data& timer = timer_array[id_];
309
310 // Registered timer?
311 if (timer.id != etl::timer::id::NO_TIMER)
312 {
313 result = timer.is_active();
314 }
315 unlock();
316 }
317 }
318
319 return result;
320 }
321
322 protected:
323
324 //*************************************************************************
327 {
328 //*******************************************
329 timer_data()
330 : callback()
331 , period(0U)
332 , delta(etl::timer::state::Inactive)
333 , id(etl::timer::id::NO_TIMER)
334 , previous(etl::timer::id::NO_TIMER)
335 , next(etl::timer::id::NO_TIMER)
336 , repeating(true)
337 {
338 }
339
340 //*******************************************
342 //*******************************************
343 timer_data(etl::timer::id::type id_,
346 bool repeating_)
348 , period(period_)
349 , delta(etl::timer::state::Inactive)
350 , id(id_)
351 , previous(etl::timer::id::NO_TIMER)
352 , next(etl::timer::id::NO_TIMER)
353 , repeating(repeating_)
354 {
355 }
356
357 //*******************************************
359 //*******************************************
360 bool is_active() const
361 {
362 return delta != etl::timer::state::Inactive;
363 }
364
365 //*******************************************
367 //*******************************************
369 {
370 delta = etl::timer::state::Inactive;
371 }
372
374 uint32_t period;
375 uint32_t delta;
376 etl::timer::id::type id;
377 uint_least8_t previous;
378 uint_least8_t next;
379 bool repeating;
380
381 private:
382
383 // Disabled.
384 timer_data(const timer_data& other) ETL_DELETE;
385 timer_data& operator =(const timer_data& other) ETL_DELETE;
386 };
387
388 //*******************************************
390 //*******************************************
392 : timer_array(timer_array_),
393 active_list(timer_array_),
394 enabled(false),
395 number_of_registered_timers(0U),
396 MAX_TIMERS(MAX_TIMERS_)
397 {
398 }
399
400 private:
401
402 //*************************************************************************
404 //*************************************************************************
405 class timer_list
406 {
407 public:
408
409 //*******************************
410 timer_list(timer_data* ptimers_)
411 : head(etl::timer::id::NO_TIMER)
412 , tail(etl::timer::id::NO_TIMER)
413 , current(etl::timer::id::NO_TIMER)
414 , ptimers(ptimers_)
415 {
416 }
417
418 //*******************************
419 bool empty() const
420 {
421 return head == etl::timer::id::NO_TIMER;
422 }
423
424 //*******************************
425 // Inserts the timer at the correct delta position
426 //*******************************
427 void insert(etl::timer::id::type id_)
428 {
429 timer_data& timer = ptimers[id_];
430
431 if (head == etl::timer::id::NO_TIMER)
432 {
433 // No entries yet.
434 head = id_;
435 tail = id_;
436 timer.previous = etl::timer::id::NO_TIMER;
437 timer.next = etl::timer::id::NO_TIMER;
438 }
439 else
440 {
441 // We already have entries.
442 etl::timer::id::type test_id = begin();
443
444 while (test_id != etl::timer::id::NO_TIMER)
445 {
446 timer_data& test = ptimers[test_id];
447
448 // Find the correct place to insert.
449 if (timer.delta <= test.delta)
450 {
451 if (test.id == head)
452 {
453 head = timer.id;
454 }
455
456 // Insert before test.
457 timer.previous = test.previous;
458 test.previous = timer.id;
459 timer.next = test.id;
460
461 // Adjust the next delta to compensate.
462 test.delta -= timer.delta;
463
464 if (timer.previous != etl::timer::id::NO_TIMER)
465 {
466 ptimers[timer.previous].next = timer.id;
467 }
468 break;
469 }
470 else
471 {
472 timer.delta -= test.delta;
473 }
474
475 test_id = next(test_id);
476 }
477
478 // Reached the end?
479 if (test_id == etl::timer::id::NO_TIMER)
480 {
481 // Tag on to the tail.
482 ptimers[tail].next = timer.id;
483 timer.previous = tail;
484 timer.next = etl::timer::id::NO_TIMER;
485 tail = timer.id;
486 }
487 }
488 }
489
490 //*******************************
491 void remove(etl::timer::id::type id_, bool has_expired)
492 {
493 timer_data& timer = ptimers[id_];
494
495 if (head == id_)
496 {
497 head = timer.next;
498 }
499 else
500 {
501 ptimers[timer.previous].next = timer.next;
502 }
503
504 if (tail == id_)
505 {
506 tail = timer.previous;
507 }
508 else
509 {
510 ptimers[timer.next].previous = timer.previous;
511 }
512
513 if (!has_expired)
514 {
515 // Adjust the next delta.
516 if (timer.next != etl::timer::id::NO_TIMER)
517 {
518 ptimers[timer.next].delta += timer.delta;
519 }
520 }
521
522 timer.previous = etl::timer::id::NO_TIMER;
523 timer.next = etl::timer::id::NO_TIMER;
524 timer.delta = etl::timer::state::Inactive;
525 }
526
527 //*******************************
528 timer_data& front()
529 {
530 return ptimers[head];
531 }
532
533 //*******************************
534 const timer_data& front() const
535 {
536 return ptimers[head];
537 }
538
539 //*******************************
540 etl::timer::id::type begin()
541 {
542 current = head;
543 return current;
544 }
545
546 //*******************************
547 etl::timer::id::type previous(etl::timer::id::type last)
548 {
549 current = ptimers[last].previous;
550 return current;
551 }
552
553 //*******************************
554 etl::timer::id::type next(etl::timer::id::type last)
555 {
556 current = ptimers[last].next;
557 return current;
558 }
559
560 //*******************************
561 void clear()
562 {
563 etl::timer::id::type id = begin();
564
565 while (id != etl::timer::id::NO_TIMER)
566 {
567 timer_data& timer = ptimers[id];
568 id = next(id);
569 timer.next = etl::timer::id::NO_TIMER;
570 }
571
572 head = etl::timer::id::NO_TIMER;
573 tail = etl::timer::id::NO_TIMER;
574 current = etl::timer::id::NO_TIMER;
575 }
576
577 private:
578
579 etl::timer::id::type head;
580 etl::timer::id::type tail;
581 etl::timer::id::type current;
582
583 timer_data* const ptimers;
584 };
585
586 //*******************************************
588 //*******************************************
589 bool is_valid_timer_id(etl::timer::id::type id_) const
590 {
591 return (id_ < MAX_TIMERS);
592 }
593
594 // The array of timer data structures.
595 timer_data* const timer_array;
596
597 // The list of active timers.
598 timer_list active_list;
599
600 bool enabled;
601 uint_least8_t number_of_registered_timers;
602
603 try_lock_type try_lock;
604 lock_type lock;
605 unlock_type unlock;
606
607 public:
608 template <uint_least8_t>
609 friend class callback_timer_locked;
610
611 template <uint_least8_t, uint32_t>
612 friend class callback_timer_deferred_locked;
613
614 const uint_least8_t MAX_TIMERS;
615 };
616
617 //***************************************************************************
619 //***************************************************************************
620 template <uint_least8_t MAX_TIMERS_>
622 {
623 public:
624
625 ETL_STATIC_ASSERT(MAX_TIMERS_ <= 254U, "No more than 254 timers are allowed");
626
631
632 //*******************************************
634 //*******************************************
639
640 //*******************************************
642 //*******************************************
648
649 // Implement virtual functions
650
651 bool tick(uint32_t count) final
652 {
653 if (enabled)
654 {
655 if (try_lock())
656 {
657 // We have something to do?
658 bool has_active = !active_list.empty();
659
660 if (has_active)
661 {
662 while (has_active && (count >= active_list.front().delta))
663 {
664 timer_data& timer = active_list.front();
665
666 count -= timer.delta;
667
668 active_list.remove(timer.id, true);
669
670 if (timer.callback.is_valid())
671 {
672 timer.callback();
673 }
674
675 if (timer.repeating)
676 {
677 // Reinsert the timer.
678 timer.delta = timer.period;
679 active_list.insert(timer.id);
680 }
681
682 has_active = !active_list.empty();
683 }
684
685 if (has_active)
686 {
687 // Subtract any remainder from the next due timeout.
688 active_list.front().delta -= count;
689 }
690 }
691
692 unlock();
693
694 return true;
695 }
696 }
697
698 return false;
699 }
700
701 private:
702
703 timer_data timer_array[MAX_TIMERS_];
704 };
705}
706
707#endif
The callback timer.
Definition callback_timer_locked.h:622
callback_timer_locked(try_lock_type try_lock_, lock_type lock_, unlock_type unlock_)
Constructor.
Definition callback_timer_locked.h:643
callback_timer_locked()
Constructor.
Definition callback_timer_locked.h:635
Definition callback.h:45
Declaration.
Definition delegate_cpp03.h:191
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:267
bool stop(etl::timer::id::type id_)
Stops a timer.
Definition callback_timer_locked.h:200
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:257
uint32_t time_to_next() const
Definition callback_timer_locked.h:280
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:229
bool set_mode(etl::timer::id::type id_, bool repeating_)
Sets a timer's mode.
Definition callback_timer_locked.h:243
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:391
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:164
bool is_active(etl::timer::id::type id_) const
Definition callback_timer_locked.h:298
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2300
bitset_ext
Definition absolute.h:38
ETL_CONSTEXPR TContainer::iterator begin(TContainer &container)
Definition iterator.h:962
ETL_NODISCARD ETL_CONSTEXPR14 T round_half_even_unscaled(T value) ETL_NOEXCEPT
Definition scaled_rounding.h:314
The configuration of a timer.
Definition callback_timer_locked.h:327
timer_data(etl::timer::id::type id_, callback_type callback_, uint32_t period_, bool repeating_)
ETL delegate callback.
Definition callback_timer_locked.h:343
void set_inactive()
Sets the timer to the inactive state.
Definition callback_timer_locked.h:368
bool is_active() const
Returns true if the timer is active.
Definition callback_timer_locked.h:360
Definition timer.h:88
Common definitions for the timer framework.
Definition timer.h:55