clocks suck
This commit is contained in:
parent
6d85fa155e
commit
123c81777a
@ -11,19 +11,6 @@
|
|||||||
// TODO sanitize input?
|
// TODO sanitize input?
|
||||||
// TODO much of this code can be reused for tick-only systems
|
// TODO much of this code can be reused for tick-only systems
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
|
|
||||||
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return setClock(&time_timeval);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||||
timeval uptime = getUptime();
|
timeval uptime = getUptime();
|
||||||
|
|
||||||
@ -44,83 +31,15 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|
||||||
*uptime = getUptime();
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeval Clock::getUptime() {
|
timeval Clock::getUptime() {
|
||||||
TickType_t ticksSinceStart = xTaskGetTickCount();
|
TickType_t ticksSinceStart = xTaskGetTickCount();
|
||||||
return Timekeeper::ticksToTimeval(ticksSinceStart);
|
return Timekeeper::ticksToTimeval(ticksSinceStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
|
||||||
timeval uptime = getUptime();
|
|
||||||
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint32_t Clock::getUptimeSeconds() {
|
// uint32_t Clock::getUptimeSeconds() {
|
||||||
// timeval uptime = getUptime();
|
// timeval uptime = getUptime();
|
||||||
// return uptime.tv_sec;
|
// return uptime.tv_sec;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
ReturnValue_t result = getClock_timeval(&time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
ReturnValue_t result = getClock_timeval(&time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
struct tm time_tm;
|
|
||||||
|
|
||||||
gmtime_r(&time_timeval.tv_sec, &time_tm);
|
|
||||||
|
|
||||||
time->year = time_tm.tm_year + 1900;
|
|
||||||
time->month = time_tm.tm_mon + 1;
|
|
||||||
time->day = time_tm.tm_mday;
|
|
||||||
|
|
||||||
time->hour = time_tm.tm_hour;
|
|
||||||
time->minute = time_tm.tm_min;
|
|
||||||
time->second = time_tm.tm_sec;
|
|
||||||
|
|
||||||
time->usecond = time_timeval.tv_usec;
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
|
||||||
struct tm time_tm = {};
|
|
||||||
|
|
||||||
time_tm.tm_year = from->year - 1900;
|
|
||||||
time_tm.tm_mon = from->month - 1;
|
|
||||||
time_tm.tm_mday = from->day;
|
|
||||||
|
|
||||||
time_tm.tm_hour = from->hour;
|
|
||||||
time_tm.tm_min = from->minute;
|
|
||||||
time_tm.tm_sec = from->second;
|
|
||||||
|
|
||||||
time_tm.tm_isdst = 0;
|
|
||||||
|
|
||||||
time_t seconds = timegm(&time_tm);
|
|
||||||
|
|
||||||
to->tv_sec = seconds;
|
|
||||||
to->tv_usec = from->usecond;
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
|
||||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -15,27 +15,6 @@
|
|||||||
|
|
||||||
using SystemClock = std::chrono::system_clock;
|
using SystemClock = std::chrono::system_clock;
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Clock::getTicksPerSecond: Not implemented for host OSAL" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("Clock::getTicksPerSecond: Not implemented for host OSAL\n");
|
|
||||||
#endif
|
|
||||||
/* To avoid division by zero */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
|
||||||
/* I don't know why someone would need to set a clock which is probably perfectly fine on a
|
|
||||||
host system with internet access so this is not implemented for now. */
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
|
|
||||||
#endif
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||||
/* I don't know why someone would need to set a clock which is probably perfectly fine on a
|
/* I don't know why someone would need to set a clock which is probably perfectly fine on a
|
||||||
host system with internet access so this is not implemented for now. */
|
host system with internet access so this is not implemented for now. */
|
||||||
@ -66,6 +45,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
time->tv_usec = timeUnix.tv_nsec / 1000.0;
|
time->tv_usec = timeUnix.tv_nsec / 1000.0;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
#else
|
#else
|
||||||
|
#warning Clock::getClock_timeval() not implemented for your platform
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
|
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
|
||||||
#else
|
#else
|
||||||
@ -75,15 +55,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|
||||||
if (time == nullptr) {
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
using namespace std::chrono;
|
|
||||||
*time = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeval Clock::getUptime() {
|
timeval Clock::getUptime() {
|
||||||
timeval timeval;
|
timeval timeval;
|
||||||
#if defined(PLATFORM_WIN)
|
#if defined(PLATFORM_WIN)
|
||||||
@ -100,6 +71,7 @@ timeval Clock::getUptime() {
|
|||||||
timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6);
|
timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
#warning Clock::getUptime() not implemented for your platform
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
|
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -107,66 +79,3 @@ timeval Clock::getUptime() {
|
|||||||
return timeval;
|
return timeval;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|
||||||
*uptime = getUptime();
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
|
||||||
timeval uptime = getUptime();
|
|
||||||
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|
||||||
/* Do some magic with chrono (C++20!) */
|
|
||||||
/* Right now, the library doesn't have the new features to get the required values yet.
|
|
||||||
so we work around that for now. */
|
|
||||||
auto now = SystemClock::now();
|
|
||||||
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
|
||||||
auto fraction = now - seconds;
|
|
||||||
time_t tt = SystemClock::to_time_t(now);
|
|
||||||
ReturnValue_t result = checkOrCreateClockMutex();
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
MutexGuard helper(timeMutex);
|
|
||||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
|
||||||
// Therefore we have to use a Mutex here
|
|
||||||
struct tm* timeInfo;
|
|
||||||
timeInfo = gmtime(&tt);
|
|
||||||
time->year = timeInfo->tm_year + 1900;
|
|
||||||
time->month = timeInfo->tm_mon + 1;
|
|
||||||
time->day = timeInfo->tm_mday;
|
|
||||||
time->hour = timeInfo->tm_hour;
|
|
||||||
time->minute = timeInfo->tm_min;
|
|
||||||
time->second = timeInfo->tm_sec;
|
|
||||||
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
|
|
||||||
time->usecond = usecond.count();
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
|
||||||
struct tm time_tm {};
|
|
||||||
|
|
||||||
time_tm.tm_year = from->year - 1900;
|
|
||||||
time_tm.tm_mon = from->month - 1;
|
|
||||||
time_tm.tm_mday = from->day;
|
|
||||||
|
|
||||||
time_tm.tm_hour = from->hour;
|
|
||||||
time_tm.tm_min = from->minute;
|
|
||||||
time_tm.tm_sec = from->second;
|
|
||||||
time_tm.tm_isdst = 0;
|
|
||||||
|
|
||||||
time_t seconds = timegm(&time_tm);
|
|
||||||
|
|
||||||
to->tv_sec = seconds;
|
|
||||||
to->tv_usec = from->usecond;
|
|
||||||
// Fails in 2038..
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
|
||||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -10,26 +10,6 @@
|
|||||||
#include "fsfw/ipc/MutexGuard.h"
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond() {
|
|
||||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
|
||||||
return ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
|
||||||
timespec timeUnix{};
|
|
||||||
timeval timeTimeval{};
|
|
||||||
convertTimeOfDayToTimeval(time, &timeTimeval);
|
|
||||||
timeUnix.tv_sec = timeTimeval.tv_sec;
|
|
||||||
timeUnix.tv_nsec = (__syscall_slong_t)timeTimeval.tv_usec * 1000;
|
|
||||||
|
|
||||||
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
|
|
||||||
if (status != 0) {
|
|
||||||
// TODO errno
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||||
timespec timeUnix{};
|
timespec timeUnix{};
|
||||||
timeUnix.tv_sec = time->tv_sec;
|
timeUnix.tv_sec = time->tv_sec;
|
||||||
@ -53,37 +33,14 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|
||||||
timeval timeVal{};
|
|
||||||
ReturnValue_t result = getClock_timeval(&timeVal);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*time = static_cast<uint64_t>(timeVal.tv_sec) * 1e6 + timeVal.tv_usec;
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeval Clock::getUptime() {
|
timeval Clock::getUptime() {
|
||||||
timeval uptime{};
|
timeval uptime{0,0};
|
||||||
auto result = getUptime(&uptime);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Clock::getUptime: Error getting uptime" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return uptime;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
double uptimeSeconds;
|
||||||
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
|
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
|
||||||
uptime->tv_sec = uptimeSeconds;
|
uptime->tv_sec = uptimeSeconds;
|
||||||
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return uptime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for new FSFW Clock function delivering seconds uptime.
|
// Wait for new FSFW Clock function delivering seconds uptime.
|
||||||
@ -97,60 +54,3 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|||||||
// return sysInfo.uptime;
|
// return sysInfo.uptime;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
|
||||||
timeval uptime{};
|
|
||||||
ReturnValue_t result = getUptime(&uptime);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|
||||||
timespec timeUnix{};
|
|
||||||
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
|
||||||
if (status != 0) {
|
|
||||||
// TODO errno
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
ReturnValue_t result = checkOrCreateClockMutex();
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
MutexGuard helper(timeMutex);
|
|
||||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
|
||||||
// Therefore we have to use a Mutex here
|
|
||||||
struct std::tm* timeInfo;
|
|
||||||
timeInfo = gmtime(&timeUnix.tv_sec);
|
|
||||||
time->year = timeInfo->tm_year + 1900;
|
|
||||||
time->month = timeInfo->tm_mon + 1;
|
|
||||||
time->day = timeInfo->tm_mday;
|
|
||||||
time->hour = timeInfo->tm_hour;
|
|
||||||
time->minute = timeInfo->tm_min;
|
|
||||||
time->second = timeInfo->tm_sec;
|
|
||||||
time->usecond = timeUnix.tv_nsec / 1000.0;
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
|
||||||
std::tm fromTm{};
|
|
||||||
// Note: Fails for years before AD
|
|
||||||
fromTm.tm_year = from->year - 1900;
|
|
||||||
fromTm.tm_mon = from->month - 1;
|
|
||||||
fromTm.tm_mday = from->day;
|
|
||||||
fromTm.tm_hour = from->hour;
|
|
||||||
fromTm.tm_min = from->minute;
|
|
||||||
fromTm.tm_sec = from->second;
|
|
||||||
fromTm.tm_isdst = 0;
|
|
||||||
|
|
||||||
to->tv_sec = timegm(&fromTm);
|
|
||||||
to->tv_usec = from->usecond;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
|
||||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -34,24 +34,12 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||||
timespec newTime;
|
TimeOfDay_t time_tod;
|
||||||
newTime.tv_sec = time->tv_sec;
|
ReturnValue_t result = convertTimevalToTimeOfDay(time, &time_tod);
|
||||||
if (time->tv_usec < 0) {
|
if (result != returnvalue::OK) {
|
||||||
// better returnvalue.
|
return result;
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
}
|
||||||
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
|
return setClock(&time_tod);
|
||||||
|
|
||||||
ISR_lock_Context context;
|
|
||||||
_TOD_Lock();
|
|
||||||
_TOD_Acquire(&context);
|
|
||||||
Status_Control status = _TOD_Set(&newTime, &context);
|
|
||||||
_TOD_Unlock();
|
|
||||||
if (status == STATUS_SUCCESSFUL) {
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
// better returnvalue
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||||
@ -73,8 +61,7 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|||||||
timespec time;
|
timespec time;
|
||||||
rtems_status_code status = rtems_clock_get_uptime(&time);
|
rtems_status_code status = rtems_clock_get_uptime(&time);
|
||||||
uptime->tv_sec = time.tv_sec;
|
uptime->tv_sec = time.tv_sec;
|
||||||
time.tv_nsec = time.tv_nsec / 1000;
|
uptime->tv_usec = time.tv_nsec / 1000;
|
||||||
uptime->tv_usec = time.tv_nsec;
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case RTEMS_SUCCESSFUL:
|
case RTEMS_SUCCESSFUL:
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
@ -84,8 +71,9 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
||||||
// This counter overflows after 50 days
|
// 32bit counter overflows after 50 days
|
||||||
*uptimeMs = rtems_clock_get_ticks_since_boot();
|
uint64_t uptime = rtems_clock_get_uptime_nanoseconds() / 1e6;
|
||||||
|
*uptimeMs = uptime & 0xffffffff;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,50 +88,3 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|
||||||
/* For all but the last field, the struct will be filled with the correct values */
|
|
||||||
rtems_time_of_day timeRtems;
|
|
||||||
rtems_status_code status = rtems_clock_get_tod(&timeRtems);
|
|
||||||
switch (status) {
|
|
||||||
case RTEMS_SUCCESSFUL: {
|
|
||||||
time->day = timeRtems.day;
|
|
||||||
time->hour = timeRtems.hour;
|
|
||||||
time->minute = timeRtems.minute;
|
|
||||||
time->month = timeRtems.month;
|
|
||||||
time->second = timeRtems.second;
|
|
||||||
time->usecond =
|
|
||||||
static_cast<float>(timeRtems.ticks) / rtems_clock_get_ticks_per_second() * 1e6;
|
|
||||||
time->year = timeRtems.year;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
case RTEMS_NOT_DEFINED:
|
|
||||||
/* System date and time is not set */
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
case RTEMS_INVALID_ADDRESS:
|
|
||||||
/* time_buffer is NULL */
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
default:
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
|
||||||
// Fails in 2038..
|
|
||||||
rtems_time_of_day timeRtems;
|
|
||||||
timeRtems.year = from->year;
|
|
||||||
timeRtems.month = from->month;
|
|
||||||
timeRtems.day = from->day;
|
|
||||||
timeRtems.hour = from->hour;
|
|
||||||
timeRtems.minute = from->minute;
|
|
||||||
timeRtems.second = from->second;
|
|
||||||
timeRtems.ticks = from->usecond * rtems_clock_get_ticks_per_second() / 1e6;
|
|
||||||
to->tv_sec = _TOD_To_seconds(&timeRtems);
|
|
||||||
to->tv_usec = from->usecond;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
|
||||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class Clock {
|
class Clock {
|
||||||
public:
|
public:
|
||||||
|
// https://xkcd.com/927/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t year; //!< Year, A.D.
|
uint32_t year; //!< Year, A.D.
|
||||||
uint32_t month; //!< Month, 1 .. 12.
|
uint32_t month; //!< Month, 1 .. 12.
|
||||||
@ -26,14 +28,6 @@ class Clock {
|
|||||||
uint32_t usecond; //!< Microseconds, 0 .. 999999
|
uint32_t usecond; //!< Microseconds, 0 .. 999999
|
||||||
} TimeOfDay_t;
|
} TimeOfDay_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the number of clock ticks per second.
|
|
||||||
* In RTEMS, this is typically 1000.
|
|
||||||
* @return The number of ticks.
|
|
||||||
*
|
|
||||||
* @deprecated, we should not worry about ticks, but only time
|
|
||||||
*/
|
|
||||||
static uint32_t getTicksPerSecond();
|
|
||||||
/**
|
/**
|
||||||
* This system call sets the system time.
|
* This system call sets the system time.
|
||||||
* To set the time, it uses a TimeOfDay_t struct.
|
* To set the time, it uses a TimeOfDay_t struct.
|
||||||
@ -61,13 +55,8 @@ class Clock {
|
|||||||
/**
|
/**
|
||||||
* Get the time since boot in a timeval struct
|
* Get the time since boot in a timeval struct
|
||||||
*
|
*
|
||||||
* @param[out] time A pointer to a timeval struct where the uptime is stored.
|
* @return a timeval struct where the uptime is stored
|
||||||
* @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
|
||||||
*
|
|
||||||
* @deprecated, I do not think this should be able to fail, use timeval getUptime()
|
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t getUptime(timeval *uptime);
|
|
||||||
|
|
||||||
static timeval getUptime();
|
static timeval getUptime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +68,7 @@ class Clock {
|
|||||||
* @param ms uptime in ms
|
* @param ms uptime in ms
|
||||||
* @return returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
* @return returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t getUptime(uint32_t *uptimeMs);
|
static uint32_t getUptime_ms();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time in microseconds since an OS-defined epoch.
|
* Returns the time in microseconds since an OS-defined epoch.
|
||||||
@ -90,6 +79,7 @@ class Clock {
|
|||||||
* - Otherwise, the OS failure code is returned.
|
* - Otherwise, the OS failure code is returned.
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t getClock_usecs(uint64_t *time);
|
static ReturnValue_t getClock_usecs(uint64_t *time);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time in a TimeOfDay_t struct.
|
* Returns the time in a TimeOfDay_t struct.
|
||||||
* @param time A pointer to a TimeOfDay_t struct.
|
* @param time A pointer to a TimeOfDay_t struct.
|
||||||
@ -106,6 +96,7 @@ class Clock {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
|
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a time of day struct to POSIX seconds.
|
* Converts a time of day struct to POSIX seconds.
|
||||||
* @param time The time of day as input
|
* @param time The time of day as input
|
||||||
|
@ -53,34 +53,61 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
|
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
|
||||||
struct tm* timeInfo;
|
struct tm time_tm;
|
||||||
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
|
// WINDOWS does not provide gmtime_r, but gmtime_s
|
||||||
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
|
|
||||||
// this implementation
|
|
||||||
ReturnValue_t result = checkOrCreateClockMutex();
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
|
||||||
// Therefore we have to use a Mutex here
|
|
||||||
MutexGuard helper(timeMutex);
|
|
||||||
#ifdef PLATFORM_WIN
|
#ifdef PLATFORM_WIN
|
||||||
time_t time;
|
errno_t result = gmtime_s(&time_tm, &from->tv_sec);
|
||||||
time = from->tv_sec;
|
if (result != 0) {
|
||||||
timeInfo = gmtime(&time);
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
timeInfo = gmtime(&from->tv_sec);
|
void* result = gmtime_r(&from->tv_sec, &time_tm);
|
||||||
|
|
||||||
|
if (result == nullptr) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
to->year = timeInfo->tm_year + 1900;
|
|
||||||
to->month = timeInfo->tm_mon + 1;
|
to->year = time_tm.tm_year + 1900;
|
||||||
to->day = timeInfo->tm_mday;
|
to->month = time_tm.tm_mon + 1;
|
||||||
to->hour = timeInfo->tm_hour;
|
to->day = time_tm.tm_mday;
|
||||||
to->minute = timeInfo->tm_min;
|
to->hour = time_tm.tm_hour;
|
||||||
to->second = timeInfo->tm_sec;
|
to->minute = time_tm.tm_min;
|
||||||
|
to->second = time_tm.tm_sec;
|
||||||
to->usecond = from->tv_usec;
|
to->usecond = from->tv_usec;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
||||||
|
struct tm time_tm = {};
|
||||||
|
|
||||||
|
time_tm.tm_year = from->year - 1900;
|
||||||
|
time_tm.tm_mon = from->month - 1;
|
||||||
|
time_tm.tm_mday = from->day;
|
||||||
|
|
||||||
|
time_tm.tm_hour = from->hour;
|
||||||
|
time_tm.tm_min = from->minute;
|
||||||
|
time_tm.tm_sec = from->second;
|
||||||
|
|
||||||
|
time_tm.tm_isdst = 0;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WIN
|
||||||
|
time_t seconds = _mkgmtime(&time_tm);
|
||||||
|
#else
|
||||||
|
time_t seconds = timegm(&time_tm);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
to->tv_sec = seconds;
|
||||||
|
to->tv_usec = from->usecond;
|
||||||
|
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||||
|
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
||||||
if (timeMutex == nullptr) {
|
if (timeMutex == nullptr) {
|
||||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||||
@ -94,3 +121,37 @@ ReturnValue_t Clock::checkOrCreateClockMutex() {
|
|||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||||
|
timeval time_timeval;
|
||||||
|
ReturnValue_t result = getClock_timeval(&time_timeval);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return convertTimevalToTimeOfDay(&time_timeval, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||||
|
timeval timeVal{};
|
||||||
|
ReturnValue_t result = getClock_timeval(&timeVal);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*time = static_cast<uint64_t>(timeVal.tv_sec) * 1e6 + timeVal.tv_usec;
|
||||||
|
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||||
|
timeval timeTimeval{};
|
||||||
|
ReturnValue_t result = convertTimeOfDayToTimeval(time, &timeTimeval);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return setClock(&timeTimeval);
|
||||||
|
}
|
||||||
|
uint32_t Clock::getUptime_ms() {
|
||||||
|
timeval uptime = getUptime();
|
||||||
|
//TODO verify that overflow is correct
|
||||||
|
return uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
|
||||||
|
}
|
@ -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::getUptime(&startTime);
|
startTime = Clock::getUptime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stopwatch::start() { Clock::getUptime(&startTime); }
|
void Stopwatch::start() { startTime = Clock::getUptime(); }
|
||||||
|
|
||||||
dur_millis_t Stopwatch::stop(bool display) {
|
dur_millis_t Stopwatch::stop(bool display) {
|
||||||
stopInternal();
|
stopInternal();
|
||||||
@ -62,7 +62,6 @@ void Stopwatch::setDisplayMode(StopwatchDisplayMode displayMode) {
|
|||||||
StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
|
StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
|
||||||
|
|
||||||
void Stopwatch::stopInternal() {
|
void Stopwatch::stopInternal() {
|
||||||
timeval endTime;
|
timeval endTime = Clock::getUptime();
|
||||||
Clock::getUptime(&endTime);
|
|
||||||
elapsedTime = endTime - startTime;
|
elapsedTime = endTime - startTime;
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,7 @@ TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
|
|||||||
// We require timeOfDayAsTimeval to be larger than time as it
|
// We require timeOfDayAsTimeval to be larger than time as it
|
||||||
// was request a few ns later
|
// was request a few ns later
|
||||||
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
|
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
|
||||||
uint32_t ticksPerSecond =Clock:: getTicksPerSecond();
|
CHECK(difference >= 0);
|
||||||
float secondPerTick = 0;
|
|
||||||
if (ticksPerSecond != 0){
|
|
||||||
secondPerTick = 1.0 / ticksPerSecond;
|
|
||||||
}
|
|
||||||
// In rtems, timevals have microsecond resolution, while TOD has only tick resolution, leading to
|
|
||||||
// negative differences when comparing "equal" times
|
|
||||||
CHECK(difference >= -secondPerTick);
|
|
||||||
CHECK(difference <= 0.005);
|
CHECK(difference <= 0.005);
|
||||||
|
|
||||||
// Conversion in the other direction
|
// Conversion in the other direction
|
||||||
|
Loading…
x
Reference in New Issue
Block a user