Merge remote-tracking branch 'origin/development'

# Conflicts:
#	library.properties
#	src/callback_timer.h
#	src/message_timer.h
#	test/test_callback_timer.cpp
#	test/test_message_timer.cpp
This commit is contained in:
John Wellbelove 2017-10-21 09:24:16 +01:00
parent a47109783e
commit 13de62bd4f
6 changed files with 217 additions and 52 deletions

4
.gitignore vendored
View File

@ -9,6 +9,9 @@ test/keil/Debug
test/keil/Release
test/keil/Objects
test/keil/Listings
examples/ArmTimerCallbacks/Listings
examples/ArmTimerCallbacks/Objects
examples/ArmTimerCallbacks/DebugConfig
#################
## Eclipse
@ -27,6 +30,7 @@ local.properties
.classpath
.settings/
.loadpath
*.uvguix.John
# External tool builders
.externalToolBuilders/

View File

@ -1,5 +1,5 @@
name=Embedded Template Library
version=10.0.1
version=10.0.2
author= John Wellbelove <john.wellbelove@etlcpp.com>
maintainer=John Wellbelove <john.wellbelove@etlcpp.com>
sentence=A C++ template library tailored for embedded systems.

View File

@ -57,7 +57,7 @@ namespace etl
previous(etl::timer::id::NO_TIMER),
next(etl::timer::id::NO_TIMER),
repeating(true),
is_c_callback(true)
has_c_callback(true)
{
}
@ -75,7 +75,7 @@ namespace etl
previous(etl::timer::id::NO_TIMER),
next(etl::timer::id::NO_TIMER),
repeating(repeating_),
is_c_callback(true)
has_c_callback(true)
{
}
@ -93,7 +93,7 @@ namespace etl
previous(etl::timer::id::NO_TIMER),
next(etl::timer::id::NO_TIMER),
repeating(repeating_),
is_c_callback(false)
has_c_callback(false)
{
}
@ -120,7 +120,7 @@ namespace etl
uint_least8_t previous;
uint_least8_t next;
bool repeating;
bool is_c_callback;
bool has_c_callback;
private:
@ -453,7 +453,6 @@ namespace etl
}
registered_timers = 0;
tick_count = 0;
enable_timer_updates();
}
@ -468,42 +467,53 @@ namespace etl
{
if (enabled)
{
if (process_semaphore == 0)
if (process_semaphore.load() == 0)
{
// We have something to do?
if (!active_list.empty())
{
tick_count += count;
bool has_active = !active_list.empty();
while (!active_list.empty() && (tick_count >= active_list.front().delta))
if (has_active)
{
while (has_active && (count >= active_list.front().delta))
{
etl::callback_timer_data& timer = active_list.front();
tick_count -= timer.delta;
count -= timer.delta;
active_list.remove(timer.id, true);
if (timer.repeating)
{
// Reinsert the timer.
timer.delta = timer.period;
active_list.insert(timer.id);
}
if (timer.p_callback != nullptr)
{
if (timer.is_c_callback)
if (timer.has_c_callback)
{
// Call the C callback.
reinterpret_cast<void(*)()>(timer.p_callback)();
}
else
{
// Call the function wrapper callback.
(*reinterpret_cast<etl::ifunction<void>*>(timer.p_callback))();
}
}
has_active = !active_list.empty();
}
return true;
if (has_active)
{
// Subtract any remainder from the next due timeout.
active_list.front().delta -= count;
}
}
return true;
}
}
@ -515,10 +525,10 @@ namespace etl
//*******************************************
bool start(etl::timer::id::type id_, bool immediate_ = false)
{
bool result = false;
disable_timer_updates();
bool result = false;
// Valid timer id?
if (id_ != etl::timer::id::NO_TIMER)
{
@ -526,7 +536,7 @@ namespace etl
// Registered timer?
if (timer.id != etl::timer::id::NO_TIMER)
{
{
// Has a valid period.
if (timer.period != etl::timer::state::INACTIVE)
{
@ -535,17 +545,11 @@ namespace etl
active_list.remove(timer.id, false);
}
// Compensate for current tick count.
timer.delta = tick_count;
if (!immediate_)
{
timer.delta += timer.period;
}
timer.delta = immediate_ ? 0 : timer.period;
active_list.insert(timer.id);
result = true;
}
}
}
}
@ -559,10 +563,10 @@ namespace etl
//*******************************************
bool stop(etl::timer::id::type id_)
{
bool result = false;
disable_timer_updates();
bool result = false;
// Valid timer id?
if (id_ != etl::timer::id::NO_TIMER)
{
@ -622,7 +626,6 @@ namespace etl
active_list(timer_array_),
enabled(false),
process_semaphore(0),
tick_count(0),
registered_timers(0),
MAX_TIMERS(MAX_TIMERS_)
{
@ -654,7 +657,6 @@ namespace etl
volatile bool enabled;
volatile etl::timer_semaphore_t process_semaphore;
volatile uint32_t tick_count;
volatile uint_least8_t registered_timers;
public:

View File

@ -40,6 +40,7 @@ SOFTWARE.
#include "message_bus.h"
#include "static_assert.h"
#include "timer.h"
#include "atomic.h"
#undef ETL_FILE
#define ETL_FILE "41"
@ -417,7 +418,6 @@ namespace etl
}
registered_timers = 0;
tick_count = 0;
enable_timer_updates();
}
@ -432,18 +432,18 @@ namespace etl
{
if (enabled)
{
if (process_semaphore == 0)
if (process_semaphore.load() == 0)
{
// We have something to do?
if (!active_list.empty())
{
tick_count += count;
bool has_active = !active_list.empty();
while (!active_list.empty() && (tick_count >= active_list.front().delta))
if (has_active)
{
while (has_active && (count >= active_list.front().delta))
{
etl::message_timer_data& timer = active_list.front();
tick_count -= timer.delta;
count -= timer.delta;
active_list.remove(timer.id, true);
@ -467,10 +467,18 @@ namespace etl
timer.p_router->receive(*(timer.p_message));
}
}
has_active = !active_list.empty();
}
return true;
if (has_active)
{
// Subtract any remainder from the next due timeout.
active_list.front().delta -= count;
}
}
return true;
}
}
@ -502,15 +510,9 @@ namespace etl
active_list.remove(timer.id, false);
}
// Compensate for current tick count.
timer.delta = tick_count;
if (!immediate_)
{
timer.delta += timer.period;
}
timer.delta = immediate_ ? 0 : timer.period;
active_list.insert(timer.id);
result = true;
}
}
@ -589,7 +591,6 @@ namespace etl
active_list(timer_array_),
enabled(false),
process_semaphore(0),
tick_count(0),
registered_timers(0),
MAX_TIMERS(MAX_TIMERS_)
{
@ -621,7 +622,6 @@ namespace etl
volatile bool enabled;
volatile etl::timer_semaphore_t process_semaphore;
volatile uint32_t tick_count;
volatile uint_least8_t registered_timers;
public:

View File

@ -63,11 +63,27 @@ namespace
tick_list.push_back(ticks);
}
void callback2()
{
tick_list.push_back(ticks);
p_controller->start(2);
p_controller->start(1);
}
void set_controller(etl::callback_timer<3>& controller)
{
p_controller = &controller;
}
std::vector<uint64_t> tick_list;
etl::callback_timer<3>* p_controller;
};
Test test;
etl::function_mv<Test, &Test::callback> member_callback(test);
etl::function_imv<Test, test, &Test::callback> member_callback;
etl::function_imv<Test, test, &Test::callback2> member_callback2;
//***************************************************************************
// Free function callback via etl::function
@ -144,6 +160,10 @@ namespace
std::vector<uint64_t> compare2 = { 23 };
std::vector<uint64_t> compare3 = { 11 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -182,6 +202,10 @@ namespace
std::vector<uint64_t> compare2 = { 23, 46, 69, 92 };
std::vector<uint64_t> compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -224,6 +248,10 @@ namespace
std::vector<uint64_t> compare2 = { 25, 50, 70, 95 };
std::vector<uint64_t> compare3 = { 15, 25, 35, 45, 55, 70, 80, 90, 100 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -272,12 +300,90 @@ namespace
std::vector<uint64_t> compare1 = { 77 };
std::vector<uint64_t> compare2 = { 23 };
std::vector<uint64_t> compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
}
//=========================================================================
TEST(callback_timer_timer_starts_timer_small_step)
{
etl::callback_timer<3> timer_controller;
etl::timer::id::type id1 = timer_controller.register_timer(member_callback2, 100, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id2 = timer_controller.register_timer(member_callback, 10, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id3 = timer_controller.register_timer(member_callback, 22, etl::timer::mode::SINGLE_SHOT);
(void)id2;
(void)id3;
test.set_controller(timer_controller);
test.tick_list.clear();
timer_controller.start(id1);
timer_controller.enable(true);
ticks = 0;
const uint32_t step = 1;
while (ticks <= 200U)
{
ticks += step;
timer_controller.tick(step);
}
std::vector<uint64_t> compare1 = { 100, 110, 122 };
CHECK(test.tick_list.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
}
//=========================================================================
TEST(callback_timer_timer_starts_timer_big_step)
{
etl::callback_timer<3> timer_controller;
etl::timer::id::type id1 = timer_controller.register_timer(member_callback2, 100, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id2 = timer_controller.register_timer(member_callback, 10, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id3 = timer_controller.register_timer(member_callback, 22, etl::timer::mode::SINGLE_SHOT);
(void)id2;
(void)id3;
test.set_controller(timer_controller);
test.tick_list.clear();
timer_controller.start(id1);
timer_controller.enable(true);
ticks = 0;
const uint32_t step = 3;
while (ticks <= 200U)
{
ticks += step;
timer_controller.tick(step);
}
std::vector<uint64_t> compare1 = { 102, 111, 123 };
CHECK(test.tick_list.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
}
//=========================================================================
TEST(callback_timer_repeating_register_unregister)
{
@ -318,6 +424,10 @@ namespace
std::vector<uint64_t> compare2 = { 23 };
std::vector<uint64_t> compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -362,6 +472,10 @@ namespace
std::vector<uint64_t> compare2 = { 23 };
std::vector<uint64_t> compare3 = { 11, 22, 33 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -401,6 +515,10 @@ namespace
std::vector<uint64_t> compare2 = { 6, 28, 51, 74, 97 };
std::vector<uint64_t> compare3 = { 16, 27, 38, 49, 60, 71, 82, 93 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), compare2.size());
CHECK_ARRAY_EQUAL(compare3.data(), free_tick_list2.data(), compare3.size());
@ -435,6 +553,9 @@ namespace
std::vector<uint64_t> compare1 = { 22 };
std::vector<uint64_t> compare2 = { 11, 11, 22, 22 };
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), free_tick_list1.data(), compare1.size());
CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list2.data(), compare2.size());
}
@ -474,11 +595,21 @@ namespace
}
std::vector<uint64_t> compare1 = { 5, 10 };
CHECK(free_tick_list1.size() != 0);
CHECK_ARRAY_EQUAL(compare1.data(), free_tick_list1.data(), compare1.size());
}
//=========================================================================
#if REALTIME_TEST
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
#define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
#else
#error No thread priority modifier defined
#endif
etl::callback_timer<3> controller;
void timer_event()
@ -487,6 +618,9 @@ namespace
uint32_t tick = TICK;
ticks = 1;
RAISE_THREAD_PRIORITY;
FIX_PROCESSOR_AFFINITY;
while (ticks <= 1000)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -506,9 +640,11 @@ namespace
TEST(callback_timer_threads)
{
FIX_PROCESSOR_AFFINITY;
etl::timer::id::type id1 = controller.register_timer(member_callback, 400, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id2 = controller.register_timer(free_function_callback, 100, etl::timer::mode::REPEATING);
etl::timer::id::type id3 = controller.register_timer(free_callback2, 10, etl::timer::mode::REPEATING);
etl::timer::id::type id3 = controller.register_timer(free_callback2, 10, etl::timer::mode::REPEATING);
test.tick_list.clear();
free_tick_list1.clear();
@ -516,7 +652,7 @@ namespace
controller.start(id1);
controller.start(id2);
controller.start(id3);
//controller.start(id3);
controller.enable(true);
@ -524,7 +660,7 @@ namespace
bool restart_1 = true;
while (ticks < 1000U)
while (ticks <= 1000U)
{
if ((ticks > 200U) && (ticks < 500U))
{
@ -551,6 +687,16 @@ namespace
CHECK_EQUAL(2U, test.tick_list.size());
CHECK_EQUAL(10U, free_tick_list1.size());
CHECK(free_tick_list2.size() < 65U);
//std::vector<uint64_t> compare1 = { 400, 900 };
//std::vector<uint64_t> compare2 = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
CHECK(test.tick_list.size() != 0);
CHECK(free_tick_list1.size() != 0);
CHECK(free_tick_list2.size() != 0);
//CHECK_ARRAY_EQUAL(compare1.data(), test.tick_list.data(), min(compare1.size(), test.tick_list.size()));
//CHECK_ARRAY_EQUAL(compare2.data(), free_tick_list1.data(), min(compare2.size(), free_tick_list1.size()));
}
#endif
};

View File

@ -550,6 +550,14 @@ namespace
//=========================================================================
#if REALTIME_TEST
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
#define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
#else
#error No thread priority modifier defined
#endif
etl::message_timer<3> controller;
void timer_event()
@ -558,6 +566,9 @@ namespace
uint32_t tick = TICK;
ticks = 1;
RAISE_THREAD_PRIORITY;
FIX_PROCESSOR_AFFINITY;
while (ticks <= 1000)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -577,6 +588,8 @@ namespace
TEST(message_timer_threads)
{
FIX_PROCESSOR_AFFINITY;
etl::timer::id::type id1 = controller.register_timer(message1, router1, 400, etl::timer::mode::SINGLE_SHOT);
etl::timer::id::type id2 = controller.register_timer(message2, router1, 100, etl::timer::mode::REPEATING);
etl::timer::id::type id3 = controller.register_timer(message3, router1, 10, etl::timer::mode::REPEATING);