diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index 51a6849f..9b889057 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -86,7 +86,7 @@ namespace etl typedef etl::delegate callback_type; - typedef etl::delegate event_callback_type; + typedef etl::delegate event_callback_type; //******************************************* /// Register a timer. @@ -197,7 +197,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); - time_to_next_callback.call_if(time_to_next()); + time_to_next_callback.call_if(next_timer(), time_to_next()); ETL_ENABLE_TIMER_UPDATES; } @@ -296,7 +296,7 @@ namespace etl } } - time_to_next_callback.call_if(time_to_next()); + time_to_next_callback.call_if(next_timer(), time_to_next()); has_active = !active_list.empty(); } @@ -341,7 +341,7 @@ namespace etl timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); - time_to_next_callback.call_if(time_to_next()); + time_to_next_callback.call_if(next_timer(), time_to_next()); ETL_ENABLE_TIMER_UPDATES; result = true; @@ -371,7 +371,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); - time_to_next_callback.call_if(time_to_next()); + time_to_next_callback.call_if(next_timer(), time_to_next()); ETL_ENABLE_TIMER_UPDATES; } @@ -435,6 +435,23 @@ namespace etl return delta; } + //******************************************* + /// Get the ID of the next timer event. + /// Returns etl::timer::id::No_Timer if there is no active + /// timer. + //******************************************* + uint32_t next_timer() const + { + etl::timer::id::type id = etl::timer::id::No_Timer; + + if (has_active_timer()) + { + id = active_list.front().id; + } + + return id; + } + //******************************************* /// Checks if a timer is currently active. /// Returns true if the timer is active, otherwise false. diff --git a/include/etl/callback_timer_atomic.h b/include/etl/callback_timer_atomic.h index 98d92651..a849d141 100644 --- a/include/etl/callback_timer_atomic.h +++ b/include/etl/callback_timer_atomic.h @@ -51,7 +51,7 @@ namespace etl typedef etl::delegate callback_type; - typedef etl::delegate event_callback_type; + typedef etl::delegate event_callback_type; //******************************************* /// Register a timer. @@ -100,7 +100,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); - remove_callback.call_if(timer.id); + time_to_next_callback.call_if(time_to_next()); --process_semaphore; } @@ -172,7 +172,6 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); - remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -185,9 +184,10 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); - insert_callback.call_if(timer.id); } + time_to_next_callback.call_if(time_to_next()); + has_active = !active_list.empty(); } @@ -227,12 +227,11 @@ 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); + time_to_next_callback.call_if(time_to_next()); --process_semaphore; result = true; @@ -262,7 +261,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); - remove_callback.call_if(timer.id); + time_to_next_callback.call_if(time_to_next()); --process_semaphore; } @@ -360,32 +359,18 @@ 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_) + void set_time_to_next_callback(event_callback_type time_to_next_) { - remove_callback = remove_; + time_to_next_callback = time_to_next_; } //******************************************* - void clear_insert_callback() + void clear_time_next_callback() { - insert_callback.clear(); - } - - //******************************************* - void clear_remove_callback() - { - remove_callback.clear(); + time_to_next_callback.clear(); } protected: @@ -656,8 +641,7 @@ namespace etl mutable TSemaphore process_semaphore; uint_least8_t number_of_registered_timers; - event_callback_type insert_callback; - event_callback_type remove_callback; + event_callback_type time_to_next_callback; public: diff --git a/test/test_callback_timer.cpp b/test/test_callback_timer.cpp index 4b58277e..c087f560 100644 --- a/test/test_callback_timer.cpp +++ b/test/test_callback_timer.cpp @@ -93,20 +93,24 @@ namespace public: uint32_t time_to_next; + etl::timer::id::type next_timer_id; TimerTimeToNextTest() : time_to_next(0) + , next_timer_id(etl::timer::id::NO_TIMER) { } - void time_to_next_handler(uint32_t time_to_next_) + void time_to_next_handler(etl::timer::id::type next_timer_id_, uint32_t time_to_next_) { - time_to_next = time_to_next_; + time_to_next = time_to_next_; + next_timer_id = next_timer_id_; } void clear(void) { - time_to_next = 0; + time_to_next = 0; + next_timer_id = etl::timer::id::NO_TIMER; } }; @@ -843,15 +847,21 @@ namespace timer_controller.start(id3); timer_controller.start(id2); - CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the interval for id3. - + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the interval for id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // The next timer should be id3. timer_controller.enable(true); + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // The next timer should be id3. + CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); - CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the interval for id3. + // The time to next should be the interval for id3. + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // Tick the time for id3 to expire. timer_controller.tick(9); @@ -859,15 +869,23 @@ namespace CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); - CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the what's left of the interval for id3. + // The time to next should be the what's left of the interval for id3. + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // Stop the timer and check that the time to next is updated to that of id2. timer_controller.stop(id3); - CHECK_EQUAL(14, timerTimeToNextTest.time_to_next); // The time to next should be the what's left of the interval for id2. + // The time to next should be the what's left of the interval for id2. + CHECK_EQUAL(14, timerTimeToNextTest.time_to_next); + // The next timer should be id2. + CHECK_EQUAL(int(id2), int(timerTimeToNextTest.next_timer_id)); // Start the timer again and check that the time to next is updated to the interval for id3. timer_controller.start(id3); CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // Tick the time for id3 to expire. timer_controller.tick(9); @@ -877,6 +895,8 @@ namespace // The time to next should be the what's left of the interval for id2. CHECK_EQUAL(5, timerTimeToNextTest.time_to_next); + // The next timer should be id2. + CHECK_EQUAL(int(id2), int(timerTimeToNextTest.next_timer_id)); // Tick the remaining time for id2 to expire. timer_controller.tick(5); @@ -886,6 +906,8 @@ namespace // The time to next should be the what's left of the interval for id3. CHECK_EQUAL(4, timerTimeToNextTest.time_to_next); + // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // Tick the remaining time for id3 to expire. timer_controller.tick(4); @@ -895,6 +917,8 @@ namespace // The time to next should be the what's left of the interval for id3. CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + // The next timer should be id3. + CHECK_EQUAL(int(id3), int(timerTimeToNextTest.next_timer_id)); // Tick the remaining time for id3 to expire. timer_controller.tick(9); @@ -904,6 +928,8 @@ namespace // The time to next should be the what's left of the interval for id1. CHECK_EQUAL(1, timerTimeToNextTest.time_to_next); + // The next timer should be id1. + CHECK_EQUAL(int(id1), int(timerTimeToNextTest.next_timer_id)); // Stop timer id3 so that id1 is the last timeout. timer_controller.stop(id3); @@ -916,6 +942,8 @@ namespace // There are no active timers so the time to next should be No_Active_Interval. CHECK_EQUAL(etl::timer::interval::No_Active_Interval, timerTimeToNextTest.time_to_next); + // The next timer should be NO_TIMER. + CHECK_EQUAL(int(etl::timer::id::NO_TIMER), int(timerTimeToNextTest.next_timer_id)); } //************************************************************************* diff --git a/test/test_callback_timer_atomic.cpp b/test/test_callback_timer_atomic.cpp index 0dcea9ab..82e7f2b4 100644 --- a/test/test_callback_timer_atomic.cpp +++ b/test/test_callback_timer_atomic.cpp @@ -92,38 +92,29 @@ namespace callback_type member_callback1 = callback_type::create(); callback_type member_callback2 = callback_type::create(); - class TimerInsertRemoveTest + class TimerTimeToNextTest { public: - uint32_t inserted; - uint32_t removed; - TimerInsertRemoveTest() - : inserted(0) - , removed(0) + uint32_t time_to_next; + + TimerTimeToNextTest() + : time_to_next(0) { } - void insert_handler(etl::timer::id::type id_) + void time_to_next_handler(uint32_t time_to_next_) { - (void)id_; - inserted++; - } - - void remove_handler(etl::timer::id::type id_) - { - (void)id_; - removed++; + time_to_next = time_to_next_; } void clear(void) { - inserted = 0; - removed = 0; + time_to_next = 0; } }; - TimerInsertRemoveTest timerInsertRemoveTest; + TimerTimeToNextTest timerTimeToNextTest; //*************************************************************************** // Free function callback via etl::function @@ -800,26 +791,63 @@ namespace } //************************************************************************* - TEST(callback_timer_is_active) + // Tick ID1 ID2 ID3 + // 0 . . . + // 1 . . . + // 2 . . . + // 3 . . . + // 4 . . . + // 5 . . . + // 6 . . . + // 7 . . . + // 8 . . . + // 9 . . O + // 10 . . . + // 11 . . . + // 12 . . . + // 13 . . . + // 14 . . . + // 15 . . . + // 16 . . . + // 17 . . . + // 18 . . O + // 19 . . . + // 20 . . . + // 21 . . . + // 22 . . . + // 23 . O . + // 24 . . . + // 25 . . . + // 26 . . . + // 27 . . O + // 28 . . . + // 29 . . . + // 30 . . . + // 31 . . . + // 32 . . . + // 33 . . . + // 34 . . . + // 35 . . . + // 36 . . O + // 37 O . . + // + TEST(callback_timer_is_active_and_time_to_next) { - timerInsertRemoveTest.clear(); + timerTimeToNextTest.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); + etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 9, etl::timer::mode::Repeating); - timer_controller.set_insert_callback( - event_callback_type::create()); - timer_controller.set_remove_callback( - event_callback_type::create()); + timer_controller.set_time_to_next_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); + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the interval for id3. timer_controller.enable(true); @@ -827,32 +855,71 @@ namespace CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(0, timerInsertRemoveTest.removed); + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the interval for id3. - timer_controller.tick(11); + // Tick the time for id3 to expire. + timer_controller.tick(9); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); - CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_TRUE(timer_controller.is_active(id3)); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(1, timerInsertRemoveTest.removed); + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); // The time to next should be the what's left of the interval for id3. - timer_controller.tick(23 - 11); + // Stop the timer and check that the time to next is updated to that of id2. + timer_controller.stop(id3); + CHECK_EQUAL(14, timerTimeToNextTest.time_to_next); // The time to next should be the what's left of the interval for id2. + + // Start the timer again and check that the time to next is updated to the interval for id3. + timer_controller.start(id3); + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + + // Tick the time for id3 to expire. + timer_controller.tick(9); + CHECK_TRUE(timer_controller.is_active(id1)); + CHECK_TRUE(timer_controller.is_active(id2)); + CHECK_TRUE(timer_controller.is_active(id3)); + + // The time to next should be the what's left of the interval for id2. + CHECK_EQUAL(5, timerTimeToNextTest.time_to_next); + + // Tick the remaining time for id2 to expire. + timer_controller.tick(5); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); - CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_TRUE(timer_controller.is_active(id3)); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(2, timerInsertRemoveTest.removed); + // The time to next should be the what's left of the interval for id3. + CHECK_EQUAL(4, timerTimeToNextTest.time_to_next); - timer_controller.tick(37 - 23); + // Tick the remaining time for id3 to expire. + timer_controller.tick(4); + CHECK_TRUE(timer_controller.is_active(id1)); + CHECK_FALSE(timer_controller.is_active(id2)); + CHECK_TRUE(timer_controller.is_active(id3)); + + // The time to next should be the what's left of the interval for id3. + CHECK_EQUAL(9, timerTimeToNextTest.time_to_next); + + // Tick the remaining time for id3 to expire. + timer_controller.tick(9); + CHECK_TRUE(timer_controller.is_active(id1)); + CHECK_FALSE(timer_controller.is_active(id2)); + CHECK_TRUE(timer_controller.is_active(id3)); + + // The time to next should be the what's left of the interval for id1. + CHECK_EQUAL(1, timerTimeToNextTest.time_to_next); + + // Stop timer id3 so that id1 is the last timeout. + timer_controller.stop(id3); + + // Tick the remaining time for id1 to expire. + timer_controller.tick(1); 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); + // There are no active timers so the time to next should be No_Active_Interval. + CHECK_EQUAL(etl::timer::interval::No_Active_Interval, timerTimeToNextTest.time_to_next); } //*************************************************************************