#ifndef __JEEP__JTIMEKEEPER__ #define __JEEP__JTIMEKEEPER__ #include #include #include #include "JSystem/JTime.hh" #include "JLang/JFileDescriptorMask.hh" #include "JLang/JTimeval.hh" #include "Jeep/JTimer.hh" /** * \file * Scheduling of actions via fixed latency intervals. * \author mdejong */ namespace JEEP {} namespace JPP { using namespace JEEP; } namespace JEEP { using JSYSTEM::getLocalTime; using JLANG::JFileDescriptorMask; using JLANG::JTimeval; /** * Time keeper. * This class can be used to check whether elapsed time exceeds preset time interval or * to wait until preset time interval has elapsed. */ class JTimekeeper { public: /** * Default constructor. */ JTimekeeper() : interval (0), total_delay(0), counter (0) { reset(); } /** * Constructor. * * \param interval_us interval time [us] */ JTimekeeper(const long long int interval_us) : interval (interval_us), total_delay(0), counter (0) { reset(); } /** * Get interval time. * * \return interval time [us] */ long long int getInterval() const { return interval; } /** * Get total delay time. * * \return delay time [us] */ long long int getDelay() const { return total_delay; } /** * Set interval time. * * \param interval_us interval time [us] */ void setInterval(const long long int interval_us) { interval = interval_us; } /** * Reset time. * * \param t0 time [us] */ void reset(const long long int t0) { this->t0 = t0; this->counter = 0; this->total_delay = 0; } /** * Reset time. */ void reset() { reset(getLocalTime()); } /** * Check whether the number of time intervals has elapsed since * the last call to the reset method. * The number of intervals is equal to the number of calls this * method returned true since the last call to the reset method. * * \return true if elapsed time exceeds interval time; else false */ bool operator()() const { if (getLocalTime() >= t0 + (counter + 1) * interval) { ++counter; return true; } else return false; } /** * Wait until the number of time intervals has elapsed since * the last call to the reset method. * The number of intervals is equal to the number of calls to * the method wait since the last call to the reset method. */ void wait() const { static const useconds_t MAXIMAL_SLEEP_TIME_US = std::numeric_limits::max(); long long int delay = t0 + (counter + 1) * interval - getLocalTime(); // [us] while (delay > MAXIMAL_SLEEP_TIME_US && usleep(MAXIMAL_SLEEP_TIME_US) == 0) { total_delay += MAXIMAL_SLEEP_TIME_US; delay -= MAXIMAL_SLEEP_TIME_US; } if (delay > 0 && usleep((useconds_t) delay) == 0) { total_delay += delay; } ++counter; } /** * Wait until the number of time intervals has elapsed since * the last call to the reset method or input data have become * available on one of the file descriptors in the given mask. * The number of intervals is equal to the number of calls to * the method wait since the last call to the reset method. * Note that the mask is overwritten following a select call. * * \param mask input mask * \return true if interrupted; else false */ bool wait(JFileDescriptorMask& mask) const { long long int t1 = getLocalTime(); long long int delay = t0 + (counter + 1) * interval - t1; // [us] // ensure one select call for each call to this method. if (delay < 0) { delay = 0; } JTimeval timeout((int) (delay/1000000), (int) (delay%1000000)); if (mask.in_avail(timeout)) { total_delay += getLocalTime() - t1; return true; } else { ++counter; total_delay += delay; return false; } } protected: long long int interval; //!< interval time [us] private: mutable long long int t0; //!< t0 of elapsed time [us] mutable long long int total_delay; //!< total delay time [us] mutable long long int counter; //!< interval counter }; } #endif