mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Work in progress
This commit is contained in:
parent
b9456c0b62
commit
024b2dd2c5
@ -1,401 +0,0 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2017 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_INTRUSIVE_TIMER_INCLUDED
|
||||
#define ETL_INTRUSIVE_TIMER_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
#include "algorithm.h"
|
||||
#include "error_handler.h"
|
||||
#include "nullptr.h"
|
||||
#include "static_assert.h"
|
||||
#include "timer_lists.h"
|
||||
#include "timer_node.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
/// Interface for timer lock policy
|
||||
//***************************************************************************
|
||||
class timer_lock_policy
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
virtual bool is_locked() = 0;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Interface for intrusive timer
|
||||
//***************************************************************************
|
||||
class intrusive_timer
|
||||
{
|
||||
public:
|
||||
|
||||
typedef etl::delegate<void(etl::timer_data::id::type, uint32_t delta)> timer_update_callback_type;
|
||||
|
||||
//*******************************************
|
||||
/// Constructor.
|
||||
//*******************************************
|
||||
explicit intrusive_timer(timer_lock_policy& lock_policy_)
|
||||
: lock_policy(lock_policy_)
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Register a timer.
|
||||
//*******************************************
|
||||
etl::timer::id::type register_timer(etl::timer_node& node)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Unregister a timer.
|
||||
//*******************************************
|
||||
bool unregister_timer(etl::timer_node& node)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (id_ != etl::timer::id::No_Timer)
|
||||
{
|
||||
timer_data& timer = timer_array[id_];
|
||||
|
||||
if (timer.id != etl::timer::id::No_Timer)
|
||||
{
|
||||
if (timer.is_active())
|
||||
{
|
||||
lock_policy.lock();
|
||||
active_list.remove(timer.id, false);
|
||||
remove_callback.call_if(timer.id);
|
||||
lock_policy.unlock();
|
||||
}
|
||||
|
||||
// Reset in-place.
|
||||
new (&timer) timer_data();
|
||||
--registered_timers;
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Enable/disable the timer.
|
||||
//*******************************************
|
||||
void enable(bool state_)
|
||||
{
|
||||
enabled = state_;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Get the enable/disable state.
|
||||
//*******************************************
|
||||
bool is_running() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Clears the timer of data.
|
||||
//*******************************************
|
||||
void clear()
|
||||
{
|
||||
lock_policy.lock();
|
||||
active_list.clear();
|
||||
lock_policy.unlock();
|
||||
|
||||
for (int i = 0; i < MAX_TIMERS; ++i)
|
||||
{
|
||||
::new (&timer_array[i]) timer_data();
|
||||
}
|
||||
|
||||
registered_timers = 0;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
// Called by the timer service to indicate the
|
||||
// amount of time that has elapsed since the last successful call to 'tick'.
|
||||
// Returns true if the tick was processed,
|
||||
// false if not.
|
||||
//*******************************************
|
||||
bool tick(uint32_t count)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
if (!lock_policy.is_locked())
|
||||
{
|
||||
// We have something to do?
|
||||
bool has_active = !active_list.empty();
|
||||
|
||||
if (has_active)
|
||||
{
|
||||
while (has_active && (count >= active_list.front().delta))
|
||||
{
|
||||
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 == timer_data::C_CALLBACK)
|
||||
{
|
||||
// Call the C callback.
|
||||
reinterpret_cast<void (*)()>(timer.p_callback)();
|
||||
}
|
||||
else if (timer.cbk_type == timer_data::IFUNCTION)
|
||||
{
|
||||
// Call the function wrapper callback.
|
||||
(*reinterpret_cast<etl::ifunction<void>*>(timer.p_callback))();
|
||||
}
|
||||
else if (timer.cbk_type == timer_data::DELEGATE)
|
||||
{
|
||||
// Call the delegate callback.
|
||||
(*reinterpret_cast<callback_type*>(timer.p_callback))();
|
||||
}
|
||||
}
|
||||
|
||||
has_active = !active_list.empty();
|
||||
}
|
||||
|
||||
if (has_active)
|
||||
{
|
||||
// Subtract any remainder from the next due timeout.
|
||||
active_list.front().delta -= count;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Starts a timer.
|
||||
//*******************************************
|
||||
bool start(etl::timer::id::type id_, bool immediate_ = false)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Valid timer id?
|
||||
if (id_ != etl::timer::id::No_Timer)
|
||||
{
|
||||
timer_data& timer = timer_array[id_];
|
||||
|
||||
// Registered timer?
|
||||
if (timer.id != etl::timer::id::No_Timer)
|
||||
{
|
||||
// Has a valid period.
|
||||
if (timer.period != etl::timer::state::Inactive)
|
||||
{
|
||||
ETL_DISABLE_TIMER_UPDATES;
|
||||
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);
|
||||
lock_policy.unlock();
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Stops a timer.
|
||||
//*******************************************
|
||||
bool stop(etl::timer::id::type id_)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Valid timer id?
|
||||
if (id_ != etl::timer::id::No_Timer)
|
||||
{
|
||||
timer_data& timer = timer_array[id_];
|
||||
|
||||
// Registered timer?
|
||||
if (timer.id != etl::timer::id::No_Timer)
|
||||
{
|
||||
if (timer.is_active())
|
||||
{
|
||||
ETL_DISABLE_TIMER_UPDATES;
|
||||
active_list.remove(timer.id, false);
|
||||
remove_callback.call_if(timer.id);
|
||||
lock_policy.unlock();
|
||||
}
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Sets a timer's period.
|
||||
//*******************************************
|
||||
bool set_period(etl::timer::id::type id_, uint32_t period_)
|
||||
{
|
||||
if (stop(id_))
|
||||
{
|
||||
timer_array[id_].period = period_;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Sets a timer's mode.
|
||||
//*******************************************
|
||||
bool set_mode(etl::timer::id::type id_, bool repeating_)
|
||||
{
|
||||
if (stop(id_))
|
||||
{
|
||||
timer_array[id_].repeating = repeating_;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Check if there is an active timer.
|
||||
//*******************************************
|
||||
bool has_active_timer() const
|
||||
{
|
||||
return !active_list.empty();
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Get the time to the next timer event.
|
||||
/// Returns etl::timer::interval::No_Active_Interval if there is no active
|
||||
/// timer.
|
||||
//*******************************************
|
||||
uint32_t time_to_next() const
|
||||
{
|
||||
uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
|
||||
|
||||
if (has_active_timer())
|
||||
{
|
||||
delta = active_list.front().delta;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Checks if a timer is currently active.
|
||||
/// Returns <b>true</b> if the timer is active, otherwise <b>false</b>.
|
||||
//*******************************************
|
||||
bool is_active(etl::timer::id::type id_) const
|
||||
{
|
||||
//// Valid timer id?
|
||||
// if (is_valid_timer_id(id_))
|
||||
//{
|
||||
// if (has_active_timer())
|
||||
// {
|
||||
// const timer_data& timer = timer_array[id_];
|
||||
|
||||
// // Registered timer?
|
||||
// if (timer.id != etl::timer::id::No_Timer)
|
||||
// {
|
||||
// return timer.is_active();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
intrusive_timer(const intrusive_timer&) ETL_DELETE;
|
||||
intrusive_timer& operator=(const intrusive_timer&) ETL_DELETE;
|
||||
|
||||
etl::timer_lock_policy& lock_policy;
|
||||
etl::private_timer::timer_register_list register_list;
|
||||
etl::private_timer::timer_active_list active_list;
|
||||
etl::private_timer::timer_triggered_list triggered_list;
|
||||
};
|
||||
} // namespace etl
|
||||
|
||||
#endif
|
||||
452
include/etl/intrusive_timer.h
Normal file
452
include/etl/intrusive_timer.h
Normal file
@ -0,0 +1,452 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2017 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_INTRUSIVE_TIMER_INCLUDED
|
||||
#define ETL_INTRUSIVE_TIMER_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
#include "algorithm.h"
|
||||
#include "delegate.h"
|
||||
#include "error_handler.h"
|
||||
#include "nullptr.h"
|
||||
#include "static_assert.h"
|
||||
#include "timer_node.h"
|
||||
|
||||
#include "private/timer_lists.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
/// Interface for timer lock policy
|
||||
//***************************************************************************
|
||||
class timer_lock_policy
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void lock() ETL_NOEXCEPT = 0;
|
||||
virtual void unlock() ETL_NOEXCEPT = 0;
|
||||
virtual bool is_locked() ETL_NOEXCEPT = 0;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Interface for intrusive timer
|
||||
//***************************************************************************
|
||||
class intrusive_timer
|
||||
{
|
||||
public:
|
||||
|
||||
typedef etl::delegate<void(etl::timer::id::type, uint32_t delta)> timer_update_callback_type;
|
||||
|
||||
//*******************************************
|
||||
/// Constructor.
|
||||
//*******************************************
|
||||
explicit intrusive_timer(timer_lock_policy& lock_policy_) ETL_NOEXCEPT
|
||||
: lock_policy(lock_policy_)
|
||||
, register_list()
|
||||
, active_list()
|
||||
, expired_list()
|
||||
, enabled(false)
|
||||
, timer_count(0U)
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Register a timer.
|
||||
/// It will not be started until the start() method is called.
|
||||
//*******************************************
|
||||
bool register_timer(etl::timer_node& node) ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer::id::type id = node.get_id();
|
||||
bool result = false;
|
||||
|
||||
if (id != etl::timer::id::No_Timer)
|
||||
{
|
||||
lock_policy.lock();
|
||||
|
||||
// Remove any existing timer with the same id.
|
||||
active_list.remove(id);
|
||||
register_list.remove(id);
|
||||
|
||||
// Register the new timer.
|
||||
register_list.insert(&node);
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
result = true;
|
||||
++timer_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Unregister a timer.
|
||||
/// By id.
|
||||
//*******************************************
|
||||
bool unregister_timer(etl::timer::id::type id) ETL_NOEXCEPT
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (id != etl::timer::id::No_Timer)
|
||||
{
|
||||
lock_policy.lock();
|
||||
|
||||
active_list.remove(id);
|
||||
register_list.remove(id);
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
result = true;
|
||||
--timer_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Unregister a timer.
|
||||
/// By node reference.
|
||||
//*******************************************
|
||||
bool unregister_timer(etl::timer_node& node) ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer::id::type id = node.get_id();
|
||||
|
||||
return unregister_timer(id);
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Enable/disable the timer.
|
||||
//*******************************************
|
||||
void enable(bool state_) ETL_NOEXCEPT
|
||||
{
|
||||
enabled = state_;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Get the enable/disable state.
|
||||
//*******************************************
|
||||
bool is_running() const ETL_NOEXCEPT
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Clears the timer of data.
|
||||
//*******************************************
|
||||
void clear() ETL_NOEXCEPT
|
||||
{
|
||||
lock_policy.lock();
|
||||
|
||||
active_list.clear();
|
||||
register_list.clear();
|
||||
|
||||
lock_policy.unlock();
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
// Called by the timer service to indicate the
|
||||
// amount of time that has elapsed since the last successful call to 'tick'.
|
||||
// Returns true if the tick was processed,
|
||||
// false if not.
|
||||
//*******************************************
|
||||
bool tick(uint32_t count)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
if (!lock_policy.is_locked())
|
||||
{
|
||||
lock_policy.lock();
|
||||
|
||||
// We have something to do?
|
||||
bool has_active = !active_list.empty();
|
||||
|
||||
if (has_active)
|
||||
{
|
||||
// Process timers that have expired.
|
||||
etl::timer_node* timer = active_list.first();
|
||||
|
||||
while (has_active && (count >= timer->delta))
|
||||
{
|
||||
count -= timer->delta;
|
||||
|
||||
active_list.remove(timer->get_id());
|
||||
|
||||
// If the timer is repeating then add it back to the active list.
|
||||
if (timer->get_mode() == etl::timer::mode::Repeating)
|
||||
{
|
||||
// Reinsert the timer.
|
||||
timer->delta = timer->get_period();
|
||||
active_list.insert(timer);
|
||||
}
|
||||
|
||||
expired_list.insert(timer);
|
||||
|
||||
timer = active_list.first();
|
||||
|
||||
has_active = !active_list.empty();
|
||||
}
|
||||
|
||||
if (has_active)
|
||||
{
|
||||
// Subtract any remainder from the next due timeout.
|
||||
active_list.first()->delta -= count;
|
||||
}
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
// Invoke all of the expired timers.
|
||||
invoke_expired_timers();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Starts a timer.
|
||||
//*******************************************
|
||||
bool start(etl::timer::id::type id_, bool immediate_ = false) ETL_NOEXCEPT
|
||||
{
|
||||
bool is_started = false;
|
||||
|
||||
lock_policy.lock();
|
||||
|
||||
etl::timer_node* timer = find_timer(register_list, id_);
|
||||
|
||||
if (timer != register_list.end())
|
||||
{
|
||||
active_list.insert(timer);
|
||||
is_started = true;
|
||||
}
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
if (is_started && immediate_)
|
||||
{
|
||||
// Trigger the timer immediately.
|
||||
timer->invoke(timer->get_config());
|
||||
}
|
||||
|
||||
return is_started;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Stops a timer.
|
||||
//*******************************************
|
||||
bool stop(etl::timer::id::type id_) ETL_NOEXCEPT
|
||||
{
|
||||
bool is_stopped = false;
|
||||
|
||||
lock_policy.lock();
|
||||
|
||||
is_stopped = (stop_impl(id_) != active_list.end());
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
return is_stopped;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Sets a timer's period.
|
||||
//*******************************************
|
||||
bool set_period(etl::timer::id::type id_, uint32_t period_) ETL_NOEXCEPT
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
lock_policy.lock();
|
||||
|
||||
stop_impl(id_);
|
||||
|
||||
etl::timer_node* timer = find_timer(register_list, id_);
|
||||
|
||||
if (timer != active_list.end())
|
||||
{
|
||||
timer->set_period(period_);
|
||||
result = true;
|
||||
}
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Sets a timer's mode.
|
||||
//*******************************************
|
||||
bool set_mode(etl::timer::id::type id_, bool mode_) ETL_NOEXCEPT
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
lock_policy.lock();
|
||||
|
||||
stop_impl(id_);
|
||||
|
||||
etl::timer_node* timer = find_timer(register_list, id_);
|
||||
|
||||
if (timer != active_list.end())
|
||||
{
|
||||
timer->set_mode(mode_);
|
||||
result = true;
|
||||
}
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Check if there is an active timer.
|
||||
//*******************************************
|
||||
bool has_active_timer() const ETL_NOEXCEPT
|
||||
{
|
||||
lock_policy.lock();
|
||||
bool has_active = !active_list.empty();
|
||||
lock_policy.unlock();
|
||||
|
||||
return has_active;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Get the time to the next timer event.
|
||||
/// Returns etl::timer::interval::No_Active_Interval if there is no active
|
||||
/// timer.
|
||||
//*******************************************
|
||||
uint32_t time_to_next() const ETL_NOEXCEPT
|
||||
{
|
||||
uint32_t delta = static_cast<uint32_t>(etl::timer::interval::No_Active_Interval);
|
||||
|
||||
lock_policy.lock();
|
||||
|
||||
if (!active_list.empty())
|
||||
{
|
||||
delta = active_list.first()->get_delta();
|
||||
}
|
||||
|
||||
lock_policy.unlock();
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Checks if a timer is currently active.
|
||||
/// Returns <b>true</b> if the timer is active, otherwise <b>false</b>.
|
||||
//*******************************************
|
||||
bool is_active(etl::timer::id::type id_) const ETL_NOEXCEPT
|
||||
{
|
||||
if (id_ != etl::timer::id::No_Timer)
|
||||
{
|
||||
lock_policy.lock();
|
||||
bool is_active = (find_timer(active_list, id_) != active_list.end());
|
||||
lock_policy.unlock();
|
||||
|
||||
return is_active;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the number of registered timers.
|
||||
//*******************************************
|
||||
size_t number_of_registered_timers() const ETL_NOEXCEPT
|
||||
{
|
||||
return timer_count;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*******************************************
|
||||
/// Stops a timer without locking.
|
||||
/// Returns the timer node if it was found, otherwise returns end().
|
||||
//*******************************************
|
||||
etl::timer_node* stop_impl(etl::timer::id::type id_) ETL_NOEXCEPT
|
||||
{
|
||||
return active_list.remove(id_);
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Finds a timer in a list by its id.
|
||||
//*******************************************
|
||||
template <typename TList>
|
||||
etl::timer_node* find_timer(TList& timer_list, etl::timer::id::type id_) const ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer_node* result = timer_list.end();
|
||||
|
||||
if (id_ != etl::timer::id::No_Timer)
|
||||
{
|
||||
timer_node* timer = timer_list.first();
|
||||
|
||||
while ((timer != timer_list.end()) && (timer->get_config().get_id() != id_))
|
||||
{
|
||||
timer = timer_list.next(timer);
|
||||
}
|
||||
|
||||
result = timer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Invokes the callbacks for all expired timers.
|
||||
//*******************************************
|
||||
void invoke_expired_timers()
|
||||
{
|
||||
etl::timer_node* timer = expired_list.first();
|
||||
|
||||
while (timer != expired_list.end())
|
||||
{
|
||||
const etl::timer_config& config = timer->get_config();
|
||||
|
||||
timer->invoke(config);
|
||||
|
||||
timer = expired_list.next(timer);
|
||||
}
|
||||
|
||||
expired_list.clear();
|
||||
}
|
||||
|
||||
intrusive_timer(const intrusive_timer&) ETL_DELETE;
|
||||
intrusive_timer& operator=(const intrusive_timer&) ETL_DELETE;
|
||||
|
||||
etl::timer_lock_policy& lock_policy;
|
||||
etl::private_timer::timer_register_list register_list;
|
||||
etl::private_timer::timer_active_list active_list;
|
||||
etl::private_timer::timer_expired_list expired_list;
|
||||
|
||||
bool enabled;
|
||||
size_t timer_count;
|
||||
};
|
||||
} // namespace etl
|
||||
|
||||
#endif
|
||||
@ -37,7 +37,7 @@ SOFTWARE.
|
||||
#include <stdint.h>
|
||||
|
||||
//*****************************************************************************
|
||||
// Definitions common to intrusive timers.
|
||||
// Definitions used by intrusive_timer.
|
||||
//*****************************************************************************
|
||||
|
||||
namespace etl
|
||||
@ -105,7 +105,7 @@ namespace etl
|
||||
etl::timer_node* current = head;
|
||||
etl::timer_node* last = end();
|
||||
|
||||
while ((current->config.id != id) && (current != end()))
|
||||
while ((current->get_id() != id) && (current != end()))
|
||||
{
|
||||
last = current;
|
||||
current = current->registered_next;
|
||||
@ -132,8 +132,7 @@ namespace etl
|
||||
// Clear the next pointer of the removed timer.
|
||||
current->registered_next = end();
|
||||
|
||||
return next;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
@ -229,10 +228,10 @@ namespace etl
|
||||
head = new_timer;
|
||||
new_timer->active_next = end();
|
||||
}
|
||||
else if (new_timer->config.delta < head->config.delta)
|
||||
else if (new_timer->delta < head->delta)
|
||||
{
|
||||
// Goes before the head.
|
||||
head->config.delta -= new_timer->config.delta;
|
||||
head->delta -= new_timer->delta;
|
||||
new_timer->active_next = head;
|
||||
head = new_timer;
|
||||
}
|
||||
@ -243,7 +242,7 @@ namespace etl
|
||||
timer_node* timer = head->active_next;
|
||||
|
||||
// Adjust the new_timer delta to take account of the head timer's delta.
|
||||
new_timer->config.delta -= previous_timer->config.delta;
|
||||
new_timer->delta -= previous_timer->delta;
|
||||
|
||||
bool inserted = false;
|
||||
|
||||
@ -251,21 +250,21 @@ namespace etl
|
||||
{
|
||||
// Find the correct place to insert.
|
||||
// The list is sorted by delta, so we need to find the first timer with a delta greater than the new timer's delta.
|
||||
if (new_timer->config.delta < timer->config.delta)
|
||||
if (new_timer->delta < timer->delta)
|
||||
{
|
||||
// Insert after the previous timer.
|
||||
previous_timer->active_next = new_timer;
|
||||
new_timer->active_next = timer;
|
||||
|
||||
// Adjust the next delta for the new timer's delta.
|
||||
timer->config.delta -= new_timer->config.delta;
|
||||
timer->delta -= new_timer->delta;
|
||||
|
||||
inserted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adjust the new_timer delta to take account of the last timer's delta.
|
||||
new_timer->config.delta -= timer->config.delta;
|
||||
new_timer->delta -= timer->delta;
|
||||
}
|
||||
|
||||
// Move to the next timer in the list.
|
||||
@ -299,7 +298,7 @@ namespace etl
|
||||
etl::timer_node* current = head;
|
||||
etl::timer_node* last = end();
|
||||
|
||||
while ((current->config.id != id) && (current != end()))
|
||||
while ((current->get_id() != id) && (current != end()))
|
||||
{
|
||||
last = current;
|
||||
current = current->active_next;
|
||||
@ -316,7 +315,7 @@ namespace etl
|
||||
// Adjust the next delta.
|
||||
if (next != end())
|
||||
{
|
||||
next->config.delta += current->config.delta;
|
||||
next->delta += current->delta;
|
||||
}
|
||||
|
||||
// Remove it from the list.
|
||||
@ -332,7 +331,7 @@ namespace etl
|
||||
// Clear the next pointer of the removed timer.
|
||||
current->active_next = end();
|
||||
|
||||
return next;
|
||||
return current;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
@ -393,14 +392,14 @@ namespace etl
|
||||
//*************************************************************************
|
||||
/// The list of timers that are registered.
|
||||
//*************************************************************************
|
||||
class timer_triggered_list
|
||||
class timer_expired_list
|
||||
{
|
||||
public:
|
||||
|
||||
//*******************************
|
||||
/// Constructor.
|
||||
//*******************************
|
||||
timer_triggered_list() ETL_NOEXCEPT
|
||||
timer_expired_list() ETL_NOEXCEPT
|
||||
: head(end())
|
||||
, tail(end())
|
||||
{
|
||||
@ -419,7 +418,7 @@ namespace etl
|
||||
//*******************************
|
||||
void insert(etl::timer_node* new_timer) ETL_NOEXCEPT
|
||||
{
|
||||
new_timer->triggered_next = end();
|
||||
new_timer->expired_next = end();
|
||||
|
||||
if (empty())
|
||||
{
|
||||
@ -427,7 +426,7 @@ namespace etl
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->triggered_next = new_timer;
|
||||
tail->expired_next = new_timer;
|
||||
}
|
||||
|
||||
tail = new_timer;
|
||||
@ -459,7 +458,7 @@ namespace etl
|
||||
{
|
||||
if (timer != end())
|
||||
{
|
||||
return timer->triggered_next;
|
||||
return timer->expired_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -485,9 +484,9 @@ namespace etl
|
||||
|
||||
while (head != end())
|
||||
{
|
||||
head = timer->triggered_next;
|
||||
timer->triggered_next = etl::timer_node::unlinked();
|
||||
timer = head;
|
||||
head = timer->expired_next;
|
||||
timer->expired_next = timer->unlinked();
|
||||
timer = head;
|
||||
}
|
||||
|
||||
tail = end();
|
||||
|
||||
@ -1,515 +0,0 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2026 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_TIMER_LISTS_INCLUDED
|
||||
#define ETL_TIMER_LISTS_INCLUDED
|
||||
|
||||
#include "../platform.h"
|
||||
#include "../nullptr.h"
|
||||
#include "../timer_node.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Definitions common to intrusive timers.
|
||||
//*****************************************************************************
|
||||
|
||||
namespace etl
|
||||
{
|
||||
namespace private_timer
|
||||
{
|
||||
//*************************************************************************
|
||||
/// The list of timers that are registered.
|
||||
/// The list does not do any checking of parameters as it is assumed that the timer service has already done this.
|
||||
//*************************************************************************
|
||||
class timer_register_list
|
||||
{
|
||||
public:
|
||||
|
||||
//*******************************
|
||||
timer_register_list() ETL_NOEXCEPT
|
||||
: head(end())
|
||||
, tail(end())
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************
|
||||
bool empty() const
|
||||
{
|
||||
return head == end();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
// Adds the timer in to the list.
|
||||
//*******************************
|
||||
void insert(etl::timer_node* new_timer) ETL_NOEXCEPT
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
head = new_timer;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->registered_next = new_timer;
|
||||
}
|
||||
|
||||
tail = new_timer;
|
||||
new_timer->registered_next = end();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
// Remove the timer from the list.
|
||||
// Returns the next timer in the list after the removed timer, or nullptr if the removed timer was the last in the list.
|
||||
//*******************************
|
||||
etl::timer_node* remove(etl::timer_node* timer) ETL_NOEXCEPT
|
||||
{
|
||||
if (timer == head)
|
||||
{
|
||||
head = timer->registered_next;
|
||||
|
||||
if (head == end())
|
||||
{
|
||||
tail = end();
|
||||
}
|
||||
|
||||
timer->registered_next = ETL_NULLPTR;
|
||||
|
||||
return head;
|
||||
}
|
||||
else
|
||||
{
|
||||
etl::timer_node* previous = head;
|
||||
|
||||
// Step through the list until we find the timer to remove, or reach the end of the list.
|
||||
while ((previous->registered_next != end()) && (previous->registered_next != timer))
|
||||
{
|
||||
previous = previous->registered_next;
|
||||
}
|
||||
|
||||
// If we found the timer, remove it from the list.
|
||||
if (previous->registered_next == timer)
|
||||
{
|
||||
previous->registered_next = timer->registered_next;
|
||||
|
||||
if (timer == tail)
|
||||
{
|
||||
tail = previous;
|
||||
}
|
||||
|
||||
timer->registered_next = end();
|
||||
|
||||
return previous->registered_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Timer not found in the list.
|
||||
return end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the first timer in the list.
|
||||
/// If the list is empty, returns end().
|
||||
//*******************************
|
||||
etl::timer_node* first() const ETL_NOEXCEPT
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the next timer in the list after the given timer.
|
||||
/// May be end() if the given timer is the last in the list.
|
||||
/// If the given timer is nullptr, returns end().
|
||||
//*******************************
|
||||
etl::timer_node* next(etl::timer_node* timer) const ETL_NOEXCEPT
|
||||
{
|
||||
if (timer != end())
|
||||
{
|
||||
return timer->registered_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the end of the list.
|
||||
/// Always returns &etl::timer_node::sentinal().
|
||||
//*******************************
|
||||
etl::timer_node* const end() const ETL_NOEXCEPT
|
||||
{
|
||||
return etl::timer_node::sentinal();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Clear the list of entries.
|
||||
//*******************************
|
||||
void clear()
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
|
||||
while (timer != end())
|
||||
{
|
||||
timer = pop_front();
|
||||
}
|
||||
|
||||
head = end();
|
||||
tail = end();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*******************************
|
||||
// Removes the timer at the front of the list.
|
||||
// Returns the new head of the list, which may be nullptr if the list is now empty.
|
||||
//*******************************
|
||||
etl::timer_node* pop_front() ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
head = timer->registered_next;
|
||||
timer->registered_next = timer->unlinked();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
etl::timer_node* head;
|
||||
etl::timer_node* tail;
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// The list of timers that are active.
|
||||
/// The list does not do any checking of parameters as it is assumed that the timer service has already done this.
|
||||
//*************************************************************************
|
||||
class timer_active_list
|
||||
{
|
||||
public:
|
||||
|
||||
//*******************************
|
||||
timer_active_list() ETL_NOEXCEPT
|
||||
: head(end())
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************
|
||||
bool empty() const ETL_NOEXCEPT
|
||||
{
|
||||
return head == end();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
// Inserts the timer at the correct delta position
|
||||
//*******************************
|
||||
void insert(etl::timer_node* new_timer) ETL_NOEXCEPT
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
// No entries yet.
|
||||
head = new_timer;
|
||||
new_timer->active_next = end();
|
||||
}
|
||||
else if (new_timer->config.delta < head->config.delta)
|
||||
{
|
||||
// Goes before the head.
|
||||
head->config.delta -= new_timer->config.delta;
|
||||
new_timer->active_next = head;
|
||||
head = new_timer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We already have entries, and new_timer doesn't go before head.
|
||||
timer_node* previous_timer = head;
|
||||
timer_node* timer = head->active_next;
|
||||
|
||||
// Adjust the new_timer delta to take account of the head timer's delta.
|
||||
new_timer->config.delta -= previous_timer->config.delta;
|
||||
|
||||
bool inserted = false;
|
||||
|
||||
while (!inserted && (timer != end()))
|
||||
{
|
||||
// Find the correct place to insert.
|
||||
// The list is sorted by delta, so we need to find the first timer with a delta greater than the new timer's delta.
|
||||
if (new_timer->config.delta < timer->config.delta)
|
||||
{
|
||||
// Insert after the previous timer.
|
||||
previous_timer->active_next = new_timer;
|
||||
new_timer->active_next = timer;
|
||||
|
||||
// Adjust the next delta for the new timer's delta.
|
||||
timer->config.delta -= new_timer->config.delta;
|
||||
|
||||
inserted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adjust the new_timer delta to take account of the last timer's delta.
|
||||
new_timer->config.delta -= timer->config.delta;
|
||||
}
|
||||
|
||||
// Move to the next timer in the list.
|
||||
previous_timer = timer;
|
||||
timer = timer->active_next;
|
||||
}
|
||||
|
||||
if (!inserted)
|
||||
{
|
||||
// Reached the end so attach to the tail.
|
||||
previous_timer->active_next = new_timer;
|
||||
new_timer->active_next = end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Removes the selected timer from the list.
|
||||
/// No action is taken if the timer is not found.
|
||||
/// returns the next timer in the list after the removed timer, or end() if the removed timer was the last in the list.
|
||||
/// The list does not do any checking of parameters as it is assumed that the timer service has already done this.
|
||||
//*******************************
|
||||
etl::timer_node* remove(etl::timer_node* timer) ETL_NOEXCEPT
|
||||
{
|
||||
// Find the timer in the list.
|
||||
etl::timer_node* current = head;
|
||||
etl::timer_node* last = end();
|
||||
|
||||
while (current != timer && current != end())
|
||||
{
|
||||
last = current;
|
||||
current = current->active_next;
|
||||
}
|
||||
|
||||
// Not found?
|
||||
if (current == end())
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
etl::timer_node* next = current->active_next;
|
||||
|
||||
// Adjust the next delta.
|
||||
if (next != end())
|
||||
{
|
||||
next->config.delta += current->config.delta;
|
||||
}
|
||||
|
||||
// Remove it from the list.
|
||||
if (last == end())
|
||||
{
|
||||
head = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
last->active_next = next;
|
||||
}
|
||||
|
||||
// Clear the next pointer of the removed timer.
|
||||
current->active_next = ETL_NULLPTR;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the first timer in the list.
|
||||
/// If the list is empty, returns end().
|
||||
//*******************************
|
||||
etl::timer_node* first() const ETL_NOEXCEPT
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the next timer in the list after the given timer.
|
||||
/// May be end() if the given timer is the last in the list.
|
||||
/// If the given timer is nullptr, returns end().
|
||||
//*******************************
|
||||
etl::timer_node* next(etl::timer_node* timer) const ETL_NOEXCEPT
|
||||
{
|
||||
if (timer != end())
|
||||
{
|
||||
return timer->active_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the end of the list.
|
||||
/// Always returns &etl::timer_node::sentinal().
|
||||
//*******************************
|
||||
etl::timer_node* const end() const ETL_NOEXCEPT
|
||||
{
|
||||
return etl::timer_node::sentinal();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Clear the list of entries.
|
||||
//*******************************
|
||||
void clear()
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
|
||||
while (timer != end())
|
||||
{
|
||||
timer = pop_front();
|
||||
}
|
||||
|
||||
head = end();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*******************************
|
||||
// Removes the timer at the front of the list.
|
||||
// Returns the new head of the list, which may be nullptr if the list is now empty.
|
||||
//*******************************
|
||||
etl::timer_node* pop_front() ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
head = timer->active_next;
|
||||
timer->active_next = timer->unlinked();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
etl::timer_node* head;
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// The list of timers that are registered.
|
||||
//*************************************************************************
|
||||
class timer_triggered_list
|
||||
{
|
||||
public:
|
||||
|
||||
//*******************************
|
||||
timer_triggered_list() ETL_NOEXCEPT
|
||||
: head(end())
|
||||
, tail(end())
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************
|
||||
bool empty() const
|
||||
{
|
||||
return head == end();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
// Adds the timer in to the list.
|
||||
//*******************************
|
||||
void insert(etl::timer_node* new_timer) ETL_NOEXCEPT
|
||||
{
|
||||
new_timer->triggered_next = end();
|
||||
|
||||
if (empty())
|
||||
{
|
||||
head = new_timer;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->triggered_next = new_timer;
|
||||
}
|
||||
|
||||
tail = new_timer;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the first timer in the list.
|
||||
/// If the list is empty, returns nullptr.
|
||||
//*******************************
|
||||
etl::timer_node* first() const ETL_NOEXCEPT
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the next timer in the list after the given timer.
|
||||
/// May be end() if the given timer is the last in the list.
|
||||
/// If the given timer is nullptr, returns end().
|
||||
//*******************************
|
||||
etl::timer_node* next(etl::timer_node* timer) const ETL_NOEXCEPT
|
||||
{
|
||||
if (timer != end())
|
||||
{
|
||||
return timer->triggered_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Returns the end of the list.
|
||||
/// Always returns &etl::timer_node::sentinal().
|
||||
//*******************************
|
||||
etl::timer_node* const end() const ETL_NOEXCEPT
|
||||
{
|
||||
return etl::timer_node::sentinal();
|
||||
}
|
||||
|
||||
//*******************************
|
||||
/// Clear the list of entries.
|
||||
//*******************************
|
||||
void clear()
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
|
||||
while (timer != end())
|
||||
{
|
||||
timer = pop_front();
|
||||
}
|
||||
|
||||
head = end();
|
||||
tail = end();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*******************************
|
||||
// Removes the timer at the front of the list.
|
||||
// Returns the new head of the list, which may be nullptr if the list is now empty.
|
||||
//*******************************
|
||||
etl::timer_node* pop_front() ETL_NOEXCEPT
|
||||
{
|
||||
etl::timer_node* timer = head;
|
||||
head = timer->triggered_next;
|
||||
timer->triggered_next = timer->unlinked();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
etl::timer_node* head;
|
||||
etl::timer_node* tail;
|
||||
};
|
||||
} // namespace private_timer
|
||||
} // namespace etl
|
||||
|
||||
#endif
|
||||
@ -46,11 +46,12 @@ namespace etl
|
||||
{
|
||||
class timer_register_list;
|
||||
class timer_active_list;
|
||||
class timer_triggered_list;
|
||||
|
||||
class intrusive_callback_timer;
|
||||
class timer_expired_list;
|
||||
} // namespace private_timer
|
||||
|
||||
class timer_node;
|
||||
class intrusive_timer;
|
||||
|
||||
//***************************************************************************
|
||||
/// A timer configuration data structure.
|
||||
//***************************************************************************
|
||||
@ -60,16 +61,16 @@ namespace etl
|
||||
|
||||
friend class private_timer::timer_register_list;
|
||||
friend class private_timer::timer_active_list;
|
||||
friend class private_timer::timer_triggered_list;
|
||||
friend class private_timer::timer_expired_list;
|
||||
|
||||
friend class intrusive_callback_timer;
|
||||
friend class timer_node;
|
||||
friend class intrusive_timer;
|
||||
|
||||
//*******************************************
|
||||
/// Constructor.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR timer_config(etl::timer::id::type id_, uint32_t period_, etl::timer::mode::type repeating_) ETL_NOEXCEPT
|
||||
: period(period_)
|
||||
, delta(period_)
|
||||
, mode(repeating_)
|
||||
, id(id_)
|
||||
{
|
||||
@ -83,14 +84,6 @@ namespace etl
|
||||
return period;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the time remaining until the timer expires.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR uint32_t get_delta() const ETL_NOEXCEPT
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the mode of the timer.
|
||||
//*******************************************
|
||||
@ -113,7 +106,6 @@ namespace etl
|
||||
ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT
|
||||
{
|
||||
period = etl::timer::state::Inactive;
|
||||
delta = etl::timer::state::Inactive;
|
||||
mode = etl::timer::mode::Repeating;
|
||||
id = etl::timer::id::No_Timer;
|
||||
}
|
||||
@ -121,7 +113,6 @@ namespace etl
|
||||
private:
|
||||
|
||||
uint32_t period; ///< The period of the timer.
|
||||
uint32_t delta; ///< The time remaining until the timer expires.
|
||||
etl::timer::mode::type mode; ///< Whether the timer is repeating or single-shot.
|
||||
etl::timer::id::type id; ///< The id of the timer.
|
||||
};
|
||||
@ -138,9 +129,9 @@ namespace etl
|
||||
|
||||
friend class private_timer::timer_register_list;
|
||||
friend class private_timer::timer_active_list;
|
||||
friend class private_timer::timer_triggered_list;
|
||||
friend class private_timer::timer_expired_list;
|
||||
|
||||
friend class intrusive_callback_timer;
|
||||
friend class intrusive_timer;
|
||||
|
||||
//*******************************************
|
||||
/// Constructor.
|
||||
@ -148,8 +139,9 @@ namespace etl
|
||||
timer_node(const timer_config& config_) ETL_NOEXCEPT
|
||||
: registered_next(unlinked())
|
||||
, active_next(unlinked())
|
||||
, triggered_next(unlinked())
|
||||
, expired_next(unlinked())
|
||||
, config(config_)
|
||||
, delta(config_.get_period())
|
||||
{
|
||||
}
|
||||
|
||||
@ -159,8 +151,9 @@ namespace etl
|
||||
timer_node(const timer_node& node_) ETL_NOEXCEPT
|
||||
: registered_next(unlinked())
|
||||
, active_next(unlinked())
|
||||
, triggered_next(unlinked())
|
||||
, expired_next(unlinked())
|
||||
, config(node_.config)
|
||||
, delta(node_.config.get_period())
|
||||
{
|
||||
}
|
||||
|
||||
@ -172,8 +165,56 @@ namespace etl
|
||||
return config;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the delta of the timer.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR uint32_t get_delta() const ETL_NOEXCEPT
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the period of the timer.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR uint32_t get_period() const ETL_NOEXCEPT
|
||||
{
|
||||
return config.get_period();
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the mode of the timer.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR uint32_t get_mode() const ETL_NOEXCEPT
|
||||
{
|
||||
return config.get_mode();
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns the id of the timer.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR etl::timer::id::type get_id() const ETL_NOEXCEPT
|
||||
{
|
||||
return config.get_id();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*******************************************
|
||||
/// Sets the period of the timer.
|
||||
//*******************************************
|
||||
void set_period(uint32_t period_) ETL_NOEXCEPT
|
||||
{
|
||||
config.period = period_;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Sets the mode of the timer.
|
||||
//*******************************************
|
||||
void set_mode(etl::timer::mode::type mode_) ETL_NOEXCEPT
|
||||
{
|
||||
config.mode = mode_;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Returns a nullptr to indicate that the timer is not linked into any list.
|
||||
//*******************************************
|
||||
@ -204,24 +245,25 @@ namespace etl
|
||||
{
|
||||
registered_next = unlinked();
|
||||
active_next = unlinked();
|
||||
triggered_next = unlinked();
|
||||
expired_next = unlinked();
|
||||
delta = config.get_period();
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Invokes the timer's callback.
|
||||
//*******************************************
|
||||
virtual void invoke()
|
||||
virtual void invoke(const etl::timer_config& /*config*/)
|
||||
{
|
||||
// Default implementation does nothing.
|
||||
}
|
||||
|
||||
timer_node& operator=(const timer_node&) ETL_DELETE;
|
||||
|
||||
timer_node* registered_next; ///< The next timer in the registered timer list. nullptr if the timer is not registered.
|
||||
timer_node* active_next; ///< The next timer in the active timer list. nullptr if the timer is not active.
|
||||
timer_node* triggered_next; ///< The next timer in the triggered timer list. nullptr if the timer is not triggered.
|
||||
|
||||
timer_config config; ///< The configuration of the timer.
|
||||
timer_node* registered_next; ///< The next timer in the registered timer list. nullptr if the timer is not registered.
|
||||
timer_node* active_next; ///< The next timer in the active timer list. nullptr if the timer is not active.
|
||||
timer_node* expired_next; ///< The next timer in the expired timer list. nullptr if the timer is not expired.
|
||||
timer_config config; ///< The configuration of the timer.
|
||||
uint32_t delta; ///< The time remaining until the timer expires.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
@ -242,9 +284,9 @@ namespace etl
|
||||
//*******************************************
|
||||
/// Invokes the timer's callback.
|
||||
//*******************************************
|
||||
virtual void invoke() ETL_OVERRIDE
|
||||
virtual void invoke(const etl::timer_config& config) ETL_OVERRIDE
|
||||
{
|
||||
callback();
|
||||
callback(config);
|
||||
}
|
||||
|
||||
TCallback callback; ///< The callback delegate for the timer.
|
||||
@ -259,18 +301,21 @@ namespace etl
|
||||
//*******************************************
|
||||
/// Constructor.
|
||||
//*******************************************
|
||||
message_timer_node(etl::imessage_router& router_, TMessage message) ETL_NOEXCEPT
|
||||
message_timer_node(etl::imessage_router& router_, TMessage message_) ETL_NOEXCEPT
|
||||
: timer_node()
|
||||
, router(&router_)
|
||||
, message(message_)
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Invokes the timer's callback.
|
||||
//*******************************************
|
||||
virtual void invoke() ETL_OVERRIDE
|
||||
virtual void invoke(const etl::timer_config& config) ETL_OVERRIDE
|
||||
{
|
||||
callback();
|
||||
message.set_timer_config(config);
|
||||
|
||||
router->receive(message);
|
||||
}
|
||||
|
||||
etl::imessage_router* router; ///< The message router to send the message to.
|
||||
|
||||
1038
test/test_intrusive_timer.cpp
Normal file
1038
test/test_intrusive_timer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -176,11 +176,11 @@ namespace
|
||||
timer = active_list.next(timer);
|
||||
CHECK_EQUAL(active_list.end(), timer);
|
||||
|
||||
CHECK_EQUAL(timer2.get_config().get_period(), timer2.get_config().get_delta());
|
||||
CHECK_EQUAL(timer3.get_config().get_period() - timer2.get_config().get_period(), timer3.get_config().get_delta());
|
||||
CHECK_EQUAL(timer1.get_config().get_period() - timer3.get_config().get_period(), timer1.get_config().get_delta());
|
||||
CHECK_EQUAL(timer4.get_config().get_period() - timer1.get_config().get_period(), timer4.get_config().get_delta());
|
||||
CHECK_EQUAL(timer5.get_config().get_period() - timer3.get_config().get_period(), timer5.get_config().get_delta());
|
||||
CHECK_EQUAL(timer2.get_config().get_period(), timer2.get_delta());
|
||||
CHECK_EQUAL(timer3.get_config().get_period() - timer2.get_config().get_period(), timer3.get_delta());
|
||||
CHECK_EQUAL(timer1.get_config().get_period() - timer3.get_config().get_period(), timer1.get_delta());
|
||||
CHECK_EQUAL(timer4.get_config().get_period() - timer1.get_config().get_period(), timer4.get_delta());
|
||||
CHECK_EQUAL(timer5.get_config().get_period() - timer3.get_config().get_period(), timer5.get_delta());
|
||||
// Remove timer3 from the list.
|
||||
active_list.remove(timer3.get_config().get_id());
|
||||
|
||||
@ -226,10 +226,10 @@ namespace
|
||||
CHECK_TRUE(timer5_found);
|
||||
|
||||
// Check the deltas are still correct.
|
||||
CHECK_EQUAL(timer2.get_config().get_period(), timer2.get_config().get_delta());
|
||||
CHECK_EQUAL(timer1.get_config().get_period() - timer3.get_config().get_period(), timer1.get_config().get_delta());
|
||||
CHECK_EQUAL(timer4.get_config().get_period() - timer1.get_config().get_period(), timer4.get_config().get_delta());
|
||||
CHECK_EQUAL(timer5.get_config().get_period() - timer2.get_config().get_period(), timer5.get_config().get_delta());
|
||||
CHECK_EQUAL(timer2.get_config().get_period(), timer2.get_delta());
|
||||
CHECK_EQUAL(timer1.get_config().get_period() - timer3.get_config().get_period(), timer1.get_delta());
|
||||
CHECK_EQUAL(timer4.get_config().get_period() - timer1.get_config().get_period(), timer4.get_delta());
|
||||
CHECK_EQUAL(timer5.get_config().get_period() - timer2.get_config().get_period(), timer5.get_delta());
|
||||
|
||||
// Remove a timer that is not in the list.
|
||||
active_list.remove(timer6.get_config().get_id());
|
||||
@ -270,10 +270,10 @@ namespace
|
||||
}
|
||||
|
||||
// Check the deltas are still correct.
|
||||
CHECK_EQUAL(timer2.get_config().get_period(), timer2.get_config().get_delta());
|
||||
CHECK_EQUAL(timer1.get_config().get_period() - timer3.get_config().get_period(), timer1.get_config().get_delta());
|
||||
CHECK_EQUAL(timer4.get_config().get_period() - timer1.get_config().get_period(), timer4.get_config().get_delta());
|
||||
CHECK_EQUAL(timer5.get_config().get_period() - timer2.get_config().get_period(), timer5.get_config().get_delta());
|
||||
CHECK_EQUAL(timer2.get_period(), timer2.get_delta());
|
||||
CHECK_EQUAL(timer1.get_period() - timer3.get_period(), timer1.get_delta());
|
||||
CHECK_EQUAL(timer4.get_period() - timer1.get_period(), timer4.get_delta());
|
||||
CHECK_EQUAL(timer5.get_period() - timer2.get_period(), timer5.get_delta());
|
||||
|
||||
// Clear the list.
|
||||
active_list.clear();
|
||||
@ -283,7 +283,7 @@ namespace
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_timer_triggered_list)
|
||||
TEST(test_timer_expired_list)
|
||||
{
|
||||
constexpr etl::timer_config timer1_config(1, 100, etl::timer::mode::Repeating);
|
||||
constexpr etl::timer_config timer2_config(2, 65, etl::timer::mode::Repeating);
|
||||
@ -297,41 +297,41 @@ namespace
|
||||
etl::timer_node timer4{timer4_config};
|
||||
etl::timer_node timer5{timer5_config};
|
||||
|
||||
etl::private_timer::timer_triggered_list triggered_list;
|
||||
etl::private_timer::timer_expired_list expired_list;
|
||||
|
||||
CHECK_TRUE(triggered_list.empty());
|
||||
CHECK_TRUE(triggered_list.first() == triggered_list.end());
|
||||
CHECK_TRUE(expired_list.empty());
|
||||
CHECK_TRUE(expired_list.first() == expired_list.end());
|
||||
|
||||
// Add the timers to the list.
|
||||
triggered_list.insert(&timer1);
|
||||
triggered_list.insert(&timer2);
|
||||
triggered_list.insert(&timer3);
|
||||
triggered_list.insert(&timer4);
|
||||
triggered_list.insert(&timer5);
|
||||
expired_list.insert(&timer1);
|
||||
expired_list.insert(&timer2);
|
||||
expired_list.insert(&timer3);
|
||||
expired_list.insert(&timer4);
|
||||
expired_list.insert(&timer5);
|
||||
|
||||
CHECK_FALSE(triggered_list.empty());
|
||||
CHECK_TRUE(triggered_list.first() == &timer1);
|
||||
CHECK_FALSE(expired_list.empty());
|
||||
CHECK_TRUE(expired_list.first() == &timer1);
|
||||
|
||||
// The timers should be in the order they were added.
|
||||
etl::timer_node* timer = triggered_list.first();
|
||||
etl::timer_node* timer = expired_list.first();
|
||||
|
||||
CHECK_EQUAL(&timer1, timer);
|
||||
timer = triggered_list.next(timer);
|
||||
timer = expired_list.next(timer);
|
||||
CHECK_EQUAL(&timer2, timer);
|
||||
timer = triggered_list.next(timer);
|
||||
timer = expired_list.next(timer);
|
||||
CHECK_EQUAL(&timer3, timer);
|
||||
timer = triggered_list.next(timer);
|
||||
timer = expired_list.next(timer);
|
||||
CHECK_EQUAL(&timer4, timer);
|
||||
timer = triggered_list.next(timer);
|
||||
timer = expired_list.next(timer);
|
||||
CHECK_EQUAL(&timer5, timer);
|
||||
timer = triggered_list.next(timer);
|
||||
CHECK_EQUAL(triggered_list.end(), timer);
|
||||
timer = expired_list.next(timer);
|
||||
CHECK_EQUAL(expired_list.end(), timer);
|
||||
|
||||
// Clear the list.
|
||||
triggered_list.clear();
|
||||
expired_list.clear();
|
||||
|
||||
CHECK_TRUE(triggered_list.empty());
|
||||
CHECK_TRUE(triggered_list.first() == triggered_list.end());
|
||||
CHECK_TRUE(expired_list.empty());
|
||||
CHECK_TRUE(expired_list.first() == expired_list.end());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -39,27 +39,22 @@ namespace
|
||||
{
|
||||
constexpr etl::timer_config config1(1, 100U, etl::timer::mode::Repeating);
|
||||
CHECK_EQUAL(100U, config1.get_period());
|
||||
CHECK_EQUAL(100U, config1.get_delta());
|
||||
CHECK_EQUAL(etl::timer::mode::Repeating, config1.get_mode());
|
||||
|
||||
etl::timer_config config2(2, 200U, etl::timer::mode::Single_Shot);
|
||||
CHECK_EQUAL(200U, config2.get_period());
|
||||
CHECK_EQUAL(200U, config2.get_delta());
|
||||
CHECK_EQUAL(etl::timer::mode::Single_Shot, config2.get_mode());
|
||||
|
||||
etl::timer_config config3(config2);
|
||||
CHECK_EQUAL(config2.get_period(), config3.get_period());
|
||||
CHECK_EQUAL(config2.get_delta(), config3.get_delta());
|
||||
CHECK_EQUAL(etl::timer::mode::Single_Shot, config2.get_mode());
|
||||
|
||||
etl::timer_config config4 = etl::timer_config(4, 500U, etl::timer::mode::Repeating);
|
||||
CHECK_EQUAL(500U, config4.get_period());
|
||||
CHECK_EQUAL(500U, config4.get_delta());
|
||||
CHECK_EQUAL(etl::timer::mode::Repeating, config4.get_mode());
|
||||
|
||||
config2.clear();
|
||||
CHECK_EQUAL(etl::timer::state::Inactive, config2.get_period());
|
||||
CHECK_EQUAL(etl::timer::state::Inactive, config2.get_delta());
|
||||
CHECK_EQUAL(etl::timer::mode::Repeating, config2.get_mode());
|
||||
}
|
||||
|
||||
@ -74,11 +69,9 @@ namespace
|
||||
const etl::timer_config& config1_ref = node1.get_config();
|
||||
|
||||
CHECK_EQUAL(config1.get_period(), node1.get_config().get_period());
|
||||
CHECK_EQUAL(config1.get_delta(), node1.get_config().get_delta());
|
||||
CHECK_EQUAL(config1.get_mode(), node1.get_config().get_mode());
|
||||
|
||||
CHECK_EQUAL(node1.get_config().get_period(), node2.get_config().get_period());
|
||||
CHECK_EQUAL(node1.get_config().get_delta(), node2.get_config().get_delta());
|
||||
CHECK_EQUAL(node1.get_config().get_mode(), node2.get_config().get_mode());
|
||||
}
|
||||
}
|
||||
|
||||
@ -3559,6 +3559,7 @@
|
||||
<ClInclude Include="..\..\include\etl\generators\variant_pool_cpp03_generator.h" />
|
||||
<ClInclude Include="..\..\include\etl\index_of_type.h" />
|
||||
<ClInclude Include="..\..\include\etl\inplace_function.h" />
|
||||
<ClInclude Include="..\..\include\etl\intrusive_timer.h" />
|
||||
<ClInclude Include="..\..\include\etl\private\timer_lists.h" />
|
||||
<ClInclude Include="..\..\include\etl\timer_node.h" />
|
||||
<ClInclude Include="..\..\include\etl\invoke.h" />
|
||||
@ -10403,6 +10404,7 @@
|
||||
<ClCompile Include="..\test_index_of_type.cpp" />
|
||||
<ClCompile Include="..\test_inplace_function.cpp" />
|
||||
<ClCompile Include="..\test_intrusive_links.cpp" />
|
||||
<ClCompile Include="..\test_intrusive_timer.cpp" />
|
||||
<ClCompile Include="..\test_invoke.cpp" />
|
||||
<ClCompile Include="..\test_is_invocable.cpp" />
|
||||
<ClCompile Include="..\test_macros.cpp" />
|
||||
|
||||
@ -1575,6 +1575,9 @@
|
||||
<ClInclude Include="..\..\include\etl\private\timer_lists.h">
|
||||
<Filter>ETL\Private</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\intrusive_timer.h">
|
||||
<Filter>ETL\Frameworks</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\test_string_char.cpp">
|
||||
@ -3851,6 +3854,9 @@
|
||||
<ClCompile Include="..\test_timer_lists.cpp">
|
||||
<Filter>Tests\Callback Timers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_intrusive_timer.cpp">
|
||||
<Filter>Tests\Callback Timers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\library.properties">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user