2021-07-14 10:50:44 +02:00
|
|
|
#include "fsfw/timemanager/Clock.h"
|
2020-09-05 20:18:52 +02:00
|
|
|
|
|
|
|
#include <chrono>
|
2021-05-12 16:47:53 +02:00
|
|
|
|
2022-03-25 18:48:53 +01:00
|
|
|
#include "fsfw/ipc/MutexGuard.h"
|
2022-02-02 10:29:30 +01:00
|
|
|
#include "fsfw/platform.h"
|
|
|
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
|
|
|
|
2021-05-12 16:47:53 +02:00
|
|
|
#if defined(PLATFORM_WIN)
|
2021-01-29 00:12:40 +01:00
|
|
|
#include <sysinfoapi.h>
|
2022-09-27 21:46:11 +02:00
|
|
|
#define timegm _mkgmtime
|
2021-05-12 16:47:53 +02:00
|
|
|
#elif defined(PLATFORM_UNIX)
|
2020-09-05 20:18:52 +02:00
|
|
|
#include <fstream>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using SystemClock = std::chrono::system_clock;
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
uint32_t Clock::getTicksPerSecond(void) {
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "Clock::getTicksPerSecond: Not implemented for host OSAL" << std::endl;
|
2021-01-29 02:35:08 +01:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("Clock::getTicksPerSecond: Not implemented for host OSAL\n");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
/* To avoid division by zero */
|
|
|
|
return 1;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
2022-02-02 10:29:30 +01:00
|
|
|
/* 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. */
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
|
2021-01-29 02:35:08 +01:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
2022-02-02 10:29:30 +01:00
|
|
|
/* 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. */
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
|
2021-01-29 02:35:08 +01:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
2021-05-12 17:32:40 +02:00
|
|
|
#if defined(PLATFORM_WIN)
|
2022-02-02 10:29:30 +01:00
|
|
|
auto now = std::chrono::system_clock::now();
|
|
|
|
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
|
|
|
auto epoch = now.time_since_epoch();
|
|
|
|
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
|
|
|
|
auto fraction = now - secondsChrono;
|
|
|
|
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2021-05-12 17:32:40 +02:00
|
|
|
#elif defined(PLATFORM_UNIX)
|
2022-02-02 10:29:30 +01:00
|
|
|
timespec timeUnix;
|
|
|
|
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
|
|
|
if (status != 0) {
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
time->tv_sec = timeUnix.tv_sec;
|
|
|
|
time->tv_usec = timeUnix.tv_nsec / 1000.0;
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
#else
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
|
2021-01-25 00:55:27 +01:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("Clock::getUptime: Not implemented for found OS!\n");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::FAILED;
|
2020-09-05 20:18:52 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
2022-02-02 10:29:30 +01:00
|
|
|
if (time == nullptr) {
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
using namespace std::chrono;
|
|
|
|
*time = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
timeval Clock::getUptime() {
|
2022-02-02 10:29:30 +01:00
|
|
|
timeval timeval;
|
2021-05-12 17:32:40 +02:00
|
|
|
#if defined(PLATFORM_WIN)
|
2022-02-02 10:29:30 +01:00
|
|
|
auto uptime = std::chrono::milliseconds(GetTickCount64());
|
|
|
|
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
|
|
|
|
timeval.tv_sec = secondsChrono.count();
|
|
|
|
auto fraction = uptime - secondsChrono;
|
|
|
|
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
|
2021-05-12 17:32:40 +02:00
|
|
|
#elif defined(PLATFORM_UNIX)
|
2022-02-02 10:29:30 +01:00
|
|
|
double uptimeSeconds;
|
|
|
|
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
|
|
|
|
// value is rounded down automatically
|
|
|
|
timeval.tv_sec = uptimeSeconds;
|
|
|
|
timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6);
|
|
|
|
}
|
2020-09-05 20:18:52 +02:00
|
|
|
#else
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-09-05 20:18:52 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return timeval;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
2022-02-02 10:29:30 +01:00
|
|
|
*uptime = getUptime();
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
2022-02-02 10:29:30 +01:00
|
|
|
timeval uptime = getUptime();
|
|
|
|
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
2022-02-02 10:29:30 +01:00
|
|
|
/* 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);
|
2022-03-25 18:48:53 +01:00
|
|
|
ReturnValue_t result = checkOrCreateClockMutex();
|
2022-08-16 01:08:26 +02:00
|
|
|
if (result != returnvalue::OK) {
|
2022-03-25 18:47:31 +01:00
|
|
|
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
|
2022-02-02 10:29:30 +01:00
|
|
|
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();
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
2022-07-21 19:10:15 +02:00
|
|
|
struct tm time_tm {};
|
2020-09-05 20:18:52 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
time_tm.tm_year = from->year - 1900;
|
|
|
|
time_tm.tm_mon = from->month - 1;
|
|
|
|
time_tm.tm_mday = from->day;
|
2020-09-05 20:18:52 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
time_tm.tm_hour = from->hour;
|
|
|
|
time_tm.tm_min = from->minute;
|
|
|
|
time_tm.tm_sec = from->second;
|
2022-03-07 18:22:10 +01:00
|
|
|
time_tm.tm_isdst = 0;
|
2020-09-05 20:18:52 +02:00
|
|
|
|
2022-03-07 18:22:10 +01:00
|
|
|
time_t seconds = timegm(&time_tm);
|
2020-09-05 20:18:52 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
to->tv_sec = seconds;
|
|
|
|
to->tv_usec = from->usecond;
|
|
|
|
// Fails in 2038..
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
2022-02-02 10:29:30 +01:00
|
|
|
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
2022-08-16 01:08:26 +02:00
|
|
|
return returnvalue::OK;
|
2020-09-05 20:18:52 +02:00
|
|
|
}
|