diff --git a/CHANGELOG.md b/CHANGELOG.md index e08cd12a..d2eff76e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixes +- Add monotonic watchdog Clock API and use it in `Countdown` and `Stopwatch` class. - Bugfix in `Service11TelecommandScheduling` which allowed commands time tagged in the past to be inserted. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738 diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index dbf6529c..ec66a11d 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getClock_timeval(timeval* time) { +ReturnValue_t Clock::getClockMonotonic(timeval* time) { +#if defined(PLATFORM_WIN) + // TODO: Implement with std::chrono::steady_clock.. or in some other way. I am not even sure + // whether this is possible with steady_clock. The conversion we have to do here just to be + // generic is kind of awkward.. + return returnvalue::FAILED; +#elif defined(PLATFORM_UNIX) + timespec timeMonotonic; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); + if (status != 0) { + return returnvalue::FAILED; + } + time->tv_sec = timeMonotonic.tv_sec; + time->tv_usec = timeMonotonic.tv_nsec / 1000.0; + return returnvalue::OK; +#else +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl; +#else + sif::printWarning("Clock::getUptime: Not implemented for found OS!\n"); +#endif + return returnvalue::FAILED; +#endif +} + +ReturnValue_t Clock::getClock(timeval* time) { #if defined(PLATFORM_WIN) auto now = std::chrono::system_clock::now(); auto secondsChrono = std::chrono::time_point_cast(now); @@ -75,6 +100,10 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { #endif } +ReturnValue_t Clock::getClock_timeval(timeval* time) { + return Clock::getClock(time); +} + ReturnValue_t Clock::getClock_usecs(uint64_t* time) { if (time == nullptr) { return returnvalue::FAILED; diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index 47099fb2..050ec099 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getClock_timeval(timeval* time) { +ReturnValue_t Clock::getClock(timeval *time) { timespec timeUnix{}; int status = clock_gettime(CLOCK_REALTIME, &timeUnix); if (status != 0) { @@ -53,6 +53,10 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { return returnvalue::OK; } +ReturnValue_t Clock::getClock_timeval(timeval* time) { + return Clock::getClock(time); +} + ReturnValue_t Clock::getClock_usecs(uint64_t* time) { timeval timeVal{}; ReturnValue_t result = getClock_timeval(&timeVal); @@ -64,6 +68,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { return returnvalue::OK; } +ReturnValue_t Clock::getClockMonotonic(timeval *time) { + timespec timeMonotonic{}; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); + if (status != 0) { + return returnvalue::FAILED; + } + time->tv_sec = timeMonotonic.tv_sec; + time->tv_usec = timeMonotonic.tv_nsec / 1000.0; + return returnvalue::OK; +} + timeval Clock::getUptime() { timeval uptime{}; auto result = getUptime(&uptime); diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index 83bc3d9f..6fe6486c 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -49,6 +49,13 @@ class Clock { * @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t setClock(const timeval *time); + + /** + * @deprecated Use getClock instead, which does the same. + * @param time + * @return + */ + static ReturnValue_t getClock_timeval(timeval *time); /** * This system call returns the current system clock in timeval format. * The timval format has the fields @c tv_sec with seconds and @c tv_usec with @@ -56,7 +63,18 @@ class Clock { * @param time A pointer to a timeval struct where the current time is stored. * @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t getClock_timeval(timeval *time); + static ReturnValue_t getClock(timeval *time); + + /** + * Retrieve a monotonic clock. This clock this is also more suited for measuring elapsed times + * between two time points, but less suited when the absolute time is required. + * + * Implementation example: A generic UNIX implementation can use CLOCK_MONOTONIC_RAW with + * `clock_gettime`. + * @param time + * @return + */ + static ReturnValue_t getClockMonotonic(timeval *time); /** * Get the time since boot in a timeval struct diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp index 662fc8f0..5e743efe 100644 --- a/src/fsfw/timemanager/Countdown.cpp +++ b/src/fsfw/timemanager/Countdown.cpp @@ -16,7 +16,7 @@ Countdown::~Countdown() = default; ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { timeout.tv_sec = milliseconds / 1000; timeout.tv_usec = (milliseconds % 1000) * 1000; - return Clock::getClock_timeval(&startTime); + return Clock::getClockMonotonic(&startTime); } bool Countdown::hasTimedOut() const { @@ -48,7 +48,7 @@ uint32_t Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_u ReturnValue_t Countdown::setTimeoutTv(timeval tv) { timeout = tv; - return Clock::getClock_timeval(&startTime); + return Clock::getClockMonotonic(&startTime); } uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; } @@ -57,6 +57,6 @@ timeval Countdown::getTimeout() const { return timeout; } timeval Countdown::getCurrentTime() const { timeval currentTime{}; - Clock::getClock_timeval(¤tTime); + Clock::getClockMonotonic(¤tTime); return currentTime; } diff --git a/src/fsfw/timemanager/Stopwatch.cpp b/src/fsfw/timemanager/Stopwatch.cpp index 4bc3a460..ad39f1b3 100644 --- a/src/fsfw/timemanager/Stopwatch.cpp +++ b/src/fsfw/timemanager/Stopwatch.cpp @@ -9,10 +9,10 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode) : displayOnDestruction(displayOnDestruction), displayMode(displayMode) { // Measures start time on initialization. - Clock::getClock_timeval(&startTime); + Clock::getClockMonotonic(&startTime); } -void Stopwatch::start() { Clock::getUptime(&startTime); } +void Stopwatch::start() { Clock::getClockMonotonic(&startTime); } dur_millis_t Stopwatch::stop(bool display) { stopInternal(); @@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; } void Stopwatch::stopInternal() { timeval endTime; - Clock::getClock_timeval(&endTime); + Clock::getClockMonotonic(&endTime); elapsedTime = endTime - startTime; }