/* PIP - Platform Independent Primitives Unix time Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "piincludes_p.h" #include "pisystemtime.h" #include "pitime.h" #include #ifdef QNX # include #endif #ifndef MICRO_PIP # include "pisystemtests.h" #elif defined(ARDUINO) # include #endif #ifdef WINDOWS extern FILETIME __pi_ftjan1970; long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;} #endif #ifdef MAC_OS //# include //# include # include //# include extern clock_serv_t __pi_mac_clock; #endif #ifdef MICRO_PIP # include #endif //! \addtogroup Core //! \{ //! \class PISystemTime pisystemtime.h //! \brief //! \~english System time with nanosecond precision //! \~russian Системное время с точностью до наносекунд //! //! \~english \section PISystemTime_sec0 Synopsis //! \~russian \section PISystemTime_sec0 Краткий обзор //! \~english //! This class provide arithmetic functions for POSIX system time. //! This time represents as seconds and nanosecons in integer formats. //! You can take current system time with function \a PISystemTime::current(), //! compare times, sum or subtract two times, convert time to/from //! seconds, milliseconds, microseconds or nanoseconds. //! //! \~russian //! Этот класс предоставляет арифметику для системного времени в формате POSIX. //! Это время представлено в виде целочисленных секунд и наносекунд. //! Можно взять текущее время с помощью метода \a PISystemTime::current(), //! сравнивать, суммировать и вычитать времена, преобразовывать в/из //! секунд, миллисекунд, микросекунд и наносекунд. //! //! \~english \section PISystemTime_sec1 Example //! \~russian \section PISystemTime_sec1 Пример //! \~\snippet pitimer.cpp system_time //! //! \} //! \addtogroup Core //! \{ //! \class PITimeMeasurer pisystemtime.h //! \brief //! \~english Time measurements //! \~russian Измерение времени //! //! \~english \section PITimeMeasurer_sec0 Usage //! \~russian \section PITimeMeasurer_sec0 Использование //! \~english //! Function \a reset() set time mark to current //! system time, then functions "double elapsed_*()" returns time elapsed from this mark. //! These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m" //! and "s" //! //! \~russian //! Метод \a reset() устанавливает текущую метку системного времени. Далее методы //! "double elapsed_*()" возвращают время, прошедшее от установленной метки. //! Эти методы возвращают нано, микро, милли и секунды с приставками //! "n", "u", "m" и "s". //! //! \} //! \details //! \warning //! \~english //! Use this function to sleep for difference of system times or constructs system time. //! If you call this function on system time returned with \a PISystemTime::current() thread will be sleep almost forever //! \~russian //! Используйте этот метод для ожидания разниц системных времен или своего времени. //! Если метод будет вызван для системного времени \a PISystemTime::current(), то //! ожидание будет почти бесконечным void PISystemTime::sleep() { piUSleep(piFloord(toMicroseconds())); } void PISystemTime::toTimespec(void * ts) { #ifndef WINDOWS ((timespec*)ts)->tv_sec = seconds; ((timespec*)ts)->tv_nsec = nanoseconds; #endif } PISystemTime PISystemTime::abs() const { if (seconds < 0) return PISystemTime(piAbsl(seconds) - 1, 1000000000l - piAbsl(nanoseconds)); else return PISystemTime(piAbsl(seconds), piAbsl(nanoseconds)); } PISystemTime PISystemTime::current(bool precise_but_not_system) { #ifdef WINDOWS if (precise_but_not_system) { llong qpc(0); if (__pi_perf_freq > 0) { qpc = __PIQueryPerformanceCounter(); return PISystemTime::fromSeconds(qpc / double(__pi_perf_freq)); } return PISystemTime(); } else { FILETIME ft, sft; # if (_WIN32_WINNT >= 0x0602) GetSystemTimePreciseAsFileTime(&ft); # else GetSystemTimeAsFileTime(&ft); # endif sft.dwHighDateTime = ft.dwHighDateTime - __pi_ftjan1970.dwHighDateTime; if (ft.dwLowDateTime < __pi_ftjan1970.dwLowDateTime) { sft.dwLowDateTime = ft.dwLowDateTime + (0xFFFFFFFF - __pi_ftjan1970.dwLowDateTime); sft.dwHighDateTime--; } else sft.dwLowDateTime = ft.dwLowDateTime - __pi_ftjan1970.dwLowDateTime; ullong lt = ullong(sft.dwHighDateTime) * 0x100000000U + ullong(sft.dwLowDateTime); return PISystemTime(lt / 10000000U, (lt % 10000000U) * 100U); } #elif defined(MAC_OS) mach_timespec_t t_cur; clock_get_time(__pi_mac_clock, &t_cur); #elif defined(MICRO_PIP) timespec t_cur; # ifdef ARDUINO static const uint32_t offSetSinceEpoch_s = 1581897605UL; uint32_t mt = millis(); t_cur.tv_sec = offSetSinceEpoch_s + (mt / 1000); t_cur.tv_nsec = (mt - (mt / 1000)) * 1000000UL; # else timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; gettimeofday(&tv, NULL); t_cur.tv_sec = tv.tv_sec; t_cur.tv_nsec = tv.tv_usec * 1000; # endif #else timespec t_cur; clock_gettime(precise_but_not_system ? CLOCK_MONOTONIC : 0, &t_cur); #endif #ifndef WINDOWS return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec); #endif } PITimeMeasurer::PITimeMeasurer() { reset(); } double PITimeMeasurer::elapsed_n() const { return (PISystemTime::current(true) - t_st).toNanoseconds() #ifndef MICRO_PIP - PISystemTests::time_elapsed_ns #endif ; } double PITimeMeasurer::elapsed_u() const { return (PISystemTime::current(true) - t_st).toMicroseconds() #ifndef MICRO_PIP - PISystemTests::time_elapsed_ns / 1.E+3 #endif ; } double PITimeMeasurer::elapsed_m() const { return (PISystemTime::current(true) - t_st).toMilliseconds() #ifndef MICRO_PIP - PISystemTests::time_elapsed_ns / 1.E+6 #endif ; } double PITimeMeasurer::elapsed_s() const { return (PISystemTime::current(true) - t_st).toSeconds() #ifndef MICRO_PIP - PISystemTests::time_elapsed_ns / 1.E+9 #endif ; } PISystemTime PITimeMeasurer::elapsed() const { return (PISystemTime::current(true) - t_st); }