2023-10-25 11:36:20 +03:00

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