// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md #include #include #include #include #include #include #if DEBUG_TIMER == 1 #define log_debug(...) LOG_DEBUG(__VA_ARGS__) #else #define log_debug(...) #endif namespace sys::timer { SystemTimer::SystemTimer(Service *parent, const std::string &name, std::chrono::milliseconds interval, Type type) : cpp_freertos::Timer(name.c_str(), cpp_freertos::Ticks::MsToTicks(interval.count()), type == Type::Periodic), name{name}, interval{interval}, type{type}, parent{parent} { attachToService(); log_debug("%s %s timer created", name.c_str(), type == Type::Periodic ? "periodic" : "single-shot"); } void SystemTimer::attachToService() { assert(parent != nullptr); parent->getTimers().attach(this); } SystemTimer::~SystemTimer() noexcept { parent->getTimers().detach(this); } void SystemTimer::Run() { auto msg = std::make_shared(this); if (const auto ret = parent->bus.sendUnicast(std::move(msg), parent->GetName()); !ret) { LOG_ERROR("Timer %s error: bus error", name.c_str()); } } void SystemTimer::start() { log_debug("Timer %s start", name.c_str()); stopTimerIfActive(); startTimer(); } void SystemTimer::restart(std::chrono::milliseconds newInterval) { log_debug("Timer %s restart", name.c_str()); stopTimerIfActive(); setInterval(newInterval); startTimer(); } void SystemTimer::stopTimerIfActive() { if (active) { cpp_freertos::Timer::Stop(0); } } void SystemTimer::startTimer() { active = true; cpp_freertos::Timer::Start(0); } void SystemTimer::stop() { log_debug("Timer %s stop!", name.c_str()); // make sure callback is not called even if it is already in the queue active = false; cpp_freertos::Timer::Stop(0); } void SystemTimer::setInterval(std::chrono::milliseconds value) { log_debug("Timer %s set interval to %" PRIi64 " ms!", name.c_str(), value.count()); interval = value; cpp_freertos::Timer::SetPeriod(cpp_freertos::Ticks::MsToTicks(interval.count()), 0); } void SystemTimer::onTimeout() { log_debug("Timer %s tick", name.c_str()); if (!callback) { LOG_WARN("Timer %s error: Callback is not valid.", name.c_str()); return; } if (!isActive()) { LOG_WARN("Timer %s error: Timer is not active.", name.c_str()); return; } log_debug("Timer %s runs callback", name.c_str()); if (type == Type::SingleShot) { stop(); } callback(*this); } bool SystemTimer::isActive() const noexcept { return active; } void SystemTimer::connect(TimerCallback &&newCallback) noexcept { callback = std::move(newCallback); } } // namespace sys::timer