/* PIP - Platform Independent Primitives Timer Copyright (C) 2020 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 "pitime.h" #include "pisystemtests.h" #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 FREERTOS # include "freertos/FreeRTOS.h" # include "freertos/task.h" #endif /*! \class PISystemTime * \brief System time * * \section PISystemTime_sec0 Synopsis * 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. * \section PISystemTime_sec1 Example * \snippet pitimer.cpp system_time */ /*! \class PITimeMeasurer * \brief Time measurements * * \section PITimeMeasurer_sec0 Synopsis * 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" */ void piUSleep(int usecs) { if (usecs <= 0) return; #ifdef WINDOWS //printf("Sleep %d\n", usecs / 1000); if (usecs > 0) Sleep(usecs / 1000); //printf("Sleep end"); #else # ifdef FREERTOS vTaskDelay(usecs / 1000 / portTICK_PERIOD_MS); # else usecs -= PISystemTests::usleep_offset_us; if (usecs > 0) usleep(usecs); # endif #endif } bool operator ==(const PITime & t0, const PITime & t1) { return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds); } bool operator <(const PITime & t0, const PITime & t1) { if (t0.hours == t1.hours) { if (t0.minutes == t1.minutes) { return t0.seconds < t1.seconds; } else return t0.minutes < t1.minutes; } else return t0.hours < t1.hours; } bool operator >(const PITime & t0, const PITime & t1) { if (t0.hours == t1.hours) { if (t0.minutes == t1.minutes) { return t0.seconds > t1.seconds; } else return t0.minutes > t1.minutes; } else return t0.hours > t1.hours; } bool operator ==(const PIDate & t0, const PIDate & t1) { return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day); } bool operator <(const PIDate & t0, const PIDate & t1) { if (t0.year == t1.year) { if (t0.month == t1.month) { return t0.day < t1.day; } else return t0.month < t1.month; } else return t0.year < t1.year; } bool operator >(const PIDate & t0, const PIDate & t1) { if (t0.year == t1.year) { if (t0.month == t1.month) { return t0.day > t1.day; } else return t0.month > t1.month; } else return t0.year > t1.year; } bool operator ==(const PIDateTime & t0, const PIDateTime & t1) { return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day && t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds); } bool operator <(const PIDateTime & t0, const PIDateTime & t1) { if (t0.year == t1.year) { if (t0.month == t1.month) { if (t0.day == t1.day) { if (t0.hours == t1.hours) { if (t0.minutes == t1.minutes) { return t0.seconds < t1.seconds; } else return t0.minutes < t1.minutes; } else return t0.hours < t1.hours; } else return t0.day < t1.day; } else return t0.month < t1.month; } else return t0.year < t1.year; } bool operator >(const PIDateTime & t0, const PIDateTime & t1) { if (t0.year == t1.year) { if (t0.month == t1.month) { if (t0.day == t1.day) { if (t0.hours == t1.hours) { if (t0.minutes == t1.minutes) { return t0.seconds > t1.seconds; } else return t0.minutes > t1.minutes; } else return t0.hours > t1.hours; } else return t0.day > t1.day; } else return t0.month > t1.month; } else return t0.year > t1.year; } PISystemTime PITime::toSystemTime() const { return PISystemTime((hours * 60. + minutes) * 60. + seconds, milliseconds * 1000.); } PITime PITime::current() { time_t rt = ::time(0); tm * pt = localtime(&rt); PITime t; t.seconds = pt->tm_sec; t.minutes = pt->tm_min; t.hours = pt->tm_hour; return t; } PITime PITime::fromSystemTime(const PISystemTime & st) { double s = st.toSeconds(); int v = s; PITime ret; ret.milliseconds = (s - v) * 1000; ret.seconds = v % 60; v = (v - ret.seconds) / 60; ret.minutes = v % 60; v = (v - ret.minutes) / 60; ret.hours = v; return ret; } PIDate PIDate::current() { time_t rt = ::time(0); tm * pt = localtime(&rt); PIDate d; d.day = pt->tm_mday; d.month = pt->tm_mon + 1; d.year = pt->tm_year + 1900; return d; } PIDateTime PIDateTime::current() { time_t rt = ::time(0); tm * pt = localtime(&rt); PIDateTime dt; dt.milliseconds = 0; dt.seconds = pt->tm_sec; dt.minutes = pt->tm_min; dt.hours = pt->tm_hour; dt.day = pt->tm_mday; dt.month = pt->tm_mon + 1; dt.year = pt->tm_year + 1900; return dt; } 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); } //long t_cur = GetCurrentTime(); //return PISystemTime(t_cur / 1000, (t_cur % 1000) * 1000000); #else # ifdef MAC_OS mach_timespec_t t_cur; clock_get_time(__pi_mac_clock, &t_cur); # else # ifdef FREERTOS timespec t_cur; 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; # else timespec t_cur; clock_gettime(0, &t_cur); # endif # endif return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec); #endif } PIString PITime::toString(const PIString & format) const { PIString ts = format; ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0')); ts.replace("h", PIString::fromNumber(hours)); ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0')); ts.replace("m", PIString::fromNumber(minutes)); ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0')); ts.replace("s", PIString::fromNumber(seconds)); ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0')); ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0')); ts.replace("z", PIString::fromNumber(milliseconds)); return ts; } PIString PIDate::toString(const PIString & format) const { PIString ts = format; ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(year).right(2)); ts.replace("y", PIString::fromNumber(year).right(1)); ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0')); ts.replace("M", PIString::fromNumber(month)); ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0')); ts.replace("d", PIString::fromNumber(day)); return ts; } PIString PIDateTime::toString(const PIString & format) const { PIString ts = format; ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(year).right(2)); ts.replace("y", PIString::fromNumber(year).right(1)); ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0')); ts.replace("M", PIString::fromNumber(month)); ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0')); ts.replace("d", PIString::fromNumber(day)); ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0')); ts.replace("h", PIString::fromNumber(hours)); ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0')); ts.replace("m", PIString::fromNumber(minutes)); ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0')); ts.replace("s", PIString::fromNumber(seconds)); ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0')); ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0')); ts.replace("z", PIString::fromNumber(milliseconds)); return ts; } time_t PIDateTime::toSecondSinceEpoch() const { tm pt; memset(&pt, 0, sizeof(pt)); pt.tm_sec = seconds; pt.tm_min = minutes; pt.tm_hour = hours; pt.tm_mday = day; pt.tm_mon = month - 1; #ifdef WINDOWS pt.tm_year = piMaxi(year - 1900, 70); #else pt.tm_year = piMaxi(year - 1900, 0); #endif return mktime(&pt); } PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) { tm * pt = localtime(&sec); PIDateTime dt; dt.seconds = pt->tm_sec; dt.minutes = pt->tm_min; dt.hours = pt->tm_hour; dt.day = pt->tm_mday; dt.month = pt->tm_mon + 1; dt.year = pt->tm_year + 1900; return dt; } PIString time2string(const PITime & time, const PIString & format) { PIString ts = format; ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0')); ts.replace("h", PIString::fromNumber(time.hours)); ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0')); ts.replace("m", PIString::fromNumber(time.minutes)); ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0')); ts.replace("s", PIString::fromNumber(time.seconds)); return ts; } PIString date2string(const PIDate & date, const PIString & format) { PIString ts = format; ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(date.year).right(2)); ts.replace("y", PIString::fromNumber(date.year).right(1)); ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0')); ts.replace("M", PIString::fromNumber(date.month)); ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0')); ts.replace("d", PIString::fromNumber(date.day)); return ts; } PIString datetime2string(const PIDateTime & date, const PIString & format) { PIString ts = format; ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0')); ts.replace("h", PIString::fromNumber(date.hours)); ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0')); ts.replace("m", PIString::fromNumber(date.minutes)); ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0')); ts.replace("s", PIString::fromNumber(date.seconds)); ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(date.year).right(2)); ts.replace("y", PIString::fromNumber(date.year).right(1)); ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0')); ts.replace("M", PIString::fromNumber(date.month)); ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0')); ts.replace("d", PIString::fromNumber(date.day)); return ts; } PITimeMeasurer::PITimeMeasurer() { reset(); } double PITimeMeasurer::elapsed_n() const { return (PISystemTime::current(true) - t_st).toNanoseconds() - PISystemTests::time_elapsed_ns; } double PITimeMeasurer::elapsed_u() const { return (PISystemTime::current(true) - t_st).toMicroseconds() - PISystemTests::time_elapsed_ns / 1.E+3; } double PITimeMeasurer::elapsed_m() const { return (PISystemTime::current(true) - t_st).toMilliseconds() - PISystemTests::time_elapsed_ns / 1.E+6; } double PITimeMeasurer::elapsed_s() const { return (PISystemTime::current(true) - t_st).toSeconds() - PISystemTests::time_elapsed_ns / 1.E+9; } PISystemTime PITimeMeasurer::elapsed() const { return (PISystemTime::current(true) - t_st); } PICout operator <<(PICout s, const PITime & v) { s.space(); s.setControl(0, true); s << "PITime(" << v.hours << ":"; s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":"; s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":"; s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")"; s.restoreControl(); return s; } PICout operator <<(PICout s, const PIDate & v) { s.space(); s.setControl(0, true); s << "PIDate(" << v.day << "-"; s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-"; s << v.year << ")"; s.restoreControl(); return s; } PICout operator <<(PICout s, const PIDateTime & v) { s.space(); s.setControl(0, true); s << "PIDateTime("; s << v.day << "-"; s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-"; s << v.year << " "; s << v.hours << ":"; s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":"; s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":"; s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")"; s.restoreControl(); return s; } #ifdef WINDOWS void msleep(int msecs) {Sleep(msecs);} #else # ifdef FREERTOS void msleep(int msecs) {vTaskDelay(msecs / portTICK_PERIOD_MS);} # else void msleep(int msecs) {usleep(msecs * 1000);} # endif #endif