Compare commits

3 Commits

Author SHA1 Message Date
a16e0b7659 substitution fix 2024-07-09 21:47:18 +03:00
0bafd3fa98 PIValueTree improvements: methods with path (recursive), forEachRecursive()
PIValueTreeConvertions::fromTextFile now can include other files and handle ${} substitutions
2024-07-09 21:44:30 +03:00
903b320629 version 3.21.0
add PISystemTime overload for thread/timer/io classes
2024-07-09 16:32:27 +03:00
12 changed files with 262 additions and 143 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP) project(PIP)
set(PIP_MAJOR 3) set(PIP_MAJOR 3)
set(PIP_MINOR 20) set(PIP_MINOR 21)
set(PIP_REVISION 0) set(PIP_REVISION 0)
set(PIP_SUFFIX ) set(PIP_SUFFIX )
set(PIP_COMPANY SHS) set(PIP_COMPANY SHS)

View File

@@ -226,6 +226,11 @@ void PIIODevice::stopThreadedRead() {
} }
void PIIODevice::terminateThreadedRead() {
read_thread.terminate();
}
bool PIIODevice::waitThreadedReadFinished(int timeout_ms) { bool PIIODevice::waitThreadedReadFinished(int timeout_ms) {
return read_thread.waitForFinish(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) { bool PIIODevice::waitThreadedWriteFinished(int timeout_ms) {
return write_thread.waitForFinish(timeout_ms); return write_thread.waitForFinish(timeout_ms);
} }

View File

@@ -205,6 +205,10 @@ public:
//! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно //! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно
void setReopenTimeout(int msecs); 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 //! \~english Returns reopen enable
//! \~russian Возвращает активно ли переоткрытие //! \~russian Возвращает активно ли переоткрытие
bool isReopenEnabled() const { return property("reopenEnabled").toBool(); } bool isReopenEnabled() const { return property("reopenEnabled").toBool(); }
@@ -255,10 +259,21 @@ public:
//! \~russian Останавливает потоковое чтение. //! \~russian Останавливает потоковое чтение.
void stopThreadedRead(); 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. //! \~english Wait for threaded read finish no longer than "timeout_ms" milliseconds.
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд. //! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд.
bool waitThreadedReadFinished(int timeout_ms = -1); 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 //! \~english Returns if threaded write is started
//! \~russian Возвращает запущен ли поток записи //! \~russian Возвращает запущен ли поток записи
@@ -272,10 +287,21 @@ public:
//! \~russian Останавливает потоковую запись. //! \~russian Останавливает потоковую запись.
void stopThreadedWrite(); 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. //! \~english Wait for threaded write finish no longer than "timeout_ms" milliseconds.
//! \~russian Ожидает завершения потоковой записи в течении не более "timeout_ms" миллисекунд. //! \~russian Ожидает завершения потоковой записи в течении не более "timeout_ms" миллисекунд.
bool waitThreadedWriteFinished(int timeout_ms = -1); 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 //! \~english Clear threaded write task queue
//! \~russian Очищает очередь потоковой записи //! \~russian Очищает очередь потоковой записи
void clearThreadedWriteQueue(); void clearThreadedWriteQueue();
@@ -293,6 +319,10 @@ public:
//! \~russian Останавливает потоковое чтение и запись и ожидает завершения. //! \~russian Останавливает потоковое чтение и запись и ожидает завершения.
void stopAndWait(int timeout_ms = -1); 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. //! \~english Interrupt blocking operation.
//! \~russian Прерывает блокирующую операцию. //! \~russian Прерывает блокирующую операцию.
virtual void interrupt() {} virtual void interrupt() {}
@@ -331,6 +361,10 @@ public:
//! Таймаут должен быть больше 0 //! Таймаут должен быть больше 0
PIByteArray readForTime(double timeout_ms); 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 //! \~english Add task to threaded write queue and return task ID
//! \~russian Добавляет данные в очередь на потоковую запись и возвращает ID задания //! \~russian Добавляет данные в очередь на потоковую запись и возвращает ID задания
@@ -500,14 +534,14 @@ protected:
//! \~english Reimplement this function to read from your device //! \~english Reimplement this function to read from your device
//! \~russian Переопределите для чтения данных из устройства //! \~russian Переопределите для чтения данных из устройства
virtual ssize_t readDevice(void * read_to, ssize_t max_size) { virtual ssize_t readDevice(void * read_to, ssize_t max_size) {
piCoutObj << "\"read\" is not implemented!"; piCoutObj << "\"readDevice\" is not implemented!";
return -2; return -2;
} }
//! \~english Reimplement this function to write to your device //! \~english Reimplement this function to write to your device
//! \~russian Переопределите для записи данных в устройство //! \~russian Переопределите для записи данных в устройство
virtual ssize_t writeDevice(const void * data, ssize_t max_size) { virtual ssize_t writeDevice(const void * data, ssize_t max_size) {
piCoutObj << "\"write\" is not implemented!"; piCoutObj << "\"writeDevice\" is not implemented!";
return -2; return -2;
} }
@@ -555,7 +589,7 @@ protected:
bool isThreadedReadStopping() const { return read_thread.isStopping(); } bool isThreadedReadStopping() const { return read_thread.isStopping(); }
DeviceMode mode_; DeviceMode mode_ = ReadOnly;
DeviceOptions options_; DeviceOptions options_;
ReadRetFunc func_read = nullptr; ReadRetFunc func_read = nullptr;
std::atomic_bool opened_; std::atomic_bool opened_;

View File

@@ -38,24 +38,11 @@
PIDiagnostics::State::State() { 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"; receive_speed = send_speed = PIString::readableSize(0) + "/s";
quality = PIDiagnostics::Unknown;
} }
PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) { PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) {
disconn_ = 0.;
// piCout << "PIDiagnostics construct"; // piCout << "PIDiagnostics construct";
setInterval(100); setInterval(100);
reset(); 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() { void PIDiagnostics::reset() {
mutex_state.lock(); mutex_state.lock();
cur_state = State(); cur_state = State();

View File

@@ -54,24 +54,23 @@ public:
//! Information about current diagnostics state //! Information about current diagnostics state
struct PIP_EXPORT State { struct PIP_EXPORT State {
State(); State();
float immediate_freq; float immediate_freq = 0.f;
float integral_freq; float integral_freq = 0.f;
ullong received_packets_per_sec; ullong received_packets_per_sec = 0ull;
ullong received_packets; ullong received_packets = 0ull;
ullong received_packets_wrong; ullong received_packets_wrong = 0ull;
ullong received_bytes_per_sec; ullong received_bytes_per_sec = 0ull;
ullong received_bytes; ullong received_bytes = 0ull;
ullong received_bytes_wrong; ullong received_bytes_wrong = 0ull;
ullong sended_packets_per_sec; ullong sended_packets_per_sec = 0ull;
ullong sended_packets; ullong sended_packets = 0ull;
ullong sended_bytes_per_sec; ullong sended_bytes_per_sec = 0ull;
ullong sended_bytes; ullong sended_bytes = 0ull;
PIString receive_speed; PIString receive_speed;
PIString send_speed; PIString send_speed;
PIDiagnostics::Quality quality; PIDiagnostics::Quality quality = PIDiagnostics::Unknown;
}; };
//! Returns current state //! Returns current state
PIDiagnostics::State state() const; PIDiagnostics::State state() const;
@@ -81,6 +80,9 @@ public:
//! Returns period of full disconnect in seconds and period of averaging frequency //! Returns period of full disconnect in seconds and period of averaging frequency
void setDisconnectTimeout(float s) { setProperty("disconnectTimeout", s); } 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 //! Returns connection quality
PIDiagnostics::Quality quality() const; PIDiagnostics::Quality quality() const;
@@ -91,16 +93,8 @@ public:
PIString sendSpeed() const; PIString sendSpeed() const;
EVENT_HANDLER0(void, start) { EVENT_HANDLER0(void, start);
PITimer::start(100.); EVENT_HANDLER1(void, start, double, msecs);
changeDisconnectTimeout(disconn_);
}
EVENT_HANDLER1(void, start, double, msecs) {
if (msecs > 0.) {
PITimer::start(msecs);
changeDisconnectTimeout(disconn_);
}
}
EVENT_HANDLER0(void, reset); EVENT_HANDLER0(void, reset);
EVENT_HANDLER1(void, received, int, size) { received(size, true); } EVENT_HANDLER1(void, received, int, size) { received(size, true); }
@@ -135,16 +129,11 @@ public:
private: private:
struct PIP_EXPORT Entry { struct PIP_EXPORT Entry {
Entry() { ullong bytes_ok = 0;
bytes_ok = bytes_fail = 0; ullong bytes_fail = 0;
cnt_ok = cnt_fail = 0; uint cnt_ok = 0;
empty = true; uint cnt_fail = 0;
} bool empty = true;
ullong bytes_ok;
ullong bytes_fail;
uint cnt_ok;
uint cnt_fail;
bool empty;
}; };
friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
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); void changeDisconnectTimeout(float disct);
PIQueue<Entry> history_rec, history_send; PIQueue<Entry> history_rec, history_send;
float disconn_; float disconn_ = 0.f;
State cur_state; State cur_state;
mutable PIMutex mutex_state; mutable PIMutex mutex_state;
}; };

View File

@@ -127,9 +127,10 @@ PIValueTree prepareFromText(const PIValueTree & root) {
PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) { PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
PIValueTree ret; PIValueTree ret;
PIMap<PIString, PIString> substitutions;
if (!device) return ret; if (!device) return ret;
PIString base_path; PIString base_path;
if (device->isTypeOf<PIFile>()) base_path = PIFile::FileInfo(device->path()).dir(); if (device->isTypeOf<PIFile>()) base_path = PIFile::FileInfo(device->path()).dir().replaceAll('\\', '/');
PIIOTextStream ts(device); PIIOTextStream ts(device);
PIString line, comm; PIString line, comm;
PIVariant value; PIVariant value;
@@ -165,6 +166,7 @@ PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
if (ind > 0) if (ind > 0)
if (line[ind - 1] == '\\') continue; if (line[ind - 1] == '\\') continue;
cind = ind; cind = ind;
break;
} }
if (cind >= 0) { if (cind >= 0) {
comm = line.takeMid(cind + 1); comm = line.takeMid(cind + 1);
@@ -192,32 +194,37 @@ PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
comm.trim(); comm.trim();
line.cutRight(1).trim(); line.cutRight(1).trim();
} }
for (const auto & s: substitutions)
line.replaceAll("${" + s.first + "}", s.second);
ind = line.find('='); ind = line.find('=');
if (ind > 0) { if (ind > 0) {
path = prefix; path = prefix;
path << line.takeLeft(ind).split('.').trim(); path << line.takeLeft(ind).split('.').trim();
line.cutLeft(1).trim(); line.cutLeft(1).trim();
if (path.front() == "include") { if (path.front() == "include") {
/*name = line.mid(ind + 1).trimmed(); PIString include = line.trimmed();
PIConfig * iconf = new PIConfig(name, incdirs); if (!PIFile::FileInfo(include).isAbsolute()) {
//piCout << "include" << name << iconf->dev; include = base_path + "/" + include.replaceAll('\\', '/');
if (!iconf->dev) { include.replaceAll("//", '/');
delete iconf;
} else {
inc_devs << iconf;
includes << iconf << iconf->includes;
updateIncludes();
} }
other.back() = src;*/ PIValueTree inc_vt = PIValueTreeConversions::fromTextFile(include);
inc_vt.forEachRecursive(
[&substitutions](const PIValueTree & v, const PIString & fn) { substitutions[fn] = v.value().toString(); });
path.clear();
} }
} else { } else {
line.clear(); line.clear();
continue; continue;
} }
// piCout << path << line << comm; // piCout << path << line << comm;
if (path.isEmpty()) {
line.clear();
continue;
}
PIValueTree & leaf(ret[path]); PIValueTree & leaf(ret[path]);
leaf.setComment(comm); leaf.setComment(comm);
leaf.setValue(unmask(line)); leaf.setValue(unmask(line));
substitutions[path.join('.')] = leaf.value().toString();
if (!path.contains(_attribute_)) if (!path.contains(_attribute_))
if (!leaf.contains({_attribute_, "type"})) leaf[_attribute_].addChild({"type", type}); if (!leaf.contains({_attribute_, "type"})) leaf[_attribute_].addChild({"type", type});
line.clear(); line.clear();

