/*! \file pitimer.h * \brief Timer */ /* 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 . */ #ifndef PITIMER_H #define PITIMER_H #include "pithread.h" #include "pitime.h" #ifdef PIP_CXX11_SUPPORT typedef std::function TimerEvent; #else typedef void (*TimerEvent)(void *, int); #endif class PITimer; class PIP_EXPORT _PITimerBase { friend class PITimer; public: _PITimerBase(); virtual ~_PITimerBase() {} double interval() const {return interval_;} void setInterval(double i); // ! \brief Return \c true if thread is running 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(bool wait); typedef void(*TickFunc)(PITimer*); TickFunc tfunc; PITimer * parent; protected: virtual bool startTimer(double interval_ms) = 0; virtual bool stopTimer(bool wait) = 0; double interval_, deferred_delay; bool deferred_, deferred_mode; // mode: true - date, false - delay volatile bool running_; PIDateTime deferred_datetime; }; class PIP_EXPORT PITimer: public PIObject { PIOBJECT_SUBCLASS(PITimer, PIObject) public: //! \brief Constructs timer with PITimer::Thread implementation explicit PITimer(); //! \brief Timer implementations enum TimerImplementation { Thread /*! Timer works in his own thread. Intervals are measured by the system time */ = 0x01, ThreadRT /*! Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS! */ = 0x02, // SignalRT /*! */ = 0x03, Pool /*! 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! */ = 0x04 }; //! \brief Constructs timer with "ti" implementation explicit PITimer(TimerImplementation ti); //! \brief Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread); #ifdef PIP_CXX11_SUPPORT //! \brief Constructs timer with "slot" slot void(), and "ti" implementation explicit PITimer(std::function slot, TimerImplementation ti = Thread); //! \brief Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation explicit PITimer(std::function slot, void * data, TimerImplementation ti = Thread); #endif virtual ~PITimer(); //! \brief Returns timer implementation PITimer::TimerImplementation implementation() const {return imp_mode;} //! \brief Returns timer loop delay in milliseconds double interval() const; //! \brief Set timer loop delay in milliseconds EVENT_HANDLER1(void, setInterval, double, ms); //! \brief Returns if timer is started bool isRunning() const; //! \brief Returns if timer is not started 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); /** \brief Start timer with \b interval() loop delay after \b delay_msecs delay. * \details Timer wait \b delay_msecs milliseconds and then normally starts with * \b interval() loop delay. */ void startDeferred(double delay_ms); /** \brief Start timer with \b interval_msecs loop delay after \b delay_msecs delay. * \details Timer wait \b delay_msecs milliseconds and then normally starts with * \b interval_msecs loop delay. */ void startDeferred(double interval_ms, double delay_ms); /** \brief Start timer with \b interval() loop delay after \b start_datetime date and time. * \details Timer wait until \b start_datetime and then normally starts with * \b interval() loop delay. */ void startDeferred(PIDateTime start_datetime); /** \brief Start timer with \b interval_msecs loop delay after \b start_datetime date and time. * \details Timer wait until \b start_datetime and then normally starts with * \b interval_msecs loop delay. */ void startDeferred(double interval_ms, PIDateTime start_datetime); EVENT_HANDLER0(bool, stop); EVENT_HANDLER1(bool, stop, bool, wait); bool waitForFinish() {return waitForFinish(-1);} bool waitForFinish(int timeout_msecs); //! \brief Set custom data void setData(void * data_) {data_t = data_;} //! \brief Set timer tick function void setSlot(TimerEvent slot) {ret_func = slot;} #ifdef PIP_CXX11_SUPPORT //! \brief Set timer tick function void setSlot(std::function slot) {ret_func = [slot](void *, int){slot();};} //! \brief Set timer tick function void setSlot(std::function slot) {ret_func = [slot](void *d, int){slot(d);};} #endif //! \brief Returns common data passed to tick functions void * data() const {return data_t;} void needLockRun(bool need) {lockRun = need;} EVENT_HANDLER0(void, lock) {mutex_.lock();} EVENT_HANDLER0(void, unlock) {mutex_.unlock();} //! \brief Returns if timer should exec \a maybeCallQueuedEvents() at every tick. //! By default \b true bool isCallQueuedEvents() const {return callEvents;} //! \brief If set timer exec \a maybeCallQueuedEvents() at every tick. //! By default \b true void setCallQueuedEvents(bool yes) {callEvents = yes;} //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, TimerEvent slot = 0) {delims << Delimiter(slot, delim);} #ifdef PIP_CXX11_SUPPORT //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, std::function slot) {delims << Delimiter([slot](void *, int){slot();}, delim);} //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, std::function slot) {delims << Delimiter([slot](void *d, int){slot(d);}, delim);} #endif //! \brief Remove all frequency delimiters \b 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 bool start() * \brief Start timer with \a interval() loop delay * \details Start execution of timer functions with frequency = 1 / msecs Hz. */ /** \fn bool start(double msecs) * \brief Start timer with \b msecs loop delay * \details Start execution of timer functions with frequency = 1. / msecs Hz. * Instead of \a start(int msecs) function this variant allow start timer * with frequencies more than 1 kHz */ //! \fn bool restart() //! \brief Stop and start timer with \a interval() loop delay //! \fn bool stop(bool wait = true) //! \brief Stop timer and wait for it finish if "wait" //! \fn void clearDelimiters() //! \brief Remove all frequency delimiters //! \} //! \events //! \{ /** \fn void tickEvent(void * data, int delimiter) * \brief Raise on timer tick * \details \b Data can be set with function \a setData(void * data) or from constructor. * \b Delimiter is frequency delimiter, 1 for main loop. */ //! \} 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(); //! Virtual timer execution function, similar to "slot" or event \a void timeout(void * data, int delimiter). //! By default is empty. virtual void tick(void * data_, int delimiter) {} void * data_t; volatile bool lockRun, callEvents; PIMutex mutex_; TimerEvent ret_func; TimerImplementation imp_mode; PIVector delims; mutable _PITimerBase * imp; private: NO_COPY_CLASS(PITimer) }; #endif // PITIMER_H