diff --git a/CMakeLists.txt b/CMakeLists.txt index da19081d..7e342b7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(PIP) set(PIP_MAJOR 3) -set(PIP_MINOR 20) +set(PIP_MINOR 21) set(PIP_REVISION 0) set(PIP_SUFFIX ) set(PIP_COMPANY SHS) diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index b517bbdb..5f3c259b 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -226,6 +226,11 @@ void PIIODevice::stopThreadedRead() { } +void PIIODevice::terminateThreadedRead() { + read_thread.terminate(); +} + + bool PIIODevice::waitThreadedReadFinished(int timeout_ms) { return read_thread.waitForFinish(timeout_ms); } @@ -247,6 +252,11 @@ void PIIODevice::stopThreadedWrite() { } +void PIIODevice::terminateThreadedWrite() { + write_thread.terminate(); +} + + bool PIIODevice::waitThreadedWriteFinished(int timeout_ms) { return write_thread.waitForFinish(timeout_ms); } diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index c434e82f..667a8e62 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -205,6 +205,10 @@ public: //! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно void setReopenTimeout(int msecs); + //! \~english Set timeout between \a open() tryings if reopen is enabled + //! \~russian Устанавливает задержку между вызовами \a open() если переоткрытие активно + void setReopenTimeout(PISystemTime timeout) { setReopenTimeout(timeout.toMilliseconds()); } + //! \~english Returns reopen enable //! \~russian Возвращает активно ли переоткрытие bool isReopenEnabled() const { return property("reopenEnabled").toBool(); } @@ -255,10 +259,21 @@ public: //! \~russian Останавливает потоковое чтение. void stopThreadedRead(); + //! \~english Terminate threaded read. + //! \~russian Прерывает потоковое чтение. + //! \~\warning + //! \~english Try not to use! This method may cause memory corruption! + //! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти! + void terminateThreadedRead(); + //! \~english Wait for threaded read finish no longer than "timeout_ms" milliseconds. //! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд. bool waitThreadedReadFinished(int timeout_ms = -1); + //! \~english Wait for threaded read finish no longer than "timeout". + //! \~russian Ожидает завершения потокового чтения в течении не более "timeout". + bool waitThreadedReadFinished(PISystemTime timeout) { return waitThreadedReadFinished(timeout.toMilliseconds()); } + //! \~english Returns if threaded write is started //! \~russian Возвращает запущен ли поток записи @@ -272,10 +287,21 @@ public: //! \~russian Останавливает потоковую запись. void stopThreadedWrite(); + //! \~english Terminate threaded write. + //! \~russian Прерывает потоковую запись. + //! \~\warning + //! \~english Try not to use! This method may cause memory corruption! + //! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти! + void terminateThreadedWrite(); + //! \~english Wait for threaded write finish no longer than "timeout_ms" milliseconds. //! \~russian Ожидает завершения потоковой записи в течении не более "timeout_ms" миллисекунд. bool waitThreadedWriteFinished(int timeout_ms = -1); + //! \~english Wait for threaded write finish no longer than "timeout". + //! \~russian Ожидает завершения потоковой записи в течении не более "timeout". + bool waitThreadedWriteFinished(PISystemTime timeout) { return waitThreadedWriteFinished(timeout.toMilliseconds()); } + //! \~english Clear threaded write task queue //! \~russian Очищает очередь потоковой записи void clearThreadedWriteQueue(); @@ -293,6 +319,10 @@ public: //! \~russian Останавливает потоковое чтение и запись и ожидает завершения. void stopAndWait(int timeout_ms = -1); + //! \~english Stop both threaded read and threaded write and wait for finish. + //! \~russian Останавливает потоковое чтение и запись и ожидает завершения. + void stopAndWait(PISystemTime timeout) { return stopAndWait(timeout.toMilliseconds()); } + //! \~english Interrupt blocking operation. //! \~russian Прерывает блокирующую операцию. virtual void interrupt() {} @@ -331,6 +361,10 @@ public: //! Таймаут должен быть больше 0 PIByteArray readForTime(double timeout_ms); + //! \~english Read from device for "timeout" and return readed data as PIByteArray. + //! \~russian Читает из устройства в течении "timeout" и возвращает данные как PIByteArray. + PIByteArray readForTime(PISystemTime timeout) { return readForTime(timeout.toMilliseconds()); } + //! \~english Add task to threaded write queue and return task ID //! \~russian Добавляет данные в очередь на потоковую запись и возвращает ID задания @@ -500,14 +534,14 @@ protected: //! \~english Reimplement this function to read from your device //! \~russian Переопределите для чтения данных из устройства virtual ssize_t readDevice(void * read_to, ssize_t max_size) { - piCoutObj << "\"read\" is not implemented!"; + piCoutObj << "\"readDevice\" is not implemented!"; return -2; } //! \~english Reimplement this function to write to your device //! \~russian Переопределите для записи данных в устройство virtual ssize_t writeDevice(const void * data, ssize_t max_size) { - piCoutObj << "\"write\" is not implemented!"; + piCoutObj << "\"writeDevice\" is not implemented!"; return -2; } @@ -555,7 +589,7 @@ protected: bool isThreadedReadStopping() const { return read_thread.isStopping(); } - DeviceMode mode_; + DeviceMode mode_ = ReadOnly; DeviceOptions options_; ReadRetFunc func_read = nullptr; std::atomic_bool opened_; diff --git a/libs/main/io_utils/pidiagnostics.cpp b/libs/main/io_utils/pidiagnostics.cpp index 2d8575ca..21beb7d5 100644 --- a/libs/main/io_utils/pidiagnostics.cpp +++ b/libs/main/io_utils/pidiagnostics.cpp @@ -38,24 +38,11 @@ PIDiagnostics::State::State() { - immediate_freq = integral_freq = 0.f; - received_packets_per_sec = 0ull; - received_packets = 0ull; - received_packets_wrong = 0ull; - received_bytes_per_sec = 0ull; - received_bytes = 0ull; - received_bytes_wrong = 0ull; - sended_packets_per_sec = 0ull; - sended_packets = 0ull; - sended_bytes_per_sec = 0ull; - sended_bytes = 0ull; receive_speed = send_speed = PIString::readableSize(0) + "/s"; - quality = PIDiagnostics::Unknown; } PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) { - disconn_ = 0.; // piCout << "PIDiagnostics construct"; setInterval(100); reset(); @@ -104,6 +91,20 @@ PIString PIDiagnostics::sendSpeed() const { } +void PIDiagnostics::start() { + PITimer::start(100.); + changeDisconnectTimeout(disconn_); +} + + +void PIDiagnostics::start(double msecs) { + if (msecs > 0.) { + PITimer::start(msecs); + changeDisconnectTimeout(disconn_); + } +} + + void PIDiagnostics::reset() { mutex_state.lock(); cur_state = State(); diff --git a/libs/main/io_utils/pidiagnostics.h b/libs/main/io_utils/pidiagnostics.h index 3cab63f4..9140903c 100644 --- a/libs/main/io_utils/pidiagnostics.h +++ b/libs/main/io_utils/pidiagnostics.h @@ -54,24 +54,23 @@ public: //! Information about current diagnostics state struct PIP_EXPORT State { State(); - float immediate_freq; - float integral_freq; - ullong received_packets_per_sec; - ullong received_packets; - ullong received_packets_wrong; - ullong received_bytes_per_sec; - ullong received_bytes; - ullong received_bytes_wrong; - ullong sended_packets_per_sec; - ullong sended_packets; - ullong sended_bytes_per_sec; - ullong sended_bytes; + float immediate_freq = 0.f; + float integral_freq = 0.f; + ullong received_packets_per_sec = 0ull; + ullong received_packets = 0ull; + ullong received_packets_wrong = 0ull; + ullong received_bytes_per_sec = 0ull; + ullong received_bytes = 0ull; + ullong received_bytes_wrong = 0ull; + ullong sended_packets_per_sec = 0ull; + ullong sended_packets = 0ull; + ullong sended_bytes_per_sec = 0ull; + ullong sended_bytes = 0ull; PIString receive_speed; PIString send_speed; - PIDiagnostics::Quality quality; + PIDiagnostics::Quality quality = PIDiagnostics::Unknown; }; - //! Returns current state PIDiagnostics::State state() const; @@ -81,6 +80,9 @@ public: //! Returns period of full disconnect in seconds and period of averaging frequency void setDisconnectTimeout(float s) { setProperty("disconnectTimeout", s); } + //! Returns period of full disconnect and period of averaging frequency + void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm.toSeconds()); } + //! Returns connection quality PIDiagnostics::Quality quality() const; @@ -91,16 +93,8 @@ public: PIString sendSpeed() const; - EVENT_HANDLER0(void, start) { - PITimer::start(100.); - changeDisconnectTimeout(disconn_); - } - EVENT_HANDLER1(void, start, double, msecs) { - if (msecs > 0.) { - PITimer::start(msecs); - changeDisconnectTimeout(disconn_); - } - } + EVENT_HANDLER0(void, start); + EVENT_HANDLER1(void, start, double, msecs); EVENT_HANDLER0(void, reset); EVENT_HANDLER1(void, received, int, size) { received(size, true); } @@ -135,16 +129,11 @@ public: private: struct PIP_EXPORT Entry { - Entry() { - bytes_ok = bytes_fail = 0; - cnt_ok = cnt_fail = 0; - empty = true; - } - ullong bytes_ok; - ullong bytes_fail; - uint cnt_ok; - uint cnt_fail; - bool empty; + ullong bytes_ok = 0; + ullong bytes_fail = 0; + uint cnt_ok = 0; + uint cnt_fail = 0; + bool empty = true; }; friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); @@ -156,7 +145,7 @@ private: void changeDisconnectTimeout(float disct); PIQueue history_rec, history_send; - float disconn_; + float disconn_ = 0.f; State cur_state; mutable PIMutex mutex_state; }; diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 14dd5061..043beb6a 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -116,7 +116,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) { //! while (isRunning()) { // while not stop() //! virtual run() //! ThreadFunc() // Slot or lambda -//! piMSleep(timer_delay) // if timer_delay > 0 +//! piMSleep(loop_delay) // if loop_delay > 0 //! } //! event stopped() //! virtual end() @@ -216,7 +216,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) { //! \~russian \section PIThread_sec1 Использование без наследования //! \~english //! You can use %PIThread without subclassing by using "ThreadFunc" pointer -//! that can be set from constructor or by overloaded function \a start(ThreadFunc func, int timer_delay). +//! that can be set from constructor or by overloaded function \a start(ThreadFunc func, int loop_delay). //! If "func" if not null this function will be executed after \a run(). //! //! ThreadFunc is any static function with format "void func(void * data)", or @@ -354,18 +354,18 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) { //! -//! \fn bool PIThread::start(int timer_delay = -1) +//! \fn bool PIThread::start(int loop_delay = -1) //! \~\details //! \~english //! Start execution of \a run() in internal loop with -//! "timer_delay" delay in milliseconds. If "timer_delay" <= 0 +//! "loop_delay" delay in milliseconds. If "loop_delay" <= 0 //! this is no delay in loop. Thread also exec external function //! set by \a setSlot() if it`s not null. //! \return \c false if thread already started or can`t start thread //! //! \~russian //! Начинает выполнение \a run() во внутреннем цикле -//! с задержкой "timer_delay" миллисекунд. Если "timer_delay" <= 0 +//! с задержкой "loop_delay" миллисекунд. Если "loop_delay" <= 0 //! то задержки не будет. Также поток вызывает внешний метод, //! заданный через \a setSlot(), если он существует. //! \return \c false если поток уже запущен или не может запуститься @@ -525,51 +525,43 @@ __PIThreadCollection_Initializer__::~__PIThreadCollection_Initializer__() { PRIVATE_DEFINITION_START(PIThread) #if defined(WINDOWS) - void * thread; + void * thread = nullptr; #elif defined(FREERTOS) TaskHandle_t thread; #else - pthread_t thread; + pthread_t thread = 0; sched_param sparam; #endif PRIVATE_DEFINITION_END(PIThread) -PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay): PIObject() { +PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int loop_delay): PIObject() { PIINTROSPECTION_THREAD_NEW(this); - tid_ = -1; - PRIVATE->thread = 0; - data_ = data; - ret_func = func; + data_ = data; + ret_func = func; terminating = running_ = lockRun = false; priority_ = piNormal; - delay_ = timer_delay; - if (startNow) start(timer_delay); + delay_ = loop_delay; + if (startNow) start(loop_delay); } -PIThread::PIThread(std::function func, bool startNow, int timer_delay) { +PIThread::PIThread(std::function func, bool startNow, int loop_delay) { PIINTROSPECTION_THREAD_NEW(this); - tid_ = -1; - PRIVATE->thread = 0; - data_ = 0; - ret_func = [func](void *) { func(); }; + ret_func = [func](void *) { func(); }; terminating = running_ = lockRun = false; priority_ = piNormal; - delay_ = timer_delay; - if (startNow) start(timer_delay); + delay_ = loop_delay; + if (startNow) start(loop_delay); } -PIThread::PIThread(bool startNow, int timer_delay): PIObject() { +PIThread::PIThread(bool startNow, int loop_delay): PIObject() { PIINTROSPECTION_THREAD_NEW(this); - tid_ = -1; - PRIVATE->thread = 0; - ret_func = 0; terminating = running_ = lockRun = false; priority_ = piNormal; - delay_ = timer_delay; - if (startNow) start(timer_delay); + delay_ = loop_delay; + if (startNow) start(loop_delay); } @@ -599,6 +591,24 @@ PIThread::~PIThread() { } +bool PIThread::start(ThreadFunc func, int loop_delay) { + ret_func = func; + return start(loop_delay); +} + + +bool PIThread::start(std::function func, int loop_delay) { + ret_func = [func](void *) { func(); }; + return start(loop_delay); +} + + +bool PIThread::startOnce(ThreadFunc func) { + ret_func = func; + return startOnce(); +} + + void PIThread::stopAndWait(int timeout_ms) { stop(); waitForFinish(timeout_ms); @@ -611,9 +621,9 @@ void PIThread::stop() { } -bool PIThread::start(int timer_delay) { +bool PIThread::start(int loop_delay) { if (running_) return false; - delay_ = timer_delay; + delay_ = loop_delay; return _startThread((void *)thread_function); } diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 6b043679..078d569b 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -104,22 +104,16 @@ public: }; EVENT_HANDLER0(bool, start) { return start(-1); } - EVENT_HANDLER1(bool, start, int, timer_delay); + EVENT_HANDLER1(bool, start, int, loop_delay); + bool start(PISystemTime loop_delay) { return start(loop_delay.toMilliseconds()); } bool start(ThreadFunc func) { return start(func, -1); } - bool start(ThreadFunc func, int timer_delay) { - ret_func = func; - return start(timer_delay); - } + bool start(ThreadFunc func, int loop_delay); + bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); } bool start(std::function func) { return start(func, -1); } - bool start(std::function func, int timer_delay) { - ret_func = [func](void *) { func(); }; - return start(timer_delay); - } + bool start(std::function func, int loop_delay); + bool start(std::function func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); } EVENT_HANDLER0(bool, startOnce); - EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) { - ret_func = func; - return startOnce(); - } + EVENT_HANDLER1(bool, startOnce, ThreadFunc, func); EVENT_HANDLER0(void, stop); EVENT_HANDLER0(void, terminate); @@ -127,6 +121,10 @@ public: //! \~russian Останавливает поток и ожидает завершения. void stopAndWait(int timeout_ms = -1); + //! \~english Stop thread and wait for finish. + //! \~russian Останавливает поток и ожидает завершения. + void stopAndWait(PISystemTime timeout) { stopAndWait(timeout.toMilliseconds()); } + //! \~english Set common data passed to external function //! \~russian Устанавливает данные, передаваемые в функцию потока void setData(void * d) { data_ = d; } @@ -200,7 +198,7 @@ public: //! \handlers //! \{ - //! \fn bool start(int timer_delay = -1) + //! \fn bool start(int loop_delay = -1) //! \brief //! \~english Start thread //! \~russian Запускает поток @@ -268,8 +266,8 @@ protected: //! \~russian Метод выполняется один раз при старте потока virtual void begin() { ; } - //! \~english Function executed at every "timer_delay" msecs until thread was stopped - //! \~russian Метод выполняется каждые "timer_delay" миллисекунд + //! \~english Function executed at every "loop_delay" msecs until thread was stopped + //! \~russian Метод выполняется каждые "loop_delay" миллисекунд virtual void run() { ; } //! \~english Function executed once at the end of thread @@ -278,12 +276,12 @@ protected: std::atomic_bool terminating, running_, lockRun; int delay_, policy_; - llong tid_; - void * data_; + llong tid_ = -1; + void * data_ = nullptr; mutable PIMutex thread_mutex; PITimeMeasurer tmf_, tms_, tmr_; - PIThread::Priority priority_; - ThreadFunc ret_func; + PIThread::Priority priority_ = piNormal; + ThreadFunc ret_func = nullptr; PRIVATE_DECLARATION(PIP_EXPORT) private: diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index 16cb36a0..f43714ff 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -120,11 +120,7 @@ _PITimerBase::_PITimerBase() { - interval_ = 1000; - deferred_delay = 0.; - running_ = deferred_ = deferred_mode = false; - tfunc = 0; - parent = 0; + running_ = false; } @@ -593,9 +589,6 @@ bool PITimer::isStopped() const { void PITimer::initFirst() { lockRun = false; callEvents = true; - data_t = 0; - ret_func = 0; - imp = 0; setProperty("interval", 0.); } @@ -714,6 +707,20 @@ void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) { } +void PITimer::addDelimiter(int delim, std::function slot) { + delims << Delimiter([slot](void * d, int) { slot(d); }, delim); +} + + +void PITimer::removeDelimiter(int delim) { + for (int i = 0; i < delims.size_s(); ++i) + if (delims[i].delim == delim) { + delims.remove(i); + i--; + } +} + + bool PITimer::restart() { init(); imp->stop(); diff --git a/libs/main/thread/pitimer.h b/libs/main/thread/pitimer.h index 1f74cba7..89daf598 100644 --- a/libs/main/thread/pitimer.h +++ b/libs/main/thread/pitimer.h @@ -57,15 +57,15 @@ public: bool stop(); typedef void (*TickFunc)(PITimer *); - TickFunc tfunc; - PITimer * parent; + TickFunc tfunc = nullptr; + PITimer * parent = nullptr; 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 + double interval_ = 1000., deferred_delay = 0.; + bool deferred_ = false, deferred_mode = false; // mode: true - date, false - delay std::atomic_bool running_; PIDateTime deferred_datetime; }; @@ -131,6 +131,7 @@ public: double interval() const; EVENT_HANDLER1(void, setInterval, double, ms); + void setInterval(PISystemTime interval) { setInterval(interval.toMilliseconds()); } //! \~english Returns if timer is started //! \~russian Возвращает работает ли таймер @@ -143,6 +144,7 @@ public: EVENT_HANDLER0(bool, start); EVENT_HANDLER1(bool, start, double, interval_ms_d); bool start(int interval_ms_i); + bool start(PISystemTime interval) { return start(interval.toMilliseconds()); } EVENT_HANDLER0(bool, restart); @@ -212,19 +214,11 @@ public: //! \~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); - } + void addDelimiter(int delim, std::function slot); //! \~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--; - } - } + void removeDelimiter(int delim); EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); } @@ -301,11 +295,10 @@ protected: Delimiter(TimerEvent slot_ = 0, int delim_ = 1) { slot = slot_; delim = delim_; - tick = 0; } TimerEvent slot; - int delim; - int tick; + int delim = 0; + int tick = 0; }; void initFirst(); @@ -318,14 +311,14 @@ protected: //! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing virtual void tick(void * data_, int delimiter) {} - void * data_t; + void * data_t = nullptr; std::atomic_bool lockRun, callEvents; PIMutex mutex_; - TimerEvent ret_func; - TimerImplementation imp_mode; + TimerEvent ret_func = nullptr; + TimerImplementation imp_mode = Thread; PIVector delims; - mutable _PITimerBase * imp; + mutable _PITimerBase * imp = nullptr; };