From 78cf00315d5bb9a05d47976a564d16c5978f1f41 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 3 Mar 2023 14:30:35 +0100 Subject: [PATCH] use sys clock for Countdown --- src/fsfw/fdir/FaultCounter.cpp | 2 +- src/fsfw/ipc/MutexGuard.h | 8 ++--- src/fsfw/osal/linux/Clock.cpp | 9 ++++-- src/fsfw/thermal/Heater.cpp | 2 +- src/fsfw/timemanager/Countdown.cpp | 51 +++++++++++++++++++----------- src/fsfw/timemanager/Countdown.h | 29 +++++++++++++---- 6 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/fsfw/fdir/FaultCounter.cpp b/src/fsfw/fdir/FaultCounter.cpp index eea08817..9ef359aa 100644 --- a/src/fsfw/fdir/FaultCounter.cpp +++ b/src/fsfw/fdir/FaultCounter.cpp @@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId, parameterWrapper->set(faultCount); break; case ParameterIds::TIMEOUT: - parameterWrapper->set(timer.timeout); + parameterWrapper->set(timer.getTimeoutMs()); break; default: return INVALID_IDENTIFIER_ID; diff --git a/src/fsfw/ipc/MutexGuard.h b/src/fsfw/ipc/MutexGuard.h index b82b2d7f..9887f396 100644 --- a/src/fsfw/ipc/MutexGuard.h +++ b/src/fsfw/ipc/MutexGuard.h @@ -26,11 +26,11 @@ class MutexGuard { #if FSFW_VERBOSE_LEVEL >= 1 if (result == MutexIF::MUTEX_TIMEOUT) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs - << " milliseconds!" << std::endl; + sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of " + << timeoutMs << " milliseconds!" << std::endl; #else - sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n", - timeoutMs); + sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n", + context, timeoutMs); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ } else if (result != returnvalue::OK) { diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index bfdcf4e2..47099fb2 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -79,11 +79,16 @@ ReturnValue_t Clock::getUptime(timeval* uptime) { // TODO This is not posix compatible and delivers only seconds precision // Linux specific file read but more precise. double uptimeSeconds; - if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) { + std::ifstream ifile("/proc/uptime"); + if (ifile.bad()) { + return returnvalue::FAILED; + } + if (ifile >> uptimeSeconds) { uptime->tv_sec = uptimeSeconds; uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6); + return returnvalue::OK; } - return returnvalue::OK; + return returnvalue::FAILED; } // Wait for new FSFW Clock function delivering seconds uptime. diff --git a/src/fsfw/thermal/Heater.cpp b/src/fsfw/thermal/Heater.cpp index 04abadc7..da78a74a 100644 --- a/src/fsfw/thermal/Heater.cpp +++ b/src/fsfw/thermal/Heater.cpp @@ -283,7 +283,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId, } switch (uniqueId) { case 0: - parameterWrapper->set(heaterOnCountdown.timeout); + parameterWrapper->set(heaterOnCountdown.getTimeoutMs()); break; default: return INVALID_IDENTIFIER_ID; diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp index 334883ae..662fc8f0 100644 --- a/src/fsfw/timemanager/Countdown.cpp +++ b/src/fsfw/timemanager/Countdown.cpp @@ -1,49 +1,62 @@ #include "fsfw/timemanager/Countdown.h" -Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) { +#include "fsfw/globalfunctions/timevalOperations.h" + +Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) { if (startImmediately) { setTimeout(initialTimeout); } else { - timeout = initialTimeout; + timeout.tv_sec = initialTimeout / 1000; + timeout.tv_usec = (initialTimeout % 1000) * 1000; } } -Countdown::~Countdown() {} +Countdown::~Countdown() = default; ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { - ReturnValue_t returnValue = Clock::getUptime(&startTime); - timeout = milliseconds; - return returnValue; + timeout.tv_sec = milliseconds / 1000; + timeout.tv_usec = (milliseconds % 1000) * 1000; + return Clock::getClock_timeval(&startTime); } bool Countdown::hasTimedOut() const { - if (uint32_t(this->getCurrentTime() - startTime) >= timeout) { + // Account for system clock going back in time. + if (getCurrentTime() < startTime) { return true; - } else { - return false; } + if (getCurrentTime() - startTime >= timeout) { + return true; + } + return false; } bool Countdown::isBusy() const { return !hasTimedOut(); } -ReturnValue_t Countdown::resetTimer() { return setTimeout(timeout); } +ReturnValue_t Countdown::resetTimer() { return setTimeoutTv(timeout); } void Countdown::timeOut() { startTime = this->getCurrentTime() - timeout; } uint32_t Countdown::getRemainingMillis() const { - // We fetch the time before the if-statement - // to be sure that the return is in - // range 0 <= number <= timeout - uint32_t currentTime = this->getCurrentTime(); if (this->hasTimedOut()) { return 0; - } else { - return (startTime + timeout) - currentTime; } + timeval remainingMillisTv = (startTime + timeout) - this->getCurrentTime(); + return remainingMillisTv.tv_sec * 1000 + remainingMillisTv.tv_usec / 1000; } -uint32_t Countdown::getCurrentTime() const { - uint32_t currentTime; - Clock::getUptime(¤tTime); +uint32_t Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_usec / 1000; } + +ReturnValue_t Countdown::setTimeoutTv(timeval tv) { + timeout = tv; + return Clock::getClock_timeval(&startTime); +} + +uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; } + +timeval Countdown::getTimeout() const { return timeout; } + +timeval Countdown::getCurrentTime() const { + timeval currentTime{}; + Clock::getClock_timeval(¤tTime); return currentTime; } diff --git a/src/fsfw/timemanager/Countdown.h b/src/fsfw/timemanager/Countdown.h index 26534789..44a1d4ad 100644 --- a/src/fsfw/timemanager/Countdown.h +++ b/src/fsfw/timemanager/Countdown.h @@ -6,6 +6,10 @@ /** * * Countdown keeps track of a timespan. + * This class uses the system clock internally to achieve + * a high resolution. This means that the API is only partially + * resistant against time jumps. The user must take care to account + * for time jumps in some from if this relevant. * * Countdown::resetTimer restarts the timer. * Countdown::setTimeout sets a new countdown duration and resets. @@ -39,6 +43,8 @@ class Countdown { * @return Returnvalue from Clock::getUptime */ ReturnValue_t setTimeout(uint32_t milliseconds); + ReturnValue_t setTimeoutTv(timeval tv); + /** * Returns true if the countdown duration has passed. * @@ -61,22 +67,31 @@ class Countdown { * Returns the remaining milliseconds (0 if timeout) */ uint32_t getRemainingMillis() const; + + uint32_t getTimeoutMs() const; + + timeval getTimeout() const; + /** * Makes hasTimedOut() return true */ void timeOut(); - /** - * Internal countdown duration in milliseconds - */ - uint32_t timeout; + + static inline uint32_t timevalToMs(timeval& tv); private: /** - * Last time the timer was started (uptime) + * Start time of the countdown. */ - uint32_t startTime = 0; + timeval startTime{}; - uint32_t getCurrentTime() const; + /** + * Timeout as timeval type. The countdown has timed out when the + * current time exceeds the start time plus the timeout. + */ + timeval timeout{}; + + timeval getCurrentTime() const; }; #endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */