Merge pull request 'new monotonic clock API' (#128) from feature_monotonic_clock_api into develop

Reviewed-on: #128
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
This commit is contained in:
Robin Müller 2023-03-04 11:47:37 +01:00
commit 2c5af91db1
6 changed files with 72 additions and 9 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Fixes ## Fixes
- Add monotonic watchdog Clock API and use it in `Countdown` and `Stopwatch` class.
- Bugfix in `Service11TelecommandScheduling` which allowed commands - Bugfix in `Service11TelecommandScheduling` which allowed commands
time tagged in the past to be inserted. time tagged in the past to be inserted.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738

View File

@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) {
return returnvalue::OK; 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) #if defined(PLATFORM_WIN)
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now); auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
@ -75,6 +100,10 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
#endif #endif
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) {
return Clock::getClock(time);
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
if (time == nullptr) { if (time == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;

View File

@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock(timeval *time) {
timespec timeUnix{}; timespec timeUnix{};
int status = clock_gettime(CLOCK_REALTIME, &timeUnix); int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
if (status != 0) { if (status != 0) {
@ -53,6 +53,10 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) {
return Clock::getClock(time);
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval timeVal{}; timeval timeVal{};
ReturnValue_t result = getClock_timeval(&timeVal); ReturnValue_t result = getClock_timeval(&timeVal);
@ -64,6 +68,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
return returnvalue::OK; 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 Clock::getUptime() {
timeval uptime{}; timeval uptime{};
auto result = getUptime(&uptime); auto result = getUptime(&uptime);

View File

@ -49,6 +49,13 @@ class Clock {
* @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned. * @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned.
*/ */
static ReturnValue_t setClock(const timeval *time); 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. * 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 * 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. * @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. * @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 * Get the time since boot in a timeval struct

View File

@ -16,7 +16,7 @@ Countdown::~Countdown() = default;
ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) {
timeout.tv_sec = milliseconds / 1000; timeout.tv_sec = milliseconds / 1000;
timeout.tv_usec = (milliseconds % 1000) * 1000; timeout.tv_usec = (milliseconds % 1000) * 1000;
return Clock::getClock_timeval(&startTime); return Clock::getClockMonotonic(&startTime);
} }
bool Countdown::hasTimedOut() const { 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) { ReturnValue_t Countdown::setTimeoutTv(timeval tv) {
timeout = 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; } 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 Countdown::getCurrentTime() const {
timeval currentTime{}; timeval currentTime{};
Clock::getClock_timeval(&currentTime); Clock::getClockMonotonic(&currentTime);
return currentTime; return currentTime;
} }

View File

@ -9,10 +9,10 @@
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode) Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) { : displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
// Measures start time on initialization. // 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) { dur_millis_t Stopwatch::stop(bool display) {
stopInternal(); stopInternal();
@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
void Stopwatch::stopInternal() { void Stopwatch::stopInternal() {
timeval endTime; timeval endTime;
Clock::getClock_timeval(&endTime); Clock::getClockMonotonic(&endTime);
elapsedTime = endTime - startTime; elapsedTime = endTime - startTime;
} }