diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index 0d1ff258..83d1b1a9 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -39,6 +39,7 @@ SOFTWARE. #include "static_assert.h" #include "timer.h" #include "atomic.h" +#include "delegate.h" #undef ETL_FILE #define ETL_FILE "43" @@ -73,6 +74,9 @@ namespace etl /// The configuration of a timer. struct callback_timer_data { + enum callback_type { + C_CALLBACK,IFUNCTION,DELEGATE + }; //******************************************* callback_timer_data() : p_callback(nullptr), @@ -82,7 +86,7 @@ namespace etl previous(etl::timer::id::NO_TIMER), next(etl::timer::id::NO_TIMER), repeating(true), - has_c_callback(true) + cbk_type(IFUNCTION) { } @@ -100,7 +104,7 @@ namespace etl previous(etl::timer::id::NO_TIMER), next(etl::timer::id::NO_TIMER), repeating(repeating_), - has_c_callback(true) + cbk_type(C_CALLBACK) { } @@ -118,10 +122,28 @@ namespace etl previous(etl::timer::id::NO_TIMER), next(etl::timer::id::NO_TIMER), repeating(repeating_), - has_c_callback(false) + cbk_type(IFUNCTION) { } + //******************************************* + /// ETL delegate callback + //******************************************* + callback_timer_data(etl::timer::id::type id_, + etl::delegate& 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. //******************************************* @@ -145,7 +167,7 @@ namespace etl uint_least8_t previous; uint_least8_t next; bool repeating; - bool has_c_callback; + callback_type cbk_type; private: @@ -406,6 +428,38 @@ namespace etl return id; } + //******************************************* + /// Register a timer. + //******************************************* + etl::timer::id::type register_timer(etl::delegate& callback_, + uint32_t period_, + bool repeating_) + { + etl::timer::id::type id = etl::timer::id::NO_TIMER; + + bool is_space = (registered_timers < MAX_TIMERS); + + if (is_space) + { + // Search for the free space. + for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) + { + etl::callback_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_); + ++registered_timers; + id = i; + break; + } + } + } + + return id; + } + //******************************************* /// Unregister a timer. //******************************************* @@ -504,16 +558,24 @@ namespace etl if (timer.p_callback != nullptr) { - if (timer.has_c_callback) + if (timer.cbk_type == callback_timer_data::C_CALLBACK) { // Call the C callback. reinterpret_cast(timer.p_callback)(); } - else + else if(timer.cbk_type == callback_timer_data::IFUNCTION) { // Call the function wrapper callback. (*reinterpret_cast*>(timer.p_callback))(); } + else if(timer.cbk_type == callback_timer_data::DELEGATE) + { + // Call the function wrapper callback. + (*reinterpret_cast*>(timer.p_callback))(); + } + else { + ETL_ALWAYS_ASSERT("Callback timer have incorrect callback type stored") + } } has_active = !active_list.empty(); diff --git a/test/test_callback_timer.cpp b/test/test_callback_timer.cpp index b0ad6fa9..640fe532 100644 --- a/test/test_callback_timer.cpp +++ b/test/test_callback_timer.cpp @@ -130,7 +130,7 @@ namespace //========================================================================= TEST(callback_timer_one_shot) { - etl::callback_timer<3> timer_controller; + 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); @@ -646,6 +646,29 @@ namespace CHECK_ARRAY_EQUAL(compare1.data(), free_tick_list1.data(), compare1.size()); } + class test_object{ + public: + void call() { + called++; + } + size_t called = 0; + }; + + TEST(callback_timer_call_etl_delegate) + { + test_object test_obj; + etl::delegate delegate_callback = etl::delegate::create(test_obj); + etl::callback_timer<1> timer_controller; + timer_controller.enable(true); + etl::timer::id::type id = timer_controller.register_timer(delegate_callback, 5, etl::timer::mode::SINGLE_SHOT); + timer_controller.start(id); + timer_controller.tick(4); + CHECK(test_obj.called == 0); + timer_controller.tick(2); + CHECK(test_obj.called == 1); + + } + //========================================================================= #if REALTIME_TEST