124 lines
2.7 KiB
C++
124 lines
2.7 KiB
C++
//
|
|
// Created by erki on 24/10/23.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <tuple>
|
|
#include <utility_function.hpp>
|
|
#include <utility_ringbuffer.hpp>
|
|
|
|
#include "cpptick/argstore.hpp"
|
|
#include "cpptick/timer.hpp"
|
|
|
|
namespace cpptick
|
|
{
|
|
|
|
struct BaseScheduler
|
|
{
|
|
using StoredCall = std::pair<Utility::IFunction<void(ArgStorage&)>*, ArgStorage>;
|
|
Utility::Ringbuffer<StoredCall, 12> stored_calls;
|
|
|
|
using StoredTimer = std::pair<std::uint32_t, Timer*>;
|
|
std::array<StoredTimer, 12> stored_timers;
|
|
|
|
BaseScheduler()
|
|
{
|
|
stored_timers.fill({-1u, nullptr});
|
|
}
|
|
|
|
virtual ~BaseScheduler() = default;
|
|
|
|
void tick()
|
|
{
|
|
if (auto start = stored_timers.begin();
|
|
start->first != -1u)
|
|
{
|
|
checkInvokeTimers();
|
|
}
|
|
|
|
if (!stored_calls.empty())
|
|
{
|
|
auto* f = stored_calls.begin()->first;
|
|
auto& args = stored_calls.begin()->second;
|
|
(*f)(args);
|
|
stored_calls.pop_front();
|
|
}
|
|
}
|
|
|
|
ArgStorage& storeCall(Utility::IFunction<void(ArgStorage&)>* call)
|
|
{
|
|
// @todo: handle overflow...
|
|
|
|
// still constructs double.
|
|
stored_calls.emplace_back(call, ArgStorage{});
|
|
auto& storage = stored_calls.back().second;
|
|
storage.reset();
|
|
return storage;
|
|
}
|
|
|
|
virtual void storeTimer(Timer* timer) = 0;
|
|
virtual void checkInvokeTimers() = 0;
|
|
};
|
|
|
|
template<typename HAL>
|
|
struct Scheduler : BaseScheduler
|
|
{
|
|
Scheduler() = default;
|
|
|
|
void storeTimer(Timer* timer) override
|
|
{
|
|
const std::uint32_t current_time = HAL::getMillis();
|
|
const std::uint32_t time_to_run = timer->expirationTime(current_time);
|
|
|
|
auto empty_slot = std::find_if(stored_timers.begin(), stored_timers.end(),
|
|
[](const StoredTimer& timer) -> bool {
|
|
return timer.first == -1u;
|
|
});
|
|
|
|
if (empty_slot == stored_timers.end())
|
|
return;
|
|
|
|
*empty_slot = {time_to_run, timer};
|
|
std::sort(stored_timers.begin(), stored_timers.end());
|
|
}
|
|
|
|
void checkInvokeTimers() override
|
|
{
|
|
const std::uint32_t current_time = HAL::getMillis();
|
|
|
|
bool timers_executed = false;
|
|
for (auto timer = stored_timers.begin(); timer->first != -1u; timer++)
|
|
{
|
|
if (timer->first <= current_time)
|
|
{
|
|
timers_executed = true;
|
|
storeCall(timer->second->getSlot());
|
|
|
|
if (timer->second->type == Timer::ONE_SHOT)
|
|
{
|
|
timer->first = -1u;
|
|
timer->second = nullptr;
|
|
}
|
|
else
|
|
{
|
|
timer->first = timer->second->expirationTime(current_time);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (timers_executed)
|
|
{
|
|
std::sort(stored_timers.begin(), stored_timers.end());
|
|
}
|
|
}
|
|
};
|
|
|
|
}// namespace cpptick
|