// // Created by erki on 24/10/23. // #pragma once #include #include #include #include #include #include "cpptick/argstore.hpp" #include "cpptick/timer.hpp" namespace cpptick { struct BaseScheduler { using StoredCall = std::pair*, ArgStorage>; Utility::Ringbuffer stored_calls; using StoredTimer = std::pair; std::array 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* 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 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