/*! \file pitimer.h * \ingroup Thread * \~\brief * \~english Timer * \~russian Таймер */ /* PIP - Platform Independent Primitives Timer 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 . */ #ifndef PITIMER_H #define PITIMER_H #include "pithread.h" #include "pitime.h" typedef std::function TimerEvent; class PITimer; class PIP_EXPORT _PITimerBase { friend class PITimer; public: _PITimerBase(); virtual ~_PITimerBase() {} double interval() const { return interval_; } void setInterval(double i); bool isRunning() const { return running_; } bool isStopped() const { return !running_; } bool start() { return start(interval_); } bool start(double interval_ms); void startDeferred(double delay_ms) { startDeferred(interval_, delay_ms); } void startDeferred(double interval_ms, double delay_ms); void startDeferred(PIDateTime start_datetime) { startDeferred(interval_, start_datetime); } void startDeferred(double interval_ms, PIDateTime start_datetime); bool stop(); typedef void (*TickFunc)(PITimer *); TickFunc tfunc; PITimer * parent; protected: virtual bool startTimer(double interval_ms) = 0; virtual bool stopTimer() = 0; double interval_, deferred_delay; bool deferred_, deferred_mode; // mode: true - date, false - delay std::atomic_bool running_; PIDateTime deferred_datetime; }; class PIP_EXPORT PITimer: public PIObject { PIOBJECT_SUBCLASS(PITimer, PIObject); public: NO_COPY_CLASS(PITimer); //! \~english Constructs timer with PITimer::Thread implementation //! \~russian Создает таймер с реализацией PITimer::Thread explicit PITimer(); //! \~english Timer implementations //! \~russian Реализация таймера enum TimerImplementation { Thread /*! \~english Timer works in his own thread. Intervals are measured by the system time \~russian Таймер работает в собственном потоке. Интервалы измеряются с помощью системного времени */ = 0x01, ThreadRT /*! \~english Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS! \~russian Использовать таймер POSIX с SIGEV_THREAD уведомлением. \attention Не поддерживается на Windows и Mac OS! */ = 0x02, Pool /*! \~english Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and sequentially executes all timers. \attention Use this implementation with care! \~russian Использовать единый TimerPool для всех таймеров с этой реализацией. TimerPool реализован через Thread и последовательно исполняет все таймеры. \attention Осторожнее с этой реализацией! */ = 0x04 }; //! \~english Constructs timer with "ti" implementation //! \~russian Создает таймер с реализацией "ti" explicit PITimer(TimerImplementation ti); //! \~english Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation //! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti" explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread); //! \~english Constructs timer with "slot" slot void(), and "ti" implementation //! \~russian Создает таймер со слотом "slot" и реализацией "ti" explicit PITimer(std::function slot, TimerImplementation ti = Thread); //! \~english Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation //! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti" explicit PITimer(std::function slot, void * data, TimerImplementation ti = Thread); virtual ~PITimer(); //! \~english Returns timer implementation //! \~russian Возвращает реализацию таймера PITimer::TimerImplementation implementation() const { return imp_mode; } //! \~english Returns timer loop delay in milliseconds //! \~russian Возвращает задержку цикла таймера в миллисекундах double interval() const; EVENT_HANDLER1(void, setInterval, double, ms); //! \~english Returns if timer is started //! \~russian Возвращает работает ли таймер bool isRunning() const; //! \~english Returns if timer is not started //! \~russian Возвращает остановлен ли таймер bool isStopped() const; EVENT_HANDLER0(bool, start); EVENT_HANDLER1(bool, start, double, interval_ms_d); bool start(int interval_ms_i); EVENT_HANDLER0(bool, restart); //! \~english Start timer with \a interval() loop delay after "delay_msecs" delay //! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs" void startDeferred(double delay_ms); //! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay //! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs" void startDeferred(double interval_ms, double delay_ms); //! \~english Start timer with \a interval() loop delay after "start_datetime" date and time //! \~russian Запускает таймер с интервалом \a interval() после наступления "start_datetime" void startDeferred(PIDateTime start_datetime); //! \~english Start timer with "interval_msecs" loop delay after "start_datetime" date and time //! \~russian Запускает таймер с интервалом "interval_msecs" после наступления "start_datetime" void startDeferred(double interval_ms, PIDateTime start_datetime); EVENT_HANDLER0(bool, stop); //! \~english Set custom data //! \~russian Установить данные, передаваемые в метод таймера void setData(void * data_) { data_t = data_; } //! \~english Returns common data passed to tick functions //! \~russian Возвращает данные, передаваемые в метод таймера void * data() const { return data_t; } //! \~english Set timer tick function //! \~russian Установить вызываемый метод void setSlot(TimerEvent slot) { ret_func = slot; } //! \~english Set timer tick function //! \~russian Установить вызываемый метод void setSlot(std::function slot) { ret_func = [slot](void *, int) { slot(); }; } //! \~english Set timer tick function //! \~russian Установить вызываемый метод void setSlot(std::function slot) { ret_func = [slot](void * d, int) { slot(d); }; } void needLockRun(bool need) { lockRun = need; } EVENT_HANDLER0(void, lock) { mutex_.lock(); } EVENT_HANDLER0(void, unlock) { mutex_.unlock(); } //! \~english Returns if timer should exec \a maybeCallQueuedEvents() at every tick. By default \b true //! \~russian Возвращает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик. По умолчанию \b true bool isCallQueuedEvents() const { return callEvents; } //! \~english Set timer exec \a maybeCallQueuedEvents() at every tick //! \~russian Установает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик void setCallQueuedEvents(bool yes) { callEvents = yes; } //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" void addDelimiter(int delim, TimerEvent slot = 0) { delims << Delimiter(slot, delim); } //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" void addDelimiter(int delim, std::function slot) { delims << Delimiter([slot](void *, int) { slot(); }, delim); } //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" void addDelimiter(int delim, std::function slot) { delims << Delimiter([slot](void * d, int) { slot(d); }, delim); } //! \~english Remove all frequency delimiters "delim" //! \~russian Удаляет все делители частоты "delim" void removeDelimiter(int delim) { for (int i = 0; i < delims.size_s(); ++i) if (delims[i].delim == delim) { delims.remove(i); i--; } } EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); } EVENT2(tickEvent, void *, data_, int, delimiter); //! \handlers //! \{ //! \fn void setInterval(double ms) //! \brief //! \~english Set timer loop delay in milliseconds //! \~russian Установить интервал таймера "ms" миллисекунд //! \fn bool start() //! \brief //! \~english Start timer with \a interval() loop delay //! \~russian Запустить таймер с интервалом \a interval() //! \~\details //! \~english //! Start execution of timer functions with frequency = 1 / msecs Hz //! \~russian //! Запускает таймер с частотой = 1 / msecs Гц //! \fn bool start(double msecs) //! \brief //! \~english Start timer with "msecs" loop delay //! \~russian Запустить таймер с интервалом "msecs" //! \~\details //! \~english //! Start execution of timer functions with frequency = 1. / msecs Hz. //! Instead of \a start(int msecs) this function allow start timer //! with frequencies more than 1 kHz //! \~russian //! Запускает таймер с частотой = 1 / msecs Гц. В отличии от //! \a start(int msecs) этот метод позволяет запустить таймер с частотой //! более 1 кГц //! \fn bool restart() //! \brief //! \~english Stop and start timer with \a interval() loop delay //! \~russian Остановить и запустить таймер с интервалом \a interval() //! \fn bool stop(bool wait = true) //! \brief //! \~english Stop timer and wait for it finish if "wait" //! \~russian Остановить таймер и если "wait" то дождаться остановки //! \fn void clearDelimiters() //! \brief //! \~english Remove all frequency delimiters //! \~russian Удаляет все делители частоты //! \} //! \events //! \{ //! \fn void tickEvent(void * data, int delimiter) //! \brief //! \~english Raise on timer tick //! \~russian Вызывается каждый тик таймера //! \~\details //! \~english //! "data" can be set with function \a setData() or from constructor. //! "delimiter" is frequency delimiter, 1 for main loop. //! \~russian //! "data" устанавливается методом \a setData() или в конструкторе. //! "delimiter" - делитель частоты, 1 для основного цикла //! \} protected: struct PIP_EXPORT Delimiter { Delimiter(TimerEvent slot_ = 0, int delim_ = 1) { slot = slot_; delim = delim_; tick = 0; } TimerEvent slot; int delim; int tick; }; void initFirst(); void init() const; void destroy(); static void tickImpS(PITimer * t) { t->tickImp(); } void tickImp(); //! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing virtual void tick(void * data_, int delimiter) {} void * data_t; std::atomic_bool lockRun, callEvents; PIMutex mutex_; TimerEvent ret_func; TimerImplementation imp_mode; PIVector delims; mutable _PITimerBase * imp; }; #endif // PITIMER_H