232 lines
7.1 KiB
C++
232 lines
7.1 KiB
C++
/*
|
||
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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "piincludes_p.h"
|
||
#include "pisystemtime.h"
|
||
#include "pitime.h"
|
||
#include <ctime>
|
||
#ifdef QNX
|
||
# include <time.h>
|
||
#endif
|
||
#ifndef MICRO_PIP
|
||
# include "pisystemtests.h"
|
||
#elif defined(ARDUINO)
|
||
# include <Arduino.h>
|
||
#endif
|
||
#ifdef WINDOWS
|
||
extern FILETIME __pi_ftjan1970;
|
||
long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;}
|
||
#endif
|
||
#ifdef MAC_OS
|
||
//# include <mach/mach_traps.h>
|
||
//# include <mach/mach.h>
|
||
# include <mach/clock.h>
|
||
//# include <crt_externs.h>
|
||
extern clock_serv_t __pi_mac_clock;
|
||
#endif
|
||
#ifdef MICRO_PIP
|
||
# include <sys/time.h>
|
||
#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);
|
||
}
|