diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index c725922d..e44320e9 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -77,305 +77,6 @@ SOFTWARE. namespace etl { - //************************************************************************* - /// The configuration of a timer. - struct callback_timer_data - { - typedef etl::delegate callback_type; - - enum callback_type_id - { - C_CALLBACK, - IFUNCTION, - DELEGATE - }; - - //******************************************* - callback_timer_data() - : p_callback(ETL_NULLPTR), - period(0), - delta(etl::timer::state::Inactive), - id(etl::timer::id::NO_TIMER), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(true), - cbk_type(IFUNCTION) - { - } - - //******************************************* - /// C function callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - void (*p_callback_)(), - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(p_callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(C_CALLBACK) - { - } - - //******************************************* - /// ETL function callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - etl::ifunction& callback_, - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(&callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(IFUNCTION) - { - } - - //******************************************* - /// ETL delegate callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - callback_type& callback_, - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(&callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(DELEGATE) - { - } - - //******************************************* - /// Returns true if the timer is active. - //******************************************* - bool is_active() const - { - return delta != etl::timer::state::Inactive; - } - - //******************************************* - /// Sets the timer to the inactive state. - //******************************************* - void set_inactive() - { - delta = etl::timer::state::Inactive; - } - - void* p_callback; - uint32_t period; - uint32_t delta; - etl::timer::id::type id; - uint_least8_t previous; - uint_least8_t next; - bool repeating; - callback_type_id cbk_type; - - private: - - // Disabled. - callback_timer_data(const callback_timer_data& other); - callback_timer_data& operator =(const callback_timer_data& other); - }; - - namespace private_callback_timer - { - //************************************************************************* - /// A specialised intrusive linked list for timer data. - //************************************************************************* - class list - { - public: - - //******************************* - list(etl::callback_timer_data* ptimers_) - : head(etl::timer::id::NO_TIMER), - tail(etl::timer::id::NO_TIMER), - current(etl::timer::id::NO_TIMER), - ptimers(ptimers_) - { - } - - //******************************* - bool empty() const - { - return head == etl::timer::id::NO_TIMER; - } - - //******************************* - // Inserts the timer at the correct delta position - //******************************* - void insert(etl::timer::id::type id_) - { - etl::callback_timer_data& timer = ptimers[id_]; - - if (head == etl::timer::id::NO_TIMER) - { - // No entries yet. - head = id_; - tail = id_; - timer.previous = etl::timer::id::NO_TIMER; - timer.next = etl::timer::id::NO_TIMER; - } - else - { - // We already have entries. - etl::timer::id::type test_id = begin(); - - while (test_id != etl::timer::id::NO_TIMER) - { - etl::callback_timer_data& test = ptimers[test_id]; - - // Find the correct place to insert. - if (timer.delta <= test.delta) - { - if (test.id == head) - { - head = timer.id; - } - - // Insert before test. - timer.previous = test.previous; - test.previous = timer.id; - timer.next = test.id; - - // Adjust the next delta to compensate. - test.delta -= timer.delta; - - if (timer.previous != etl::timer::id::NO_TIMER) - { - ptimers[timer.previous].next = timer.id; - } - break; - } - else - { - timer.delta -= test.delta; - } - - test_id = next(test_id); - } - - // Reached the end? - if (test_id == etl::timer::id::NO_TIMER) - { - // Tag on to the tail. - ptimers[tail].next = timer.id; - timer.previous = tail; - timer.next = etl::timer::id::NO_TIMER; - tail = timer.id; - } - } - } - - //******************************* - void remove(etl::timer::id::type id_, bool has_expired) - { - etl::callback_timer_data& timer = ptimers[id_]; - - if (head == id_) - { - head = timer.next; - } - else - { - ptimers[timer.previous].next = timer.next; - } - - if (tail == id_) - { - tail = timer.previous; - } - else - { - ptimers[timer.next].previous = timer.previous; - } - - if (!has_expired) - { - // Adjust the next delta. - if (timer.next != etl::timer::id::NO_TIMER) - { - ptimers[timer.next].delta += timer.delta; - } - } - - timer.previous = etl::timer::id::NO_TIMER; - timer.next = etl::timer::id::NO_TIMER; - timer.delta = etl::timer::state::Inactive; - } - - //******************************* - etl::callback_timer_data& front() - { - return ptimers[head]; - } - - //******************************* - const etl::callback_timer_data& front() const - { - return ptimers[head]; - } - - //******************************* - etl::timer::id::type begin() - { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; - } - - //******************************* - etl::timer::id::type next(etl::timer::id::type last) - { - current = ptimers[last].next; - return current; - } - - //******************************* - void clear() - { - etl::timer::id::type id = begin(); - - while (id != etl::timer::id::NO_TIMER) - { - etl::callback_timer_data& timer = ptimers[id]; - id = next(id); - timer.next = etl::timer::id::NO_TIMER; - } - - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; - } - - private: - - etl::timer::id::type head; - etl::timer::id::type tail; - etl::timer::id::type current; - - etl::callback_timer_data* const ptimers; - }; - } - //*************************************************************************** /// Interface for callback timer //*************************************************************************** @@ -385,6 +86,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -401,12 +104,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, p_callback_, period_, repeating_); + new (&timer) timer_data(i, p_callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -433,12 +136,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, callback_, period_, repeating_); + new (&timer) timer_data(i, callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -466,12 +169,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, callback_, period_, repeating_); + new (&timer) timer_data(i, callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -492,7 +195,7 @@ namespace etl if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; if (timer.id != etl::timer::id::NO_TIMER) { @@ -500,11 +203,12 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } // Reset in-place. - new (&timer) callback_timer_data(); + new (&timer) timer_data(); --registered_timers; result = true; @@ -541,7 +245,7 @@ namespace etl for (int i = 0; i < MAX_TIMERS; ++i) { - ::new (&timer_array[i]) callback_timer_data(); + ::new (&timer_array[i]) timer_data(); } registered_timers = 0; @@ -566,32 +270,34 @@ namespace etl { while (has_active && (count >= active_list.front().delta)) { - etl::callback_timer_data& timer = active_list.front(); + timer_data& timer = active_list.front(); count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.repeating) { // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } if (timer.p_callback != ETL_NULLPTR) { - if (timer.cbk_type == callback_timer_data::C_CALLBACK) + if (timer.cbk_type == timer_data::C_CALLBACK) { // Call the C callback. reinterpret_cast(timer.p_callback)(); } - else if(timer.cbk_type == callback_timer_data::IFUNCTION) + else if(timer.cbk_type == timer_data::IFUNCTION) { // Call the function wrapper callback. (*reinterpret_cast*>(timer.p_callback))(); } - else if(timer.cbk_type == callback_timer_data::DELEGATE) + else if(timer.cbk_type == timer_data::DELEGATE) { // Call the delegate callback. (*reinterpret_cast(timer.p_callback))(); @@ -625,7 +331,7 @@ namespace etl // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -637,10 +343,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; result = true; @@ -661,7 +369,7 @@ namespace etl // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -670,6 +378,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -743,7 +452,7 @@ namespace etl { if (has_active_timer()) { - const etl::callback_timer_data& timer = timer_array[id_]; + const timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -756,12 +465,152 @@ namespace etl return false; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: + //************************************************************************* + /// The configuration of a timer. + struct timer_data + { + typedef etl::delegate callback_type; + + enum callback_type_id + { + C_CALLBACK, + IFUNCTION, + DELEGATE + }; + + //******************************************* + timer_data() + : p_callback(ETL_NULLPTR) + , period(0) + , delta(etl::timer::state::Inactive) + , id(etl::timer::id::NO_TIMER) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(true) + , cbk_type(IFUNCTION) + { + } + + //******************************************* + /// C function callback + //******************************************* + timer_data(etl::timer::id::type id_, + void (*p_callback_)(), + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(p_callback_)) + , period(period_) + , delta(etl::timer::state::Inactive) + , id(id_) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(repeating_) + , cbk_type(C_CALLBACK) + { + } + + //******************************************* + /// ETL function callback + //******************************************* + timer_data(etl::timer::id::type id_, + etl::ifunction& callback_, + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(&callback_)) + , period(period_) + , delta(etl::timer::state::Inactive) + , id(id_) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(repeating_) + , cbk_type(IFUNCTION) + { + } + + //******************************************* + /// ETL delegate callback + //******************************************* + timer_data(etl::timer::id::type id_, + callback_type& callback_, + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(&callback_)), + period(period_), + delta(etl::timer::state::Inactive), + id(id_), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(repeating_), + cbk_type(DELEGATE) + { + } + + //******************************************* + /// Returns true if the timer is active. + //******************************************* + bool is_active() const + { + return delta != etl::timer::state::Inactive; + } + + //******************************************* + /// Sets the timer to the inactive state. + //******************************************* + void set_inactive() + { + delta = etl::timer::state::Inactive; + } + + void* p_callback; + uint32_t period; + uint32_t delta; + etl::timer::id::type id; + uint_least8_t previous; + uint_least8_t next; + bool repeating; + callback_type_id cbk_type; + + private: + + // Disabled. + timer_data(const timer_data& other); + timer_data& operator =(const timer_data& other); + }; + //******************************************* /// Constructor. //******************************************* - icallback_timer(callback_timer_data* const timer_array_, const uint_least8_t Max_Timers_) + icallback_timer(timer_data* const timer_array_, const uint_least8_t Max_Timers_) : timer_array(timer_array_), active_list(timer_array_), enabled(false), @@ -783,11 +632,193 @@ namespace etl return (id_ < MAX_TIMERS); } + //************************************************************************* + class timer_list + { + public: + + //******************************* + timer_list(timer_data* ptimers_) + : head(etl::timer::id::NO_TIMER) + , tail(etl::timer::id::NO_TIMER) + , current(etl::timer::id::NO_TIMER) + , ptimers(ptimers_) + { + } + + //******************************* + bool empty() const + { + return head == etl::timer::id::NO_TIMER; + } + + //******************************* + // Inserts the timer at the correct delta position + //******************************* + void insert(etl::timer::id::type id_) + { + timer_data& timer = ptimers[id_]; + + if (head == etl::timer::id::NO_TIMER) + { + // No entries yet. + head = id_; + tail = id_; + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + } + else + { + // We already have entries. + etl::timer::id::type test_id = begin(); + + while (test_id != etl::timer::id::NO_TIMER) + { + timer_data& test = ptimers[test_id]; + + // Find the correct place to insert. + if (timer.delta <= test.delta) + { + if (test.id == head) + { + head = timer.id; + } + + // Insert before test. + timer.previous = test.previous; + test.previous = timer.id; + timer.next = test.id; + + // Adjust the next delta to compensate. + test.delta -= timer.delta; + + if (timer.previous != etl::timer::id::NO_TIMER) + { + ptimers[timer.previous].next = timer.id; + } + break; + } + else + { + timer.delta -= test.delta; + } + + test_id = next(test_id); + } + + // Reached the end? + if (test_id == etl::timer::id::NO_TIMER) + { + // Tag on to the tail. + ptimers[tail].next = timer.id; + timer.previous = tail; + timer.next = etl::timer::id::NO_TIMER; + tail = timer.id; + } + } + } + + //******************************* + void remove(etl::timer::id::type id_, bool has_expired) + { + timer_data& timer = ptimers[id_]; + + if (head == id_) + { + head = timer.next; + } + else + { + ptimers[timer.previous].next = timer.next; + } + + if (tail == id_) + { + tail = timer.previous; + } + else + { + ptimers[timer.next].previous = timer.previous; + } + + if (!has_expired) + { + // Adjust the next delta. + if (timer.next != etl::timer::id::NO_TIMER) + { + ptimers[timer.next].delta += timer.delta; + } + } + + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + timer.delta = etl::timer::state::Inactive; + } + + //******************************* + timer_data& front() + { + return ptimers[head]; + } + + //******************************* + const timer_data& front() const + { + return ptimers[head]; + } + + //******************************* + etl::timer::id::type begin() + { + current = head; + return current; + } + + //******************************* + etl::timer::id::type previous(etl::timer::id::type last) + { + current = ptimers[last].previous; + return current; + } + + //******************************* + etl::timer::id::type next(etl::timer::id::type last) + { + current = ptimers[last].next; + return current; + } + + //******************************* + void clear() + { + etl::timer::id::type id = begin(); + + while (id != etl::timer::id::NO_TIMER) + { + timer_data& timer = ptimers[id]; + id = next(id); + timer.next = etl::timer::id::NO_TIMER; + } + + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; + current = etl::timer::id::NO_TIMER; + } + + private: + + etl::timer::id::type head; + etl::timer::id::type tail; + etl::timer::id::type current; + + timer_data* const ptimers; + }; + // The array of timer data structures. - callback_timer_data* const timer_array; + timer_data* const timer_array; // The list of active timers. - private_callback_timer::list active_list; + timer_list active_list; volatile bool enabled; #if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) @@ -806,6 +837,9 @@ namespace etl #endif uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t MAX_TIMERS; @@ -831,7 +865,7 @@ namespace etl private: - callback_timer_data timer_array[Max_Timers_]; + timer_data timer_array[Max_Timers_]; }; } diff --git a/include/etl/callback_timer_atomic.h b/include/etl/callback_timer_atomic.h index d2c63a47..b18703aa 100644 --- a/include/etl/callback_timer_atomic.h +++ b/include/etl/callback_timer_atomic.h @@ -53,6 +53,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -102,6 +104,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -173,6 +176,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -185,6 +189,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -226,10 +231,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); --process_semaphore; result = true; @@ -259,6 +266,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -355,6 +363,34 @@ namespace etl return result; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -638,6 +674,9 @@ namespace etl mutable TSemaphore process_semaphore; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/callback_timer_deferred_locked.h b/include/etl/callback_timer_deferred_locked.h index 2cd97d10..ce760648 100644 --- a/include/etl/callback_timer_deferred_locked.h +++ b/include/etl/callback_timer_deferred_locked.h @@ -54,22 +54,7 @@ namespace etl private: - class CallbackNode - { - public: - - CallbackNode(callback_type &callback_,uint_least8_t priority_) : callback(callback_), priority(priority_) - { - } - - bool operator < (const CallbackNode& p) const - { - return this->priority > p.priority; // comparison was inverted here to easy the code design - } - - callback_type callback; - uint_least8_t priority; - }; + typedef icallback_timer_locked::callback_node callback_node; public: @@ -111,12 +96,13 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { if (!handler_queue.full()) { - handler_queue.push(CallbackNode(timer.callback, timer_priorities[timer.id])); + handler_queue.push(callback_node(timer.callback, timer_priorities[timer.id])); } } @@ -125,6 +111,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -165,7 +152,7 @@ namespace etl } else { - CallbackNode &work_todo_callback_node = handler_queue.top(); + callback_node &work_todo_callback_node = handler_queue.top(); work_todo_callback = work_todo_callback_node.callback; handler_queue.pop(); } @@ -211,7 +198,7 @@ namespace etl private: - priority_queue handler_queue; + priority_queue handler_queue; uint_least8_t timer_priorities[Max_Timers_]; timer_data timer_array[Max_Timers_]; }; diff --git a/include/etl/callback_timer_interrupt.h b/include/etl/callback_timer_interrupt.h index 22058cdc..247b69de 100644 --- a/include/etl/callback_timer_interrupt.h +++ b/include/etl/callback_timer_interrupt.h @@ -52,6 +52,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -106,6 +108,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } // Reset in-place. @@ -176,6 +179,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -187,6 +191,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -229,10 +234,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); result = true; } @@ -263,6 +270,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } result = true; @@ -356,6 +364,34 @@ namespace etl return false; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -637,6 +673,9 @@ namespace etl bool enabled; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/callback_timer_locked.h b/include/etl/callback_timer_locked.h index 861f2101..75689634 100644 --- a/include/etl/callback_timer_locked.h +++ b/include/etl/callback_timer_locked.h @@ -54,6 +54,8 @@ namespace etl typedef etl::delegate lock_type; typedef etl::delegate unlock_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -103,6 +105,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -180,10 +183,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); unlock(); result = true; @@ -213,6 +218,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -319,8 +325,53 @@ namespace etl return result; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: + class callback_node + { + public: + + callback_node(callback_type &callback_,uint_least8_t priority_) : callback(callback_), priority(priority_) + { + } + + bool operator < (const callback_node& p) const + { + return this->priority > p.priority; // comparison was inverted here to easy the code design + } + + callback_type callback; + uint_least8_t priority; + }; + //************************************************************************* /// The configuration of a timer. struct timer_data @@ -604,7 +655,11 @@ namespace etl lock_type lock; ///< The callback that locks. unlock_type unlock; ///< The callback that unlocks. + event_callback_type insert_callback; + event_callback_type remove_callback; + public: + template friend class callback_timer_locked; @@ -629,6 +684,12 @@ namespace etl typedef icallback_timer_locked::lock_type lock_type; typedef icallback_timer_locked::unlock_type unlock_type; + private: + + typedef icallback_timer_locked::callback_node callback_node; + + public: + //******************************************* /// Constructor. //******************************************* @@ -646,8 +707,9 @@ namespace etl this->set_locks(try_lock_, lock_, unlock_); } - // Implement virtual functions - + //******************************************* + /// Handle the tick call + //******************************************* bool tick(uint32_t count) final { if (enabled) @@ -666,6 +728,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -677,6 +740,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 2a2c2d89..d5898fb2 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -301,65 +301,65 @@ namespace etl ///\ingroup error_handler //*************************************************************************** #if defined(ETL_NO_CHECKS) - #define ETL_ASSERT(b, e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT(b, e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_OR_RETURN(b, e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) static_cast(sizeof(b)) // Does nothing. - #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN(e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT_FAIL(e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN(e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) static_cast(sizeof(b)) // Does nothing. #elif defined(ETL_USE_ASSERT_FUNCTION) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} while(false) // If the condition fails, calls the assert function + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} while(false) // If the condition fails, calls the assert function and return + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} while(false) // If the condition fails, calls the assert function and return a value - #define ETL_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value + #define ETL_ASSERT_FAIL(e) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} while(false) // Calls the assert function + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} while(false) // Calls the assert function and return + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} while(false) // Calls the assert function and return a value #elif ETL_USING_EXCEPTIONS #if defined(ETL_LOG_ERRORS) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} while(false) // If the condition fails, calls the error handler then throws an exception. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} while(false) // If the condition fails, calls the error handler then throws an exception. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} while(false) // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL(e) {etl::error_handler::error((e)); throw((e));} // Calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); throw((e)); return;} // Calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL(e) do {etl::error_handler::error((e)); throw((e));} while(false) // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::error_handler::error((e)); throw((e)); return;} while(false) // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::error_handler::error((e)); throw((e)); return(v);} while(false) // Calls the error handler then throws an exception. #else - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. - #define ETL_ASSERT_FAIL(e) {throw((e));} // Throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception. + #define ETL_ASSERT_FAIL(e) do {throw((e));} while(false) // Throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {throw((e));} while(false) // Throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {throw((e));} while(false) // Throws an exception. #endif #else #if defined(ETL_LOG_ERRORS) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} // If the condition fails, calls the error handler - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} // If the condition fails, calls the error handler and return - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} // If the condition fails, calls the error handler and return a value + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} while(false) // If the condition fails, calls the error handler + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} while(false) // If the condition fails, calls the error handler and return + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} while(false) // If the condition fails, calls the error handler and return a value - #define ETL_ASSERT_FAIL(e) {etl::error_handler::error((e));} // Calls the error handler - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); return;} // Calls the error handler and return - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); return (v);} // Calls the error handler and return a value + #define ETL_ASSERT_FAIL(e) do {etl::error_handler::error((e));} while(false) // Calls the error handler + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::error_handler::error((e)); return;} while(false) // Calls the error handler and return + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::error_handler::error((e)); return (v);} while(false) // Calls the error handler and return a value #else #if ETL_IS_DEBUG_BUILD - #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {assert(false); return;}} // If the condition fails, asserts and return. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} // If the condition fails, asserts and return a value. + #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {assert(false); return;}} while(false) // If the condition fails, asserts and return. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} while(false) // If the condition fails, asserts and return a value. - #define ETL_ASSERT_FAIL(e) assert(false) // Asserts. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {assert(false); return;} // Asserts. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts. + #define ETL_ASSERT_FAIL(e) assert(false) // Asserts. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {assert(false); return;} while(false) // Asserts. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {assert(false); return(v);} while(false) // Asserts. #else - #define ETL_ASSERT(b, e) // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY return;} // Returns. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY return(v);} // Returns a value. + #define ETL_ASSERT(b, e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY return;} while(false) // Returns. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY return(v);} while(false) // Returns a value. - #define ETL_ASSERT_FAIL(e) // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value. + #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {return;} while(false) // Returns. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {return(v);} while(false) // Returns a value. #endif #endif #endif @@ -376,7 +376,6 @@ namespace etl #elif ETL_DEBUG_USING_EXCEPTIONS #if defined(ETL_DEBUG_LOG_ERRORS) #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. @@ -385,7 +384,6 @@ namespace etl #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. #else #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. @@ -448,10 +446,12 @@ namespace etl #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. + #define ETL_ERROR_UNTYPED(text) (etl::exception((text),__FILE__,__LINE__)) // Make a generic exception with a message, file name and line number. #else #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. + #define ETL_ERROR_UNTYPED(text) (etl::exception((text),"",__LINE__)) // Make a generic exception with a message and line number. #endif #endif diff --git a/include/etl/message_timer.h b/include/etl/message_timer.h index 7ddc55fc..094d8b03 100644 --- a/include/etl/message_timer.h +++ b/include/etl/message_timer.h @@ -39,6 +39,7 @@ SOFTWARE. #include "timer.h" #include "atomic.h" #include "algorithm.h" +#include "delegate.h" #include @@ -341,6 +342,8 @@ namespace etl { public: + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -396,6 +399,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -467,11 +471,13 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.repeating) { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } if (timer.p_router != ETL_NULLPTR) @@ -518,10 +524,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; result = true; @@ -551,6 +559,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -619,6 +628,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //******************************************* @@ -669,6 +706,9 @@ namespace etl #endif uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/message_timer_atomic.h b/include/etl/message_timer_atomic.h index a8826da2..cf349c57 100644 --- a/include/etl/message_timer_atomic.h +++ b/include/etl/message_timer_atomic.h @@ -39,6 +39,7 @@ SOFTWARE. #include "timer.h" #include "atomic.h" #include "algorithm.h" +#include "delegate.h" #include @@ -54,6 +55,8 @@ namespace etl { public: + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -109,6 +112,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -180,6 +184,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -190,6 +195,7 @@ namespace etl { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -231,10 +237,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); --process_semaphore; result = true; @@ -264,6 +272,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -332,6 +341,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -620,6 +657,9 @@ namespace etl mutable TSemaphore process_semaphore; uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t MAX_TIMERS; diff --git a/include/etl/message_timer_interrupt.h b/include/etl/message_timer_interrupt.h index 5fc0281d..6945d968 100644 --- a/include/etl/message_timer_interrupt.h +++ b/include/etl/message_timer_interrupt.h @@ -54,6 +54,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + public: //******************************************* @@ -116,6 +118,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); } // Reset in-place. @@ -187,6 +190,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -198,6 +202,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -240,10 +245,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); result = true; } @@ -274,6 +281,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } result = true; @@ -340,6 +348,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -626,6 +662,9 @@ namespace etl bool enabled; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/message_timer_locked.h b/include/etl/message_timer_locked.h index 9f0e2a2c..1d4e4b61 100644 --- a/include/etl/message_timer_locked.h +++ b/include/etl/message_timer_locked.h @@ -56,6 +56,8 @@ namespace etl typedef etl::delegate lock_type; typedef etl::delegate unlock_type; + typedef etl::delegate event_callback_type; + public: //******************************************* @@ -113,6 +115,7 @@ namespace etl { lock(); active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); unlock(); } @@ -184,6 +187,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -194,6 +198,7 @@ namespace etl { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -237,10 +242,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); unlock(); result = true; @@ -270,6 +277,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -348,6 +356,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -638,6 +674,8 @@ namespace etl lock_type lock; ///< The callback that locks. unlock_type unlock; ///< The callback that unlocks. + event_callback_type insert_callback; + event_callback_type remove_callback; public: const uint_least8_t Max_Timers; diff --git a/test/test_callback_timer.cpp b/test/test_callback_timer.cpp index e800990d..62b2a059 100644 --- a/test/test_callback_timer.cpp +++ b/test/test_callback_timer.cpp @@ -81,10 +81,42 @@ namespace etl::callback_timer<3>* p_controller; }; + using event_callback_type = etl::icallback_timer::event_callback_type; + Object object; etl::function_imv member_callback; etl::function_imv member_callback2; + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -762,36 +794,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer<4> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_atomic.cpp b/test/test_callback_timer_atomic.cpp index 97d1b366..01b09e89 100644 --- a/test/test_callback_timer_atomic.cpp +++ b/test/test_callback_timer_atomic.cpp @@ -86,10 +86,42 @@ namespace using callback_type = etl::icallback_timer_atomic::callback_type; + using event_callback_type = etl::icallback_timer_atomic::event_callback_type; + Object object; callback_type member_callback1 = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -767,36 +799,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer_atomic<3, std::atomic_uint32_t> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_deferred_locked.cpp b/test/test_callback_timer_deferred_locked.cpp index 591cf732..46aaafe5 100644 --- a/test/test_callback_timer_deferred_locked.cpp +++ b/test/test_callback_timer_deferred_locked.cpp @@ -147,6 +147,8 @@ namespace using lock_type = etl::icallback_timer_locked::lock_type; using unlock_type = etl::icallback_timer_locked::unlock_type; + using event_callback_type = etl::icallback_timer_locked::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); @@ -154,6 +156,36 @@ namespace callback_type member_callback_inc2 = callback_type::create(); callback_type member_callback_inc3 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -980,6 +1012,7 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -991,33 +1024,51 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); timer_controller.handle_deferred(); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); timer_controller.handle_deferred(); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); timer_controller.handle_deferred(); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* @@ -1034,6 +1085,9 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); @@ -1042,7 +1096,7 @@ namespace timer_controller.tick(11); timer_controller.handle_deferred(); - CHECK_EQUAL(12, timer_controller.time_to_next()); + CHECK_EQUAL(23 - 11, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); timer_controller.tick(23); diff --git a/test/test_callback_timer_interrupt.cpp b/test/test_callback_timer_interrupt.cpp index e13683d1..ae373c6e 100644 --- a/test/test_callback_timer_interrupt.cpp +++ b/test/test_callback_timer_interrupt.cpp @@ -99,10 +99,42 @@ namespace using callback_type = etl::icallback_timer_interrupt::callback_type; + using event_callback_type = etl::icallback_timer_interrupt::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -775,36 +807,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer_interrupt<3, ScopedGuard> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_locked.cpp b/test/test_callback_timer_locked.cpp index c0e21bd1..ddeda3a4 100644 --- a/test/test_callback_timer_locked.cpp +++ b/test/test_callback_timer_locked.cpp @@ -121,10 +121,42 @@ namespace using lock_type = etl::icallback_timer_locked::lock_type; using unlock_type = etl::icallback_timer_locked::unlock_type; + using event_callback_type = etl::icallback_timer_locked::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -874,6 +906,7 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -885,30 +918,48 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer.cpp b/test/test_message_timer.cpp index 0d5231f6..1e4eca2e 100644 --- a/test/test_message_timer.cpp +++ b/test/test_message_timer.cpp @@ -134,6 +134,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer) { //************************************************************************* @@ -646,35 +678,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer<3> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer_atomic.cpp b/test/test_message_timer_atomic.cpp index 98a899ee..b612cd46 100644 --- a/test/test_message_timer_atomic.cpp +++ b/test/test_message_timer_atomic.cpp @@ -134,6 +134,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_atomic::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer) { //************************************************************************* @@ -646,35 +678,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer_atomic<3, std::atomic_uint32_t> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer_interrupt.cpp b/test/test_message_timer_interrupt.cpp index e746644b..7c66edb9 100644 --- a/test/test_message_timer_interrupt.cpp +++ b/test/test_message_timer_interrupt.cpp @@ -157,6 +157,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_interrupt::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer_interrupt) { //************************************************************************* @@ -693,35 +725,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer_interrupt<3, ScopedGuard> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer_locked.cpp b/test/test_message_timer_locked.cpp index c3078c2d..6d7c1215 100644 --- a/test/test_message_timer_locked.cpp +++ b/test/test_message_timer_locked.cpp @@ -168,6 +168,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_locked::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + using try_lock_type = etl::imessage_timer_locked::try_lock_type; using lock_type = etl::imessage_timer_locked::lock_type; using unlock_type = etl::imessage_timer_locked::unlock_type; @@ -773,6 +805,7 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -784,29 +817,50 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 3d361cfb..bc0e7529 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -11376,11 +11376,13 @@ + + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 3b9bf643..088c6ca8 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3886,6 +3886,12 @@ ETL\Arduino + + Resource Files\CI\Github + + + Resource Files\CI\Github +