Embedded Template Library 1.0
Loading...
Searching...
No Matches
callback_timer_interrupt.h
1 /******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2022 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_INTERRUPT_INCLUDED
30#define ETL_CALLBACK_TIMER_INTERRUPT_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 //***************************************************************************
48 template <typename TInterruptGuard>
50 {
51 public:
52
53 typedef etl::delegate<void(void)> callback_type;
54
55 //*******************************************
57 //*******************************************
60 bool repeating_)
61 {
62 etl::timer::id::type id = etl::timer::id::NO_TIMER;
63
64 bool is_space = (number_of_registered_timers < MAX_TIMERS);
65
66 if (is_space)
67 {
68 // Search for the free space.
69 for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i)
70 {
71 timer_data& timer = timer_array[i];
72
73 if (timer.id == etl::timer::id::NO_TIMER)
74 {
75 TInterruptGuard guard;
76 (void)guard; // Silence 'unused variable warnings.
77
78 // Create in-place.
80 ++number_of_registered_timers;
81 id = i;
82 break;
83 }
84 }
85 }
86
87 return id;
88 }
89
90 //*******************************************
92 //*******************************************
94 {
95 bool result = false;
96
97 if (id_ != etl::timer::id::NO_TIMER)
98 {
99 timer_data& timer = timer_array[id_];
100
101 if (timer.id != etl::timer::id::NO_TIMER)
102 {
103 if (timer.is_active())
104 {
105 TInterruptGuard guard;
106 (void)guard; // Silence 'unused variable warnings.
107
108 active_list.remove(timer.id, false);
109 }
110
111 // Reset in-place.
112 new (&timer) timer_data();
113 --number_of_registered_timers;
114
115 result = true;
116 }
117 }
118
119 return result;
120 }
121
122 //*******************************************
124 //*******************************************
125 void enable(bool state_)
126 {
127 enabled = state_;
128 }
129
130 //*******************************************
132 //*******************************************
133 bool is_running() const
134 {
135 return enabled;
136 }
137
138 //*******************************************
140 //*******************************************
141 void clear()
142 {
143 {
144 TInterruptGuard guard;
145 (void)guard; // Silence 'unused variable warnings.
146
147 active_list.clear();
148 number_of_registered_timers = 0;
149 }
150
151 for (uint8_t i = 0U; i < MAX_TIMERS; ++i)
152 {
153 ::new (&timer_array[i]) timer_data();
154 }
155 }
156
157 //*******************************************
158 // Called by the timer service to indicate the
159 // amount of time that has elapsed since the last successful call to 'tick'.
160 // Returns true if the tick was processed,
161 // false if not.
162 //*******************************************
163 bool tick(uint32_t count)
164 {
165 if (enabled)
166 {
167 // We have something to do?
168 bool has_active = !active_list.empty();
169
170 if (has_active)
171 {
172 while (has_active && (count >= active_list.front().delta))
173 {
174 timer_data& timer = active_list.front();
175
176 count -= timer.delta;
177
178 active_list.remove(timer.id, true);
179
180 if (timer.callback.is_valid())
181 {
182 timer.callback();
183 }
184
185 if (timer.repeating)
186 {
187 // Reinsert the timer.
188 timer.delta = timer.period;
189 active_list.insert(timer.id);
190 }
191
192 has_active = !active_list.empty();
193 }
194
195 if (has_active)
196 {
197 // Subtract any remainder from the next due timeout.
198 active_list.front().delta -= count;
199 }
200 }
201
202 return true;
203 }
204
205 return false;
206 }
207
208 //*******************************************
210 //*******************************************
212 {
213 bool result = false;
214
215 // Valid timer id?
216 if (id_ != etl::timer::id::NO_TIMER)
217 {
218 timer_data& timer = timer_array[id_];
219
220 // Registered timer?
221 if (timer.id != etl::timer::id::NO_TIMER)
222 {
223 // Has a valid period.
224 if (timer.period != etl::timer::state::Inactive)
225 {
226 TInterruptGuard guard;
227 (void)guard; // Silence 'unused variable warnings.
228
229 if (timer.is_active())
230 {
231 active_list.remove(timer.id, false);
232 }
233
234 timer.delta = immediate_ ? 0U : timer.period;
235 active_list.insert(timer.id);
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 TInterruptGuard guard;
263 (void)guard; // Silence 'unused variable warnings.
264
265 active_list.remove(timer.id, false);
266 }
267
268 result = true;
269 }
270 }
271
272 return result;
273 }
274
275 //*******************************************
277 //*******************************************
279 {
280 if (stop(id_))
281 {
282 timer_array[id_].period = period_;
283 return true;
284 }
285
286 return false;
287 }
288
289 //*******************************************
291 //*******************************************
293 {
294 if (stop(id_))
295 {
296 timer_array[id_].repeating = repeating_;
297 return true;
298 }
299
300 return false;
301 }
302
303 //*******************************************
305 //*******************************************
306 bool has_active_timer() const
307 {
308 TInterruptGuard guard;
309 (void)guard; // Silence 'unused variable warnings.
310 return !active_list.empty();
311 }
312
313 //*******************************************
316 //*******************************************
318 {
319 uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
320
321 TInterruptGuard guard;
322 (void)guard; // Silence 'unused variable warnings.
323
324 if (!active_list.empty())
325 {
326 delta = active_list.front().delta;
327 }
328
329 return delta;
330 }
331
332 //*******************************************
335 //*******************************************
337 {
338 // Valid timer id?
339 if (is_valid_timer_id(id_))
340 {
341 if (has_active_timer())
342 {
343 TInterruptGuard guard;
344 (void)guard; // Silence 'unused variable warnings.
345
346 const timer_data& timer = timer_array[id_];
347
348 // Registered timer?
349 if (timer.id != etl::timer::id::NO_TIMER)
350 {
351 return timer.is_active();
352 }
353 }
354 }
355
356 return false;
357 }
358
359 protected:
360
361 //*************************************************************************
364 {
365 //*******************************************
366 timer_data()
367 : callback()
368 , period(0U)
369 , delta(etl::timer::state::Inactive)
370 , id(etl::timer::id::NO_TIMER)
371 , previous(etl::timer::id::NO_TIMER)
372 , next(etl::timer::id::NO_TIMER)
373 , repeating(true)
374 {
375 }
376
377 //*******************************************
379 //*******************************************
383 bool repeating_)
385 , period(period_)
386 , delta(etl::timer::state::Inactive)
387 , id(id_)
388 , previous(etl::timer::id::NO_TIMER)
389 , next(etl::timer::id::NO_TIMER)
390 , repeating(repeating_)
391 {
392 }
393
394 //*******************************************
396 //*******************************************
397 bool is_active() const
398 {
399 return delta != etl::timer::state::Inactive;
400 }
401
402 //*******************************************
404 //*******************************************
406 {
407 delta = etl::timer::state::Inactive;
408 }
409
411 uint32_t period;
412 uint32_t delta;
414 uint_least8_t previous;
415 uint_least8_t next;
416 bool repeating;
417
418 private:
419
420 // Disabled.
421 timer_data(const timer_data& other) ETL_DELETE;
422 timer_data& operator =(const timer_data& other) ETL_DELETE;
423 };
424
425 //*******************************************
427 //*******************************************
429 : timer_array(timer_array_)
430 , active_list(timer_array_)
431 , enabled(false)
432 , number_of_registered_timers(0U)
433 , MAX_TIMERS(MAX_TIMERS_)
434 {
435 }
436
437 private:
438
439 //*******************************************
441 //*******************************************
442 bool is_valid_timer_id(etl::timer::id::type id_) const
443 {
444 return (id_ < MAX_TIMERS);
445 }
446
447 //*************************************************************************
449 //*************************************************************************
450 class timer_list
451 {
452 public:
453
454 //*******************************
455 timer_list(timer_data* ptimers_)
456 : head(etl::timer::id::NO_TIMER)
457 , tail(etl::timer::id::NO_TIMER)
458 , current(etl::timer::id::NO_TIMER)
459 , ptimers(ptimers_)
460 {
461 }
462
463 //*******************************
464 bool empty() const
465 {
466 return head == etl::timer::id::NO_TIMER;
467 }
468
469 //*******************************
470 // Inserts the timer at the correct delta position
471 //*******************************
472 void insert(etl::timer::id::type id_)
473 {
474 timer_data& timer = ptimers[id_];
475
476 if (head == etl::timer::id::NO_TIMER)
477 {
478 // No entries yet.
479 head = id_;
480 tail = id_;
481 timer.previous = etl::timer::id::NO_TIMER;
482 timer.next = etl::timer::id::NO_TIMER;
483 }
484 else
485 {
486 // We already have entries.
487 etl::timer::id::type test_id = begin();
488
489 while (test_id != etl::timer::id::NO_TIMER)
490 {
491 timer_data& test = ptimers[test_id];
492
493 // Find the correct place to insert.
494 if (timer.delta <= test.delta)
495 {
496 if (test.id == head)
497 {
498 head = timer.id;
499 }
500
501 // Insert before test.
502 timer.previous = test.previous;
503 test.previous = timer.id;
504 timer.next = test.id;
505
506 // Adjust the next delta to compensate.
507 test.delta -= timer.delta;
508
509 if (timer.previous != etl::timer::id::NO_TIMER)
510 {
511 ptimers[timer.previous].next = timer.id;
512 }
513 break;
514 }
515 else
516 {
517 timer.delta -= test.delta;
518 }
519
520 test_id = next(test_id);
521 }
522
523 // Reached the end?
524 if (test_id == etl::timer::id::NO_TIMER)
525 {
526 // Tag on to the tail.
527 ptimers[tail].next = timer.id;
528 timer.previous = tail;
529 timer.next = etl::timer::id::NO_TIMER;
530 tail = timer.id;
531 }
532 }
533 }
534
535 //*******************************
536 void remove(etl::timer::id::type id_, bool has_expired)
537 {
538 timer_data& timer = ptimers[id_];
539
540 if (head == id_)
541 {
542 head = timer.next;
543 }
544 else
545 {
546 ptimers[timer.previous].next = timer.next;
547 }
548
549 if (tail == id_)
550 {
551 tail = timer.previous;
552 }
553 else
554 {
555 ptimers[timer.next].previous = timer.previous;
556 }
557
558 if (!has_expired)
559 {
560 // Adjust the next delta.
561 if (timer.next != etl::timer::id::NO_TIMER)
562 {
563 ptimers[timer.next].delta += timer.delta;
564 }
565 }
566
567 timer.previous = etl::timer::id::NO_TIMER;
568 timer.next = etl::timer::id::NO_TIMER;
569 timer.delta = etl::timer::state::Inactive;
570 }
571
572 //*******************************
573 timer_data& front()
574 {
575 return ptimers[head];
576 }
577
578 //*******************************
579 const timer_data& front() const
580 {
581 return ptimers[head];
582 }
583
584 //*******************************
586 {
587 current = head;
588 return current;
589 }
590
591 //*******************************
593 {
594 current = ptimers[last].previous;
595 return current;
596 }
597
598 //*******************************
600 {
601 current = ptimers[last].next;
602 return current;
603 }
604
605 //*******************************
606 void clear()
607 {
609
610 while (id != etl::timer::id::NO_TIMER)
611 {
612 timer_data& timer = ptimers[id];
613 id = next(id);
614 timer.next = etl::timer::id::NO_TIMER;
615 }
616
617 head = etl::timer::id::NO_TIMER;
618 tail = etl::timer::id::NO_TIMER;
619 current = etl::timer::id::NO_TIMER;
620 }
621
622 private:
623
626 etl::timer::id::type current;
627
628 timer_data* const ptimers;
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 public:
641
642 const uint_least8_t MAX_TIMERS;
643 };
644
645 //***************************************************************************
647 //***************************************************************************
648 template <uint_least8_t MAX_TIMERS_, typename TInterruptGuard>
650 {
651 public:
652
653 ETL_STATIC_ASSERT(MAX_TIMERS_ <= 254U, "No more than 254 timers are allowed");
654
656
657 //*******************************************
659 //*******************************************
664
665 private:
666
668 };
669}
670
671#endif
The callback timer.
Definition callback_timer_interrupt.h:650
callback_timer_interrupt()
Constructor.
Definition callback_timer_interrupt.h:660
Definition callback.h:45
Declaration.
Definition delegate_cpp03.h:175
Interface for callback timer.
Definition callback_timer_interrupt.h:50
bool stop(etl::timer::id::type id_)
Stops a timer.
Definition callback_timer_interrupt.h:248
bool is_active(etl::timer::id::type id_) const
Definition callback_timer_interrupt.h:336
icallback_timer_interrupt(timer_data *const timer_array_, const uint_least8_t MAX_TIMERS_)
Constructor.
Definition callback_timer_interrupt.h:428
bool is_running() const
Get the enable/disable state.
Definition callback_timer_interrupt.h:133
uint32_t time_to_next() const
Definition callback_timer_interrupt.h:317
bool set_mode(etl::timer::id::type id_, bool repeating_)
Sets a timer's mode.
Definition callback_timer_interrupt.h:292
void enable(bool state_)
Enable/disable the timer.
Definition callback_timer_interrupt.h:125
etl::timer::id::type register_timer(const callback_type &callback_, uint32_t period_, bool repeating_)
Register a timer.
Definition callback_timer_interrupt.h:58
bool unregister_timer(etl::timer::id::type id_)
Unregister a timer.
Definition callback_timer_interrupt.h:93
bool start(etl::timer::id::type id_, bool immediate_=false)
Starts a timer.
Definition callback_timer_interrupt.h:211
void clear()
Clears the timer of data.
Definition callback_timer_interrupt.h:141
bool set_period(etl::timer::id::type id_, uint32_t period_)
Sets a timer's period.
Definition callback_timer_interrupt.h:278
bool has_active_timer() const
Check if there is an active timer.
Definition callback_timer_interrupt.h:306
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_interrupt.h:364
void set_inactive()
Sets the timer to the inactive state.
Definition callback_timer_interrupt.h:405
bool is_active() const
Returns true if the timer is active.
Definition callback_timer_interrupt.h:397
timer_data(etl::timer::id::type id_, callback_type callback_, uint32_t period_, bool repeating_)
ETL delegate callback.
Definition callback_timer_interrupt.h:380
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