From 95dab69b35cb7f7b086f8e5f528f66506c398838 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 4 Mar 2023 11:03:22 +0100 Subject: [PATCH 1/5] new monotonic clock API --- CHANGELOG.md | 1 + src/fsfw/osal/linux/Clock.cpp | 17 ++++++++++++++++- src/fsfw/timemanager/Clock.h | 20 +++++++++++++++++++- src/fsfw/timemanager/Countdown.cpp | 6 +++--- src/fsfw/timemanager/Stopwatch.cpp | 6 +++--- 5 files changed, 42 insertions(+), 8 deletions(-) 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/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index 47099fb2..c625785b 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 timeUnix{}; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeUnix); + if (status != 0) { + return returnvalue::FAILED; + } + time->tv_sec = timeUnix.tv_sec; + time->tv_usec = timeUnix.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; } From 04ee3c73626fae6c090762981096eaba11866ba8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 4 Mar 2023 11:04:55 +0100 Subject: [PATCH 2/5] renaming --- src/fsfw/osal/linux/Clock.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index c625785b..050ec099 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -69,13 +69,13 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { } ReturnValue_t Clock::getClockMonotonic(timeval *time) { - timespec timeUnix{}; - int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeUnix); + timespec timeMonotonic{}; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); if (status != 0) { return returnvalue::FAILED; } - time->tv_sec = timeUnix.tv_sec; - time->tv_usec = timeUnix.tv_nsec / 1000.0; + time->tv_sec = timeMonotonic.tv_sec; + time->tv_usec = timeMonotonic.tv_nsec / 1000.0; return returnvalue::OK; } From bbf0d7a0d25de0f2d2f6a63af8c0ebfa79251dfb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 4 Mar 2023 11:31:54 +0100 Subject: [PATCH 3/5] add basic impl (no windows) for host --- src/fsfw/osal/host/Clock.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index dbf6529c..18cc4639 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -47,7 +47,29 @@ 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 +#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 +97,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; From a39f1271ec5b7b2bd987c655705381d07a01baed Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 4 Mar 2023 11:32:32 +0100 Subject: [PATCH 4/5] return FAILED for win --- src/fsfw/osal/host/Clock.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index 18cc4639..5e917600 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -50,6 +50,7 @@ ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::getClockMonotonic(timeval* time) { #if defined(PLATFORM_WIN) // TODO: Implement with std::chrono::steady_clock + return returnvalue::FAILED; #elif defined(PLATFORM_UNIX) timespec timeMonotonic; int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); From 5cd7b98ba7a1f26702c3cf780e4cde6296164348 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 4 Mar 2023 11:38:16 +0100 Subject: [PATCH 5/5] more todo docs --- src/fsfw/osal/host/Clock.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index 5e917600..ec66a11d 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -49,7 +49,9 @@ ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::getClockMonotonic(timeval* time) { #if defined(PLATFORM_WIN) - // TODO: Implement with std::chrono::steady_clock + // 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;