Embedded Template Library 1.0
Loading...
Searching...
No Matches
message_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_MESSAGE_TIMER_INTERRUPT_INCLUDED
30#define ETL_MESSAGE_TIMER_INTERRUPT_INCLUDED
31
32#include "platform.h"
33#include "nullptr.h"
34#include "message_types.h"
35#include "message.h"
36#include "message_router.h"
37#include "message_bus.h"
38#include "static_assert.h"
39#include "timer.h"
40#include "delegate.h"
41#include "algorithm.h"
42
43#include <stdint.h>
44
45namespace etl
46{
47 //***************************************************************************
49 //***************************************************************************
50 template <typename TInterruptGuard>
52 {
53 public:
54
55 typedef etl::delegate<void(void)> callback_type;
56
57 public:
58
59 //*******************************************
61 //*******************************************
65 bool repeating_,
66 etl::message_router_id_t destination_router_id_ = etl::imessage_router::ALL_MESSAGE_ROUTERS)
67 {
68 etl::timer::id::type id = etl::timer::id::NO_TIMER;
69
70 bool is_space = (number_of_registered_timers < MAX_TIMERS);
71
72 if (is_space)
73 {
74 // There's no point adding null message routers.
75 if (!router_.is_null_router())
76 {
77 // Search for the free space.
78 for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i)
79 {
80 timer_data& timer = timer_array[i];
81
82 if (timer.id == etl::timer::id::NO_TIMER)
83 {
84 TInterruptGuard guard;
85 (void)guard; // Silence 'unused variable warnings.
86
87 // Create in-place.
89 ++number_of_registered_timers;
90 id = i;
91 break;
92 }
93 }
94 }
95 }
96
97 return id;
98 }
99
100 //*******************************************
102 //*******************************************
104 {
105 bool result = false;
106
107 if (id_ != etl::timer::id::NO_TIMER)
108 {
109 timer_data& timer = timer_array[id_];
110
111 if (timer.id != etl::timer::id::NO_TIMER)
112 {
113 if (timer.is_active())
114 {
115 TInterruptGuard guard;
116 (void)guard; // Silence 'unused variable warnings.
117
118 active_list.remove(timer.id, true);
119 }
120
121 // Reset in-place.
122 new (&timer) timer_data();
123 --number_of_registered_timers;
124
125 result = true;
126 }
127 }
128
129 return result;
130 }
131
132 //*******************************************
134 //*******************************************
135 void enable(bool state_)
136 {
137 enabled = state_;
138 }
139
140 //*******************************************
142 //*******************************************
143 bool is_running() const
144 {
145 return enabled;
146 }
147
148 //*******************************************
150 //*******************************************
151 void clear()
152 {
153 {
154 TInterruptGuard guard;
155 (void)guard; // Silence 'unused variable warnings.
156
157 active_list.clear();
158 }
159
160 for (int i = 0; i < MAX_TIMERS; ++i)
161 {
162 new (&timer_array[i]) timer_data();
163 }
164
165 number_of_registered_timers = 0U;
166 }
167
168 //*******************************************
169 // Called by the timer service to indicate the
170 // amount of time that has elapsed since the last successful call to 'tick'.
171 // Returns true if the tick was processed,
172 // false if not.
173 //*******************************************
174 bool tick(uint32_t count)
175 {
176 if (enabled)
177 {
178 // We have something to do?
179 bool has_active = !active_list.empty();
180
181 if (has_active)
182 {
183 while (has_active && (count >= active_list.front().delta))
184 {
185 timer_data& timer = active_list.front();
186
187 count -= timer.delta;
188
189 active_list.remove(timer.id, true);
190
191 if (timer.p_router != ETL_NULLPTR)
192 {
193 timer.p_router->receive(timer.destination_router_id, *(timer.p_message));
194 }
195
196 if (timer.repeating)
197 {
198 // Reinsert the timer.
199 timer.delta = timer.period;
200 active_list.insert(timer.id);
201 }
202
203 has_active = !active_list.empty();
204 }
205
206 if (has_active)
207 {
208 // Subtract any remainder from the next due timeout.
209 active_list.front().delta -= count;
210 }
211 }
212
213 return true;
214 }
215
216 return false;
217 }
218
219 //*******************************************
221 //*******************************************
223 {
224 bool result = false;
225
226 // Valid timer id?
227 if (id_ != etl::timer::id::NO_TIMER)
228 {
229 timer_data& timer = timer_array[id_];
230
231 // Registered timer?
232 if (timer.id != etl::timer::id::NO_TIMER)
233 {
234 // Has a valid period.
235 if (timer.period != etl::timer::state::Inactive)
236 {
237 TInterruptGuard guard;
238 (void)guard; // Silence 'unused variable warnings.
239
240 if (timer.is_active())
241 {
242 active_list.remove(timer.id, false);
243 }
244
245 timer.delta = immediate_ ? 0 : timer.period;
246 active_list.insert(timer.id);
247
248 result = true;
249 }
250 }
251 }
252
253 return result;
254 }
255
256 //*******************************************
258 //*******************************************
260 {
261 bool result = false;
262
263 // Valid timer id?
264 if (id_ != etl::timer::id::NO_TIMER)
265 {
266 timer_data& timer = timer_array[id_];
267
268 // Registered timer?
269 if (timer.id != etl::timer::id::NO_TIMER)
270 {
271 if (timer.is_active())
272 {
273 TInterruptGuard guard;
274 (void)guard; // Silence 'unused variable warnings.
275
276 active_list.remove(timer.id, false);
277 }
278
279 result = true;
280 }
281 }
282
283 return result;
284 }
285
286 //*******************************************
288 //*******************************************
290 {
291 if (stop(id_))
292 {
293 timer_array[id_].period = period_;
294 return true;
295 }
296
297 return false;
298 }
299
300 //*******************************************
302 //*******************************************
304 {
305 if (stop(id_))
306 {
307 timer_array[id_].repeating = repeating_;
308 return true;
309 }
310
311 return false;
312 }
313
314 //*******************************************
316 //*******************************************
317 bool has_active_timer() const
318 {
319 TInterruptGuard guard;
320 (void)guard; // Silence 'unused variable warnings.
321 return !active_list.empty();
322 }
323
324 //*******************************************
327 //*******************************************
329 {
330 uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
331
332 TInterruptGuard guard;
333 (void)guard; // Silence 'unused variable warnings.
334
335 if (!active_list.empty())
336 {
337 delta = active_list.front().delta;
338 }
339
340 return delta;
341 }
342
343 protected:
344
345 //*************************************************************************
348 {
349 //*******************************************
350 timer_data()
351 : p_message(ETL_NULLPTR)
352 , p_router(ETL_NULLPTR)
353 , period(0)
354 , delta(etl::timer::state::Inactive)
355 , destination_router_id(etl::imessage_bus::ALL_MESSAGE_ROUTERS)
356 , id(etl::timer::id::NO_TIMER)
357 , previous(etl::timer::id::NO_TIMER)
358 , next(etl::timer::id::NO_TIMER)
359 , repeating(true)
360 {
361 }
362
363 //*******************************************
365 const etl::imessage& message_,
368 bool repeating_,
369 etl::message_router_id_t destination_router_id_ = etl::imessage_bus::ALL_MESSAGE_ROUTERS)
370 : p_message(&message_)
371 , p_router(&irouter_)
372 , period(period_)
373 , delta(etl::timer::state::Inactive)
374 , destination_router_id(destination_router_id_)
375 , id(id_)
376 , previous(etl::timer::id::NO_TIMER)
377 , next(etl::timer::id::NO_TIMER)
378 , repeating(repeating_)
379 {
380 }
381
382 //*******************************************
384 //*******************************************
385 bool is_active() const
386 {
387 return delta != etl::timer::state::Inactive;
388 }
389
390 //*******************************************
392 //*******************************************
394 {
395 delta = etl::timer::state::Inactive;
396 }
397
398 const etl::imessage* p_message;
399 etl::imessage_router* p_router;
400 uint32_t period;
401 uint32_t delta;
402 etl::message_router_id_t destination_router_id;
404 uint_least8_t previous;
405 uint_least8_t next;
406 bool repeating;
407
408 private:
409
410 // Disabled.
413 };
414
415 //*******************************************
417 //*******************************************
419 : timer_array(timer_array_)
420 , active_list(timer_array_)
421 , enabled(false)
422 , number_of_registered_timers(0U)
423 , MAX_TIMERS(MAX_TIMERS_)
424 {
425 }
426
427 //*******************************************
429 //*******************************************
433
434 private:
435
436 //*************************************************************************
438 //*************************************************************************
439 class timer_list
440 {
441 public:
442
443 //*******************************
444 timer_list(timer_data* ptimers_)
445 : head(etl::timer::id::NO_TIMER)
446 , tail(etl::timer::id::NO_TIMER)
447 , current(etl::timer::id::NO_TIMER)
448 , ptimers(ptimers_)
449 {
450 }
451
452 //*******************************
453 bool empty() const
454 {
455 return head == etl::timer::id::NO_TIMER;
456 }
457
458 //*******************************
459 // Inserts the timer at the correct delta position
460 //*******************************
461 void insert(etl::timer::id::type id_)
462 {
463 timer_data& timer = ptimers[id_];
464
465 if (head == etl::timer::id::NO_TIMER)
466 {
467 // No entries yet.
468 head = id_;
469 tail = id_;
470 timer.previous = etl::timer::id::NO_TIMER;
471 timer.next = etl::timer::id::NO_TIMER;
472 }
473 else
474 {
475 // We already have entries.
476 etl::timer::id::type test_id = begin();
477
478 while (test_id != etl::timer::id::NO_TIMER)
479 {
480 timer_data& test = ptimers[test_id];
481
482 // Find the correct place to insert.
483 if (timer.delta <= test.delta)
484 {
485 if (test.id == head)
486 {
487 head = timer.id;
488 }
489
490 // Insert before test.
491 timer.previous = test.previous;
492 test.previous = timer.id;
493 timer.next = test.id;
494
495 // Adjust the next delta to compensate.
496 test.delta -= timer.delta;
497
498 if (timer.previous != etl::timer::id::NO_TIMER)
499 {
500 ptimers[timer.previous].next = timer.id;
501 }
502 break;
503 }
504 else
505 {
506 timer.delta -= test.delta;
507 }
508
509 test_id = next(test_id);
510 }
511
512 // Reached the end?
513 if (test_id == etl::timer::id::NO_TIMER)
514 {
515 // Tag on to the tail.
516 ptimers[tail].next = timer.id;
517 timer.previous = tail;
518 timer.next = etl::timer::id::NO_TIMER;
519 tail = timer.id;
520 }
521 }
522 }
523
524 //*******************************
525 void remove(etl::timer::id::type id_, bool has_expired)
526 {
527 timer_data& timer = ptimers[id_];
528
529 if (head == id_)
530 {
531 head = timer.next;
532 }
533 else
534 {
535 ptimers[timer.previous].next = timer.next;
536 }
537
538 if (tail == id_)
539 {
540 tail = timer.previous;
541 }
542 else
543 {
544 ptimers[timer.next].previous = timer.previous;
545 }
546
547 if (!has_expired)
548 {
549 // Adjust the next delta.
550 if (timer.next != etl::timer::id::NO_TIMER)
551 {
552 ptimers[timer.next].delta += timer.delta;
553 }
554 }
555
556 timer.previous = etl::timer::id::NO_TIMER;
557 timer.next = etl::timer::id::NO_TIMER;
558 timer.delta = etl::timer::state::Inactive;
559 }
560
561 //*******************************
562 timer_data& front()
563 {
564 return ptimers[head];
565 }
566
567 //*******************************
568 const timer_data& front() const
569 {
570 return ptimers[head];
571 }
572
573 //*******************************
575 {
576 current = head;
577 return current;
578 }
579
580 //*******************************
582 {
583 current = ptimers[last].previous;
584 return current;
585 }
586
587 //*******************************
589 {
590 current = ptimers[last].next;
591 return current;
592 }
593
594 //*******************************
595 void clear()
596 {
598
599 while (id != etl::timer::id::NO_TIMER)
600 {
601 timer_data& timer = ptimers[id];
602 id = next(id);
603 timer.next = etl::timer::id::NO_TIMER;
604 }
605
606 head = etl::timer::id::NO_TIMER;
607 tail = etl::timer::id::NO_TIMER;
608 current = etl::timer::id::NO_TIMER;
609 }
610
611 private:
612
615 etl::timer::id::type current;
616
617 timer_data* const ptimers;
618 };
619
620 // The array of timer data structures.
621 timer_data* const timer_array;
622
623 // The list of active timers.
624 timer_list active_list;
625
626 bool enabled;
627 uint_least8_t number_of_registered_timers;
628
629 public:
630
631 const uint_least8_t MAX_TIMERS;
632 };
633
634 //***************************************************************************
636 //***************************************************************************
637 template <uint_least8_t MAX_TIMERS_, typename TInterruptGuard>
639 {
640 public:
641
642 ETL_STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed");
643
645
646 //*******************************************
648 //*******************************************
653
654 private:
655
657 };
658}
659
660#endif
Declaration.
Definition delegate_cpp03.h:191
This is the base of all message routers.
Definition message_router_generator.h:121
Interface for message timer.
Definition message_timer_interrupt.h:52
bool set_mode(etl::timer::id::type id_, bool repeating_)
Sets a timer's mode.
Definition message_timer_interrupt.h:303
bool start(etl::timer::id::type id_, bool immediate_=false)
Starts a timer.
Definition message_timer_interrupt.h:222
bool unregister_timer(etl::timer::id::type id_)
Unregister a timer.
Definition message_timer_interrupt.h:103
etl::timer::id::type register_timer(const etl::imessage &message_, etl::imessage_router &router_, uint32_t period_, bool repeating_, etl::message_router_id_t destination_router_id_=etl::imessage_router::ALL_MESSAGE_ROUTERS)
Register a timer.
Definition message_timer_interrupt.h:62
imessage_timer_interrupt(timer_data *const timer_array_, const uint_least8_t MAX_TIMERS_)
Constructor.
Definition message_timer_interrupt.h:418
void clear()
Clears the timer of data.
Definition message_timer_interrupt.h:151
bool stop(etl::timer::id::type id_)
Stops a timer.
Definition message_timer_interrupt.h:259
void enable(bool state_)
Enable/disable the timer.
Definition message_timer_interrupt.h:135
~imessage_timer_interrupt()
Destructor.
Definition message_timer_interrupt.h:430
bool has_active_timer() const
Check if there is an active timer.
Definition message_timer_interrupt.h:317
bool is_running() const
Get the enable/disable state.
Definition message_timer_interrupt.h:143
uint32_t time_to_next() const
Definition message_timer_interrupt.h:328
bool set_period(etl::timer::id::type id_, uint32_t period_)
Sets a timer's period.
Definition message_timer_interrupt.h:289
Definition message.h:73
The message timer.
Definition message_timer_interrupt.h:639
message_timer_interrupt()
Constructor.
Definition message_timer_interrupt.h:649
ETL_CONSTEXPR14 TIterator remove(TIterator first, TIterator last, const T &value)
Definition algorithm.h:2192
bitset_ext
Definition absolute.h:38
ETL_CONSTEXPR TContainer::iterator begin(TContainer &container)
Definition iterator.h:962
The configuration of a timer.
Definition message_timer_interrupt.h:348
bool is_active() const
Returns true if the timer is active.
Definition message_timer_interrupt.h:385
void set_inactive()
Sets the timer to the inactive state.
Definition message_timer_interrupt.h:393
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