View File

@@ -116,7 +116,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {
//! while (isRunning()) { // while not stop() //! while (isRunning()) { // while not stop()
//! virtual run() //! virtual run()
//! ThreadFunc() // Slot or lambda //! ThreadFunc() // Slot or lambda
//! piMSleep(timer_delay) // if timer_delay > 0 //! piMSleep(loop_delay) // if loop_delay > 0
//! } //! }
//! event stopped() //! event stopped()
//! virtual end() //! virtual end()
@@ -216,7 +216,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {
//! \~russian \section PIThread_sec1 Использование без наследования //! \~russian \section PIThread_sec1 Использование без наследования
//! \~english //! \~english
//! You can use %PIThread without subclassing by using "ThreadFunc" pointer //! 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(). //! 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 //! 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 //! \~\details
//! \~english //! \~english
//! Start execution of \a run() in internal loop with //! 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 //! this is no delay in loop. Thread also exec external function
//! set by \a setSlot() if it`s not null. //! set by \a setSlot() if it`s not null.
//! \return \c false if thread already started or can`t start thread //! \return \c false if thread already started or can`t start thread
//! //!
//! \~russian //! \~russian
//! Начинает выполнение \a run() во внутреннем цикле //! Начинает выполнение \a run() во внутреннем цикле
//! с задержкой "timer_delay" миллисекунд. Если "timer_delay" <= 0 //! с задержкой "loop_delay" миллисекунд. Если "loop_delay" <= 0
//! то задержки не будет. Также поток вызывает внешний метод, //! то задержки не будет. Также поток вызывает внешний метод,
//! заданный через \a setSlot(), если он существует. //! заданный через \a setSlot(), если он существует.
//! \return \c false если поток уже запущен или не может запуститься //! \return \c false если поток уже запущен или не может запуститься
@@ -525,51 +525,43 @@ __PIThreadCollection_Initializer__::~__PIThreadCollection_Initializer__() {
PRIVATE_DEFINITION_START(PIThread) PRIVATE_DEFINITION_START(PIThread)
#if defined(WINDOWS) #if defined(WINDOWS)
void * thread; void * thread = nullptr;
#elif defined(FREERTOS) #elif defined(FREERTOS)
TaskHandle_t thread; TaskHandle_t thread;
#else #else
pthread_t thread; pthread_t thread = 0;
sched_param sparam; sched_param sparam;
#endif #endif
PRIVATE_DEFINITION_END(PIThread) 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); PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1; data_ = data;
PRIVATE->thread = 0; ret_func = func;
data_ = data;
ret_func = func;
terminating = running_ = lockRun = false; terminating = running_ = lockRun = false;
priority_ = piNormal; priority_ = piNormal;
delay_ = timer_delay; delay_ = loop_delay;
if (startNow) start(timer_delay); if (startNow) start(loop_delay);
} }
PIThread::PIThread(std::function<void()> func, bool startNow, int timer_delay) { PIThread::PIThread(std::function<void()> func, bool startNow, int loop_delay) {
PIINTROSPECTION_THREAD_NEW(this); PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1; ret_func = [func](void *) { func(); };
PRIVATE->thread = 0;
data_ = 0;
ret_func = [func](void *) { func(); };
terminating = running_ = lockRun = false; terminating = running_ = lockRun = false;
priority_ = piNormal; priority_ = piNormal;
delay_ = timer_delay; delay_ = loop_delay;
if (startNow) start(timer_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); PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1;
PRIVATE->thread = 0;
ret_func = 0;
terminating = running_ = lockRun = false; terminating = running_ = lockRun = false;
priority_ = piNormal; priority_ = piNormal;
delay_ = timer_delay; delay_ = loop_delay;
if (startNow) start(timer_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<void()> 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) { void PIThread::stopAndWait(int timeout_ms) {
stop(); stop();
waitForFinish(timeout_ms); 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; if (running_) return false;
delay_ = timer_delay; delay_ = loop_delay;
return _startThread((void *)thread_function); return _startThread((void *)thread_function);
} }

View File

@@ -104,22 +104,16 @@ public:
}; };
EVENT_HANDLER0(bool, start) { return start(-1); } 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) { return start(func, -1); }
bool start(ThreadFunc func, int timer_delay) { bool start(ThreadFunc func, int loop_delay);
ret_func = func; bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
return start(timer_delay);
}
bool start(std::function<void()> func) { return start(func, -1); } bool start(std::function<void()> func) { return start(func, -1); }
bool start(std::function<void()> func, int timer_delay) { bool start(std::function<void()> func, int loop_delay);
ret_func = [func](void *) { func(); }; bool start(std::function<void()> func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
return start(timer_delay);
}
EVENT_HANDLER0(bool, startOnce); EVENT_HANDLER0(bool, startOnce);
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) { EVENT_HANDLER1(bool, startOnce, ThreadFunc, func);
ret_func = func;
return startOnce();
}
EVENT_HANDLER0(void, stop); EVENT_HANDLER0(void, stop);
EVENT_HANDLER0(void, terminate); EVENT_HANDLER0(void, terminate);
@@ -127,6 +121,10 @@ public:
//! \~russian Останавливает поток и ожидает завершения. //! \~russian Останавливает поток и ожидает завершения.
void stopAndWait(int timeout_ms = -1); 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 //! \~english Set common data passed to external function
//! \~russian Устанавливает данные, передаваемые в функцию потока //! \~russian Устанавливает данные, передаваемые в функцию потока
void setData(void * d) { data_ = d; } void setData(void * d) { data_ = d; }
@@ -200,7 +198,7 @@ public:
//! \handlers //! \handlers
//! \{ //! \{
//! \fn bool start(int timer_delay = -1) //! \fn bool start(int loop_delay = -1)
//! \brief //! \brief
//! \~english Start thread //! \~english Start thread
//! \~russian Запускает поток //! \~russian Запускает поток
@@ -268,8 +266,8 @@ protected:
//! \~russian Метод выполняется один раз при старте потока //! \~russian Метод выполняется один раз при старте потока
virtual void begin() { ; } virtual void begin() { ; }
//! \~english Function executed at every "timer_delay" msecs until thread was stopped //! \~english Function executed at every "loop_delay" msecs until thread was stopped
//! \~russian Метод выполняется каждые "timer_delay" миллисекунд //! \~russian Метод выполняется каждые "loop_delay" миллисекунд
virtual void run() { ; } virtual void run() { ; }
//! \~english Function executed once at the end of thread //! \~english Function executed once at the end of thread
@@ -278,12 +276,12 @@ protected:
std::atomic_bool terminating, running_, lockRun; std::atomic_bool terminating, running_, lockRun;
int delay_, policy_; int delay_, policy_;
llong tid_; llong tid_ = -1;
void * data_; void * data_ = nullptr;
mutable PIMutex thread_mutex; mutable PIMutex thread_mutex;
PITimeMeasurer tmf_, tms_, tmr_; PITimeMeasurer tmf_, tms_, tmr_;
PIThread::Priority priority_; PIThread::Priority priority_ = piNormal;
ThreadFunc ret_func; ThreadFunc ret_func = nullptr;
PRIVATE_DECLARATION(PIP_EXPORT) PRIVATE_DECLARATION(PIP_EXPORT)
private: private:

View File

@@ -120,11 +120,7 @@
_PITimerBase::_PITimerBase() { _PITimerBase::_PITimerBase() {
interval_ = 1000; running_ = false;
deferred_delay = 0.;
running_ = deferred_ = deferred_mode = false;
tfunc = 0;
parent = 0;
} }
@@ -593,9 +589,6 @@ bool PITimer::isStopped() const {
void PITimer::initFirst() { void PITimer::initFirst() {
lockRun = false; lockRun = false;
callEvents = true; callEvents = true;
data_t = 0;
ret_func = 0;
imp = 0;
setProperty("interval", 0.); setProperty("interval", 0.);
} }
@@ -714,6 +707,20 @@ void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) {
} }
void PITimer::addDelimiter(int delim, std::function<void(void *)> 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() { bool PITimer::restart() {
init(); init();
imp->stop(); imp->stop();

View File

@@ -57,15 +57,15 @@ public:
bool stop(); bool stop();
typedef void (*TickFunc)(PITimer *); typedef void (*TickFunc)(PITimer *);
TickFunc tfunc; TickFunc tfunc = nullptr;
PITimer * parent; PITimer * parent = nullptr;
protected: protected:
virtual bool startTimer(double interval_ms) = 0; virtual bool startTimer(double interval_ms) = 0;
virtual bool stopTimer() = 0; virtual bool stopTimer() = 0;
double interval_, deferred_delay; double interval_ = 1000., deferred_delay = 0.;
bool deferred_, deferred_mode; // mode: true - date, false - delay bool deferred_ = false, deferred_mode = false; // mode: true - date, false - delay
std::atomic_bool running_; std::atomic_bool running_;
PIDateTime deferred_datetime; PIDateTime deferred_datetime;
}; };
@@ -131,6 +131,7 @@ public:
double interval() const; double interval() const;
EVENT_HANDLER1(void, setInterval, double, ms); EVENT_HANDLER1(void, setInterval, double, ms);
void setInterval(PISystemTime interval) { setInterval(interval.toMilliseconds()); }
//! \~english Returns if timer is started //! \~english Returns if timer is started
//! \~russian Возвращает работает ли таймер //! \~russian Возвращает работает ли таймер
@@ -143,6 +144,7 @@ public:
EVENT_HANDLER0(bool, start); EVENT_HANDLER0(bool, start);
EVENT_HANDLER1(bool, start, double, interval_ms_d); EVENT_HANDLER1(bool, start, double, interval_ms_d);
bool start(int interval_ms_i); bool start(int interval_ms_i);
bool start(PISystemTime interval) { return start(interval.toMilliseconds()); }
EVENT_HANDLER0(bool, restart); EVENT_HANDLER0(bool, restart);
@@ -212,19 +214,11 @@ public:
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, std::function<void(void *)> slot) { void addDelimiter(int delim, std::function<void(void *)> slot);
delims << Delimiter([slot](void * d, int) { slot(d); }, delim);
}
//! \~english Remove all frequency delimiters "delim" //! \~english Remove all frequency delimiters "delim"
//! \~russian Удаляет все делители частоты "delim" //! \~russian Удаляет все делители частоты "delim"
void removeDelimiter(int 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(); } EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
@@ -301,11 +295,10 @@ protected:
Delimiter(TimerEvent slot_ = 0, int delim_ = 1) { Delimiter(TimerEvent slot_ = 0, int delim_ = 1) {
slot = slot_; slot = slot_;
delim = delim_; delim = delim_;
tick = 0;
} }
TimerEvent slot; TimerEvent slot;
int delim; int delim = 0;
int tick; int tick = 0;
}; };
void initFirst(); void initFirst();
@@ -318,14 +311,14 @@ protected:
//! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing //! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing
virtual void tick(void * data_, int delimiter) {} virtual void tick(void * data_, int delimiter) {}
void * data_t; void * data_t = nullptr;
std::atomic_bool lockRun, callEvents; std::atomic_bool lockRun, callEvents;
PIMutex mutex_; PIMutex mutex_;
TimerEvent ret_func; TimerEvent ret_func = nullptr;
TimerImplementation imp_mode; TimerImplementation imp_mode = Thread;
PIVector<Delimiter> delims; PIVector<Delimiter> delims;
mutable _PITimerBase * imp; mutable _PITimerBase * imp = nullptr;
}; };

View File

@@ -125,12 +125,24 @@ void PIValueTree::applyValues(const PIValueTree & root, bool recursive) {
PIVariant PIValueTree::childValue(const PIString & child_name, const PIVariant & default_value, bool * exists) const { PIVariant PIValueTree::childValue(const PIString & child_name, const PIVariant & default_value, bool * exists) const {
if (!contains(child_name)) { const PIValueTree & node = child(child_name);
if (node.isNull()) {
if (exists) *exists = false; if (exists) *exists = false;
return default_value; return default_value;
} }
return child(child_name).value();
if (exists) *exists = true; if (exists) *exists = true;
return node.value();
}
PIVariant PIValueTree::childValue(const PIStringList & child_path, const PIVariant & default_value, bool * exists) const {
const PIValueTree & node = child(child_path);
if (node.isNull()) {
if (exists) *exists = false;
return default_value;
}
if (exists) *exists = true;
return node.value();
} }
@@ -167,6 +179,15 @@ const PIValueTree & PIValueTree::child(const PIString & name) const {
} }
const PIValueTree & PIValueTree::child(const PIStringList & path) const {
if (_is_null || path.isEmpty()) return *this;
const PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]);
return *ret;
}
PIValueTree & PIValueTree::child(const PIString & name) { PIValueTree & PIValueTree::child(const PIString & name) {
if (_is_null) return *this; if (_is_null) return *this;
for (auto & c: _children) for (auto & c: _children)
@@ -175,6 +196,15 @@ PIValueTree & PIValueTree::child(const PIString & name) {
} }
PIValueTree & PIValueTree::child(const PIStringList & path) {
if (_is_null || path.isEmpty()) return *this;
PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]);
return *ret;
}
PIValueTree & PIValueTree::insertChild(int index, const PIValueTree & n) { PIValueTree & PIValueTree::insertChild(int index, const PIValueTree & n) {
if (_is_null) return *this; if (_is_null) return *this;
for (auto & c: _children) for (auto & c: _children)
@@ -214,6 +244,11 @@ PIValueTree & PIValueTree::remove(const PIString & name) {
} }
void PIValueTree::forEachRecursive(std::function<void(const PIValueTree &, const PIString &)> func) {
forEachRecursiveInternal(func);
}
const PIStringList & PIValueTree::standardAttributes() { const PIStringList & PIValueTree::standardAttributes() {
static PIStringList ret = { static PIStringList ret = {
// clang-format off // clang-format off
@@ -293,3 +328,11 @@ PIValueTree & PIValueTree::nullValue() {
ret._is_null = true; ret._is_null = true;
return ret; return ret;
} }
void PIValueTree::forEachRecursiveInternal(std::function<void(const PIValueTree &, const PIString &)> func, PIString prefix) {
for (auto & c: _children) {
func(c, prefix + c.name());
c.forEachRecursiveInternal(func, c.name() + ".");
}
}

View File

@@ -191,6 +191,17 @@ public:
//! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае. //! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае.
PIVariant childValue(const PIString & child_name, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const; PIVariant childValue(const PIString & child_name, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const;
//! \~\brief
//! \~english Returns the value of a child node with a given path.
//! \param child_path The path of the child node.
//! \param default_value The default value to be returned if the child node is not found.
//! \param exists If not null, set to true if the child node exists, false otherwise.
//! \~russian Возвращает значение дочернего элемента с заданным путем.
//! \param child_path Путь дочернего узла.
//! \param default_value Значение по умолчанию, которое будет возвращено, если дочерний узел не найден.
//! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае.
PIVariant childValue(const PIStringList & child_path, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const;
//! \~\brief //! \~\brief
//! \~english Reads the value of a child node with a given name into "read_to". Returns a reference to the current %PIValueTree object. //! \~english Reads the value of a child node with a given name into "read_to". Returns a reference to the current %PIValueTree object.
//! \~russian Читает значение дочернего элемента с заданным именем в "read_to". Возвращает ссылку на текущий объект %PIValueTree. //! \~russian Читает значение дочернего элемента с заданным именем в "read_to". Возвращает ссылку на текущий объект %PIValueTree.
@@ -220,11 +231,21 @@ public:
//! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
const PIValueTree & child(const PIString & name) const; const PIValueTree & child(const PIString & name) const;
//! \~\brief
//! \~english Returns a const reference to the child node with a given path, or null node if it doesn`t exists.
//! \~russian Возвращает константную ссылку на дочерний узел с заданным путем или пустой узел, если его нет.
const PIValueTree & child(const PIStringList & path) const;
//! \~\brief //! \~\brief
//! \~english Returns a reference to the child node with a given name, or null node if it doesn`t exists. //! \~english Returns a reference to the child node with a given name, or null node if it doesn`t exists.
//! \~russian Возвращает ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
PIValueTree & child(const PIString & name); PIValueTree & child(const PIString & name);
//! \~\brief
//! \~english Returns a reference to the child node with a given path, or null node if it doesn`t exists.
//! \~russian Возвращает ссылку на дочерний узел с заданным путем или пустой узел, если его нет.
PIValueTree & child(const PIStringList & path);
//! \~\brief //! \~\brief
//! \~english Inserts a node at a given index. Returns a reference to the current %PIValueTree object. //! \~english Inserts a node at a given index. Returns a reference to the current %PIValueTree object.
//! \~russian Вставляет узел в заданном индексе. Возвращает ссылку на текущий объект %PIValueTree. //! \~russian Вставляет узел в заданном индексе. Возвращает ссылку на текущий объект %PIValueTree.
@@ -260,6 +281,11 @@ public:
//! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
const PIValueTree & operator[](const PIString & name) const { return child(name); } const PIValueTree & operator[](const PIString & name) const { return child(name); }
//! \~\brief
//! \~english Recursive call "func" for every child. "full_name" is a name with path, joined with ".".
//! \~russian Рекурсивно выполняет "func" для каждого узла. "full_name" - это имя с путём, соединены ".".
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & full_name)> func);
//! \~\brief //! \~\brief
//! \~english Returns a list of standard attribute names. //! \~english Returns a list of standard attribute names.
//! \~russian Возвращает список стандартных имен атрибутов. //! \~russian Возвращает список стандартных имен атрибутов.
@@ -268,6 +294,7 @@ public:
private: private:
static void print(PIString & s, const PIValueTree & v, PIString tab); static void print(PIString & s, const PIValueTree & v, PIString tab);
static PIValueTree & nullValue(); static PIValueTree & nullValue();
void forEachRecursiveInternal(std::function<void(const PIValueTree &, const PIString &)> func, PIString prefix = {});
PIString _name; PIString _name;
PIString _comment; PIString _comment;