Compare commits
5 Commits
f041d1435e
...
1c7fc39b6c
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c7fc39b6c | |||
| f07c9cbce8 | |||
| abdba6d68b | |||
| 3db26a762c | |||
| b35561f74e |
@@ -1,10 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
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 4)
|
||||||
set(PIP_MINOR 21)
|
set(PIP_MINOR 0)
|
||||||
set(PIP_REVISION 0)
|
set(PIP_REVISION 0)
|
||||||
set(PIP_SUFFIX )
|
set(PIP_SUFFIX _alpha)
|
||||||
set(PIP_COMPANY SHS)
|
set(PIP_COMPANY SHS)
|
||||||
set(PIP_DOMAIN org.SHS)
|
set(PIP_DOMAIN org.SHS)
|
||||||
|
|
||||||
@@ -247,18 +247,6 @@ if(PIP_MATH_YN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# Check if RT timers exists
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES time.h)
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES )
|
|
||||||
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS))
|
|
||||||
list(APPEND LIBS_MAIN rt)
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES rt)
|
|
||||||
endif()
|
|
||||||
CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0)
|
|
||||||
CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1)
|
|
||||||
CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
|
|
||||||
|
|
||||||
|
|
||||||
# Check if build debug version
|
# Check if build debug version
|
||||||
if (PIP_BUILD_DEBUG)
|
if (PIP_BUILD_DEBUG)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
|
||||||
@@ -317,15 +305,6 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
|
|||||||
#message("${_PIP_DEFS_CHANGED}")
|
#message("${_PIP_DEFS_CHANGED}")
|
||||||
|
|
||||||
|
|
||||||
# Check if RT timers exists
|
|
||||||
if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
|
|
||||||
set(PIP_TIMERS "Thread, ThreadRT, Pool")
|
|
||||||
add_definitions(-DPIP_TIMER_RT)
|
|
||||||
else()
|
|
||||||
set(PIP_TIMERS "Thread, Pool")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Add main library
|
# Add main library
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
@@ -673,7 +652,6 @@ message("")
|
|||||||
message(" Options:")
|
message(" Options:")
|
||||||
message(" std::iostream: ${PIP_STD_IOSTREAM}")
|
message(" std::iostream: ${PIP_STD_IOSTREAM}")
|
||||||
message(" ICU strings : ${PIP_ICU}")
|
message(" ICU strings : ${PIP_ICU}")
|
||||||
message(" Timer types : ${PIP_TIMERS}")
|
|
||||||
message(" Introspection: ${PIP_INTROSPECTION}")
|
message(" Introspection: ${PIP_INTROSPECTION}")
|
||||||
message(" Coverage : ${PIP_COVERAGE}")
|
message(" Coverage : ${PIP_COVERAGE}")
|
||||||
if(INTROSPECTION)
|
if(INTROSPECTION)
|
||||||
|
|||||||
@@ -66,10 +66,6 @@ if (NOT BUILDING_PIP)
|
|||||||
find_library(PTHREAD_LIBRARY pthread)
|
find_library(PTHREAD_LIBRARY pthread)
|
||||||
find_library(UTIL_LIBRARY util)
|
find_library(UTIL_LIBRARY util)
|
||||||
set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY})
|
set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY})
|
||||||
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT PIP_FREERTOS))
|
|
||||||
find_library(RT_LIBRARY rt)
|
|
||||||
list(APPEND _PIP_ADD_LIBS_ ${RT_LIBRARY})
|
|
||||||
endif()
|
|
||||||
list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_})
|
list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
|
|
||||||
//! [delimiter]
|
//! [delimiter]
|
||||||
void tfunc(void * , int delim) {
|
void tfunc(int delim) {
|
||||||
piCout << "tick with delimiter" << delim;
|
piCout << "tick with delimiter" << delim;
|
||||||
};
|
};
|
||||||
void tfunc4(void * , int delim) {
|
void tfunc4(int delim) {
|
||||||
piCout << "tick4 with delimiter" << delim;
|
piCout << "tick4 with delimiter" << delim;
|
||||||
};
|
};
|
||||||
int main() {
|
int main() {
|
||||||
@@ -13,8 +13,7 @@ int main() {
|
|||||||
timer.addDelimiter(4, tfunc4);
|
timer.addDelimiter(4, tfunc4);
|
||||||
timer.start(50);
|
timer.start(50);
|
||||||
piMSleep(200);
|
piMSleep(200);
|
||||||
timer.stop();
|
timer.stopAndWait();
|
||||||
timer.waitForFinish();
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
/* Result:
|
/* Result:
|
||||||
@@ -29,14 +28,14 @@ tick4 with delimiter 4
|
|||||||
//! [delimiter]
|
//! [delimiter]
|
||||||
//! [elapsed]
|
//! [elapsed]
|
||||||
int main() {
|
int main() {
|
||||||
PITimer timer;
|
PITimeMeasurer tm;
|
||||||
piMSleep(100);
|
piMSleep(100);
|
||||||
piCout << "elapsed" << timer.elapsed_m() << "ms";
|
piCout << "elapsed" << tm.elapsed_m() << "ms";
|
||||||
piMSleep(100);
|
piMSleep(100);
|
||||||
piCout << "elapsed" << timer.elapsed_m() << "ms";
|
piCout << "elapsed" << tm.elapsed_m() << "ms";
|
||||||
timer.reset();
|
tm.reset();
|
||||||
piMSleep(150);
|
piMSleep(150);
|
||||||
piCout << "elapsed" << timer.elapsed_s() << "s";
|
piCout << "elapsed" << tm.elapsed_s() << "s";
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
/* Result:
|
/* Result:
|
||||||
@@ -47,22 +46,21 @@ elapsed 0.15 s
|
|||||||
//! [elapsed]
|
//! [elapsed]
|
||||||
//! [system_time]
|
//! [system_time]
|
||||||
int main() {
|
int main() {
|
||||||
PISystemTime t0; // s = ns = 0
|
PISystemTime t0; // s = ns = 0
|
||||||
t0.addMilliseconds(200); // s = 0, ns = 200000000
|
t0.addMilliseconds(200); // s = 0, ns = 200000000
|
||||||
t0.addMilliseconds(900); // s = 1, ns = 100000000
|
t0.addMilliseconds(900); // s = 1, ns = 100000000
|
||||||
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
|
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
|
||||||
t0.sleep(); // sleep for 1 second
|
t0.sleep(); // sleep for 1 second
|
||||||
PISystemTime t1;
|
PISystemTime t1;
|
||||||
t0 = currentSystemTime();
|
t0 = PISystemTime::current();
|
||||||
piMSleep(500);
|
piMSleep(500);
|
||||||
t1 = currentSystemTime();
|
t1 = PISystemTime::current();
|
||||||
(t1 - t0).sleep(); // sleep for 500 milliseconds
|
(t1 - t0).sleep(); // sleep for 500 milliseconds
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
//! [system_time]
|
//! [system_time]
|
||||||
|
|
||||||
void _() {
|
void _(){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class MainClass: public PITimer {
|
|||||||
public:
|
public:
|
||||||
MainClass() {}
|
MainClass() {}
|
||||||
protected:
|
protected:
|
||||||
void tick(void * data, int delimiter) {
|
void tick(int delimiter) {
|
||||||
piCout << "timer tick";
|
piCout << "timer tick";
|
||||||
// timer tick
|
// timer tick
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ bool PICloudClient::openDevice() {
|
|||||||
mutex_connect.lock();
|
mutex_connect.lock();
|
||||||
eth.startThreadedRead();
|
eth.startThreadedRead();
|
||||||
// piCoutObj << "connecting...";
|
// piCoutObj << "connecting...";
|
||||||
bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
|
bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout());
|
||||||
// piCoutObj << "conn_ok" << conn_ok << is_connected;
|
// piCoutObj << "conn_ok" << conn_ok << is_connected;
|
||||||
mutex_connect.unlock();
|
mutex_connect.unlock();
|
||||||
if (!conn_ok) {
|
if (!conn_ok) {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "picloudserver.h"
|
#include "picloudserver.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
|
|
||||||
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
|
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
|
||||||
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000);
|
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000);
|
||||||
@@ -94,7 +96,7 @@ bool PICloudServer::openDevice() {
|
|||||||
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
|
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
|
||||||
if (op) {
|
if (op) {
|
||||||
eth.startThreadedRead();
|
eth.startThreadedRead();
|
||||||
ping_timer.start(5000);
|
ping_timer.start(5_s);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ping_timer.stop();
|
ping_timer.stop();
|
||||||
@@ -169,7 +171,7 @@ PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client
|
|||||||
PICloudServer::Client::~Client() {
|
PICloudServer::Client::~Client() {
|
||||||
// piCoutObj << "~PICloudServer::Client..." << this;
|
// piCoutObj << "~PICloudServer::Client..." << this;
|
||||||
close();
|
close();
|
||||||
stopAndWait(10000);
|
stopAndWait(10_s);
|
||||||
// piCoutObj << "~PICloudServer::Client done" << this;
|
// piCoutObj << "~PICloudServer::Client done" << this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "piscreen.h"
|
#include "piscreen.h"
|
||||||
|
|
||||||
#include "piincludes_p.h"
|
#include "piincludes_p.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#ifndef WINDOWS
|
#ifndef WINDOWS
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
# include <sys/ioctl.h>
|
# include <sys/ioctl.h>
|
||||||
@@ -417,8 +418,8 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
|
|||||||
|
|
||||||
PIScreen::~PIScreen() {
|
PIScreen::~PIScreen() {
|
||||||
if (isRunning()) stop();
|
if (isRunning()) stop();
|
||||||
PIThread::waitForFinish(10);
|
PIThread::waitForFinish(100_ms);
|
||||||
listener->waitForFinish(10);
|
listener->waitForFinish(100_ms);
|
||||||
delete listener;
|
delete listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,6 +591,12 @@ void PIScreen::waitForFinish() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIScreen::start(bool wait) {
|
||||||
|
PIThread::start(25_Hz);
|
||||||
|
if (wait) waitForFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIScreen::stop(bool clear) {
|
void PIScreen::stop(bool clear) {
|
||||||
PIThread::stopAndWait();
|
PIThread::stopAndWait();
|
||||||
if (clear) console.clearScreen();
|
if (clear) console.clearScreen();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "piterminal.h"
|
#include "piterminal.h"
|
||||||
|
|
||||||
#include "piincludes_p.h"
|
#include "piincludes_p.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pisharedmemory.h"
|
#include "pisharedmemory.h"
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
@@ -126,7 +127,7 @@ PITerminal::PITerminal(): PIThread() {
|
|||||||
|
|
||||||
PITerminal::~PITerminal() {
|
PITerminal::~PITerminal() {
|
||||||
if (isRunning()) stop();
|
if (isRunning()) stop();
|
||||||
PIThread::waitForFinish(10);
|
PIThread::waitForFinish(1_s);
|
||||||
destroy();
|
destroy();
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
if (PRIVATE->shm) delete PRIVATE->shm;
|
if (PRIVATE->shm) delete PRIVATE->shm;
|
||||||
@@ -915,7 +916,7 @@ bool PITerminal::initialize() {
|
|||||||
# endif
|
# endif
|
||||||
cursor_blink = false;
|
cursor_blink = false;
|
||||||
cursor_tm.reset();
|
cursor_tm.reset();
|
||||||
start(40);
|
start(25_Hz);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,7 +924,7 @@ bool PITerminal::initialize() {
|
|||||||
void PITerminal::destroy() {
|
void PITerminal::destroy() {
|
||||||
// piCout << "destroy ...";
|
// piCout << "destroy ...";
|
||||||
stop();
|
stop();
|
||||||
waitForFinish(1000);
|
waitForFinish(1_s);
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
if (PRIVATE->pi.hProcess) {
|
if (PRIVATE->pi.hProcess) {
|
||||||
// piCout << "term";
|
// piCout << "term";
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "pibroadcast.h"
|
#include "pibroadcast.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
/** \class PIBroadcast
|
/** \class PIBroadcast
|
||||||
* \brief Broadcast for all interfaces, including loopback
|
* \brief Broadcast for all interfaces, including loopback
|
||||||
*
|
*
|
||||||
@@ -223,7 +225,7 @@ void PIBroadcast::startRead() {
|
|||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
_started = false;
|
_started = false;
|
||||||
reinit();
|
reinit();
|
||||||
PIThread::start(3000);
|
PIThread::start(3_s);
|
||||||
}
|
}
|
||||||
if (_send_only) return;
|
if (_send_only) return;
|
||||||
PIMutexLocker ml(mcast_mutex);
|
PIMutexLocker ml(mcast_mutex);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "pistreampacker.h"
|
#include "pistreampacker.h"
|
||||||
|
|
||||||
#include "piiodevice.h"
|
#include "piiodevice.h"
|
||||||
|
#include "piliterals_bytes.h"
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
# pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
@@ -52,7 +53,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
|
|||||||
aggressive_optimization = true;
|
aggressive_optimization = true;
|
||||||
packet_size = -1;
|
packet_size = -1;
|
||||||
size_crypted_size = sizeof(int);
|
size_crypted_size = sizeof(int);
|
||||||
crypt_frag_size = 1024 * 1024;
|
crypt_frag_size = 1_MiB;
|
||||||
max_packet_size = 1400;
|
max_packet_size = 1400;
|
||||||
packet_sign = 0xAFBE;
|
packet_sign = 0xAFBE;
|
||||||
assignDevice(dev);
|
assignDevice(dev);
|
||||||
|
|||||||
@@ -167,7 +167,8 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
|
|||||||
|
|
||||||
|
|
||||||
PIKbdListener::~PIKbdListener() {
|
PIKbdListener::~PIKbdListener() {
|
||||||
terminate();
|
stop();
|
||||||
|
if (!waitForFinish(100_ms)) terminate();
|
||||||
end();
|
end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,10 +73,7 @@ public:
|
|||||||
|
|
||||||
EVENT_HANDLER0(void, waitForFinish);
|
EVENT_HANDLER0(void, waitForFinish);
|
||||||
EVENT_HANDLER0(void, start) { start(false); }
|
EVENT_HANDLER0(void, start) { start(false); }
|
||||||
EVENT_HANDLER1(void, start, bool, wait) {
|
EVENT_HANDLER1(void, start, bool, wait);
|
||||||
PIThread::start(40);
|
|
||||||
if (wait) waitForFinish();
|
|
||||||
}
|
|
||||||
EVENT_HANDLER0(void, stop) { stop(false); }
|
EVENT_HANDLER0(void, stop) { stop(false); }
|
||||||
EVENT_HANDLER1(void, stop, bool, clear);
|
EVENT_HANDLER1(void, stop, bool, clear);
|
||||||
|
|
||||||
|
|||||||
@@ -150,11 +150,6 @@
|
|||||||
//! \~russian Макрос объявлен когда компилятор неизвестен
|
//! \~russian Макрос объявлен когда компилятор неизвестен
|
||||||
# define CC_OTHER
|
# define CC_OTHER
|
||||||
|
|
||||||
//! \~\brief
|
|
||||||
//! \~english Macro is defined when PIP can use "rt" library for \a PITimer::ThreadRT timers implementation
|
|
||||||
//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для \a PITimer::ThreadRT реализации таймера
|
|
||||||
# define PIP_TIMER_RT
|
|
||||||
|
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Macro to declare private section, "export" is optional
|
//! \~english Macro to declare private section, "export" is optional
|
||||||
//! \~russian Макрос для объявления частной секции, "export" необязателен
|
//! \~russian Макрос для объявления частной секции, "export" необязателен
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void PIIntrospectionThreads::threadStart(PIThread * t) {
|
|||||||
ThreadInfo & ti(threads[t]);
|
ThreadInfo & ti(threads[t]);
|
||||||
ti.id = t->tid();
|
ti.id = t->tid();
|
||||||
ti.priority = t->priority();
|
ti.priority = t->priority();
|
||||||
ti.delay = t->delay_;
|
ti.delay = t->delay_.toMilliseconds();
|
||||||
ti.state = sStarting;
|
ti.state = sStarting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,10 @@
|
|||||||
#include "pibinarylog.h"
|
#include "pibinarylog.h"
|
||||||
|
|
||||||
#include "pidir.h"
|
#include "pidir.h"
|
||||||
#include "piliterals.h"
|
#include "piliterals_bytes.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pipropertystorage.h"
|
#include "pipropertystorage.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
#define PIBINARYLOG_VERSION_OLD 0x31
|
#define PIBINARYLOG_VERSION_OLD 0x31
|
||||||
|
|
||||||
@@ -259,9 +261,9 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
|
|||||||
<< "Creating directory" << dir.path();
|
<< "Creating directory" << dir.path();
|
||||||
dir.make(true);
|
dir.make(true);
|
||||||
}
|
}
|
||||||
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||||
PIString cnpath = npath + ".binlog";
|
PIString cnpath = npath + ".binlog";
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (PIFile::isExists(cnpath)) {
|
while (PIFile::isExists(cnpath)) {
|
||||||
cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog";
|
cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog";
|
||||||
i++;
|
i++;
|
||||||
@@ -644,9 +646,9 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
|||||||
}
|
}
|
||||||
PIByteArray ba;
|
PIByteArray ba;
|
||||||
Record br;
|
Record br;
|
||||||
br.id = 0;
|
br.id = 0;
|
||||||
br.size = 0;
|
br.size = 0;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
constexpr size_t hdr_size = sizeof(Record) - sizeof(PIByteArray);
|
constexpr size_t hdr_size = sizeof(Record) - sizeof(PIByteArray);
|
||||||
ba.resize(hdr_size);
|
ba.resize(hdr_size);
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -977,16 +979,16 @@ void PIBinaryLog::configureFromVariantDevice(const PIPropertyStorage & d) {
|
|||||||
|
|
||||||
|
|
||||||
void PIBinaryLog::propertyChanged(const char * s) {
|
void PIBinaryLog::propertyChanged(const char * s) {
|
||||||
default_id = property("defaultID").toInt();
|
default_id = property("defaultID").toInt();
|
||||||
rapid_start = property("rapidStart").toBool();
|
rapid_start = property("rapidStart").toBool();
|
||||||
play_mode = (PlayMode)property("playMode").toInt();
|
play_mode = (PlayMode)property("playMode").toInt();
|
||||||
const double ps = property("playSpeed").toDouble();
|
const double ps = property("playSpeed").toDouble();
|
||||||
play_speed = ps > 0. ? 1. / ps : 0.;
|
play_speed = ps > 0. ? 1. / ps : 0.;
|
||||||
play_delay = property("playDelay").toSystemTime();
|
play_delay = property("playDelay").toSystemTime();
|
||||||
split_mode = (SplitMode)property("splitMode").toInt();
|
split_mode = (SplitMode)property("splitMode").toInt();
|
||||||
split_time = property("splitTime").toSystemTime();
|
split_time = property("splitTime").toSystemTime();
|
||||||
split_size = property("splitFileSize").toLLong();
|
split_size = property("splitFileSize").toLLong();
|
||||||
split_count = property("splitRecordCount").toInt();
|
split_count = property("splitRecordCount").toInt();
|
||||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ void PIEthernet::construct() {
|
|||||||
setOption(BlockingWrite);
|
setOption(BlockingWrite);
|
||||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||||
sock = sock_s = -1;
|
sock = sock_s = -1;
|
||||||
setReadTimeout(10000.);
|
setReadTimeout(10_s);
|
||||||
setWriteTimeout(10000.);
|
setWriteTimeout(10_s);
|
||||||
setTTL(64);
|
setTTL(64);
|
||||||
setMulticastTTL(1);
|
setMulticastTTL(1);
|
||||||
server_thread_.setData(this);
|
server_thread_.setData(this);
|
||||||
@@ -331,7 +331,7 @@ void PIEthernet::closeSocket(int & sd) {
|
|||||||
|
|
||||||
void PIEthernet::applyTimeouts() {
|
void PIEthernet::applyTimeouts() {
|
||||||
if (sock < 0) return;
|
if (sock < 0) return;
|
||||||
double rtm = readTimeout(), wtm = writeTimeout();
|
PISystemTime rtm = readTimeout(), wtm = writeTimeout();
|
||||||
applyTimeout(sock, SO_RCVTIMEO, rtm);
|
applyTimeout(sock, SO_RCVTIMEO, rtm);
|
||||||
applyTimeout(sock, SO_SNDTIMEO, wtm);
|
applyTimeout(sock, SO_SNDTIMEO, wtm);
|
||||||
if (sock_s != sock && sock_s != -1) {
|
if (sock_s != sock && sock_s != -1) {
|
||||||
@@ -341,17 +341,15 @@ void PIEthernet::applyTimeouts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIEthernet::applyTimeout(int fd, int opt, double ms) {
|
void PIEthernet::applyTimeout(int fd, int opt, PISystemTime tm) {
|
||||||
if (fd == 0) return;
|
if (fd == 0) return;
|
||||||
// piCoutObj << "setReadIsBlocking" << yes;
|
// piCoutObj << "setReadIsBlocking" << yes;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
DWORD _tm = ms;
|
DWORD _tm = tm.toMilliseconds();
|
||||||
#else
|
#else
|
||||||
double s = ms / 1000.;
|
|
||||||
timeval _tm;
|
timeval _tm;
|
||||||
_tm.tv_sec = piFloord(s);
|
_tm.tv_sec = tm.seconds;
|
||||||
s -= _tm.tv_sec;
|
_tm.tv_usec = tm.nanoseconds / 1000;
|
||||||
_tm.tv_usec = s * 1000000.;
|
|
||||||
#endif
|
#endif
|
||||||
ethSetsockopt(fd, SOL_SOCKET, opt, &_tm, sizeof(_tm));
|
ethSetsockopt(fd, SOL_SOCKET, opt, &_tm, sizeof(_tm));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,16 +174,16 @@ public:
|
|||||||
Type type() const { return eth_type; }
|
Type type() const { return eth_type; }
|
||||||
|
|
||||||
//! Returns read timeout
|
//! Returns read timeout
|
||||||
double readTimeout() const { return property("readTimeout").toDouble(); }
|
PISystemTime readTimeout() const { return property("readTimeout").toSystemTime(); }
|
||||||
|
|
||||||
//! Returns write timeout
|
//! Returns write timeout
|
||||||
double writeTimeout() const { return property("writeTimeout").toDouble(); }
|
PISystemTime writeTimeout() const { return property("writeTimeout").toSystemTime(); }
|
||||||
|
|
||||||
//! Set timeout for read
|
//! Set timeout for read
|
||||||
void setReadTimeout(double ms) { setProperty("readTimeout", ms); }
|
void setReadTimeout(PISystemTime tm) { setProperty("readTimeout", tm); }
|
||||||
|
|
||||||
//! Set timeout for write
|
//! Set timeout for write
|
||||||
void setWriteTimeout(double ms) { setProperty("writeTimeout", ms); }
|
void setWriteTimeout(PISystemTime tm) { setProperty("writeTimeout", tm); }
|
||||||
|
|
||||||
|
|
||||||
//! Returns TTL (Time To Live)
|
//! Returns TTL (Time To Live)
|
||||||
@@ -437,11 +437,11 @@ public:
|
|||||||
//! \brief ethernet parameters
|
//! \brief ethernet parameters
|
||||||
int parameters;
|
int parameters;
|
||||||
|
|
||||||
//! \brief read timeout, default 1000 ms
|
//! \brief read timeout, default 10 s
|
||||||
double readTimeout;
|
PISystemTime readTimeout;
|
||||||
|
|
||||||
//! \brief write timeout, default 1000 ms
|
//! \brief write timeout, default 10 s
|
||||||
double writeTimeout;
|
PISystemTime writeTimeout;
|
||||||
|
|
||||||
//! \brief time-to-live, default 64
|
//! \brief time-to-live, default 64
|
||||||
int TTL;
|
int TTL;
|
||||||
@@ -475,7 +475,7 @@ protected:
|
|||||||
bool closeDevice() override;
|
bool closeDevice() override;
|
||||||
void closeSocket(int & sd);
|
void closeSocket(int & sd);
|
||||||
void applyTimeouts();
|
void applyTimeouts();
|
||||||
void applyTimeout(int fd, int opt, double ms);
|
void applyTimeout(int fd, int opt, PISystemTime tm);
|
||||||
void applyOptInt(int level, int opt, int val);
|
void applyOptInt(int level, int opt, int val);
|
||||||
|
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
#include "piiodevice.h"
|
#include "piiodevice.h"
|
||||||
|
|
||||||
#include "piconfig.h"
|
#include "piconfig.h"
|
||||||
#include "piconnection.h"
|
#include "piliterals_bytes.h"
|
||||||
#include "piliterals.h"
|
#include "piliterals_string.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pipropertystorage.h"
|
#include "pipropertystorage.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
|
|
||||||
//! \class PIIODevice piiodevice.h
|
//! \class PIIODevice piiodevice.h
|
||||||
@@ -158,9 +160,9 @@ void PIIODevice::setReopenEnabled(bool yes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIODevice::setReopenTimeout(int msecs) {
|
void PIIODevice::setReopenTimeout(PISystemTime timeout) {
|
||||||
setProperty("reopenTimeout", msecs);
|
setProperty("reopenTimeout", timeout);
|
||||||
reopen_timeout = msecs;
|
reopen_timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -231,11 +233,13 @@ void PIIODevice::terminateThreadedRead() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIIODevice::waitThreadedReadFinished(int timeout_ms) {
|
bool PIIODevice::waitThreadedReadFinished(PISystemTime timeout) {
|
||||||
PITimeMeasurer tm, tm_intr;
|
PITimeMeasurer tm, tm_intr;
|
||||||
while (read_thread.isRunning()) {
|
while (read_thread.isRunning()) {
|
||||||
if (tm.elapsed_m() > timeout_ms) return false;
|
if (timeout.isNotNull()) {
|
||||||
if (tm_intr.elapsed_m() > 100.) {
|
if (tm.elapsed() > timeout) return false;
|
||||||
|
}
|
||||||
|
if (tm_intr.elapsed() > 100_ms) {
|
||||||
tm_intr.reset();
|
tm_intr.reset();
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
@@ -266,8 +270,8 @@ void PIIODevice::terminateThreadedWrite() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIIODevice::waitThreadedWriteFinished(int timeout_ms) {
|
bool PIIODevice::waitThreadedWriteFinished(PISystemTime timeout) {
|
||||||
return write_thread.waitForFinish(timeout_ms);
|
return write_thread.waitForFinish(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -290,10 +294,10 @@ void PIIODevice::stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIODevice::stopAndWait(int timeout_ms) {
|
void PIIODevice::stopAndWait(PISystemTime timeout) {
|
||||||
stop();
|
stop();
|
||||||
waitThreadedReadFinished(timeout_ms);
|
waitThreadedReadFinished(timeout);
|
||||||
waitThreadedWriteFinished(timeout_ms);
|
waitThreadedWriteFinished(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -327,7 +331,7 @@ void PIIODevice::_init() {
|
|||||||
opened_ = false;
|
opened_ = false;
|
||||||
setOptions(0);
|
setOptions(0);
|
||||||
setReopenEnabled(true);
|
setReopenEnabled(true);
|
||||||
setReopenTimeout(1000);
|
setReopenTimeout(1_s);
|
||||||
#ifdef MICRO_PIP
|
#ifdef MICRO_PIP
|
||||||
threaded_read_buffer_size = 512;
|
threaded_read_buffer_size = 512;
|
||||||
#else
|
#else
|
||||||
@@ -375,7 +379,7 @@ void PIIODevice::read_func() {
|
|||||||
piMSleep(10);
|
piMSleep(10);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (reopen_enabled) {
|
if (reopen_enabled) {
|
||||||
if (reopen_tm.elapsed_m() >= reopen_timeout) {
|
if (reopen_tm.elapsed() >= reopen_timeout) {
|
||||||
reopen_tm.reset();
|
reopen_tm.reset();
|
||||||
ok = open();
|
ok = open();
|
||||||
}
|
}
|
||||||
@@ -394,14 +398,14 @@ void PIIODevice::read_func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIByteArray PIIODevice::readForTime(double timeout_ms) {
|
PIByteArray PIIODevice::readForTime(PISystemTime timeout) {
|
||||||
PIByteArray str;
|
PIByteArray str;
|
||||||
if (timeout_ms <= 0.) return str;
|
if (timeout.isNull()) return str;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
uchar * td = new uchar[threaded_read_buffer_size];
|
uchar * td = new uchar[threaded_read_buffer_size];
|
||||||
bool was_br = setOption(BlockingRead, false);
|
bool was_br = setOption(BlockingRead, false);
|
||||||
tm.reset();
|
tm.reset();
|
||||||
while (tm.elapsed_m() < timeout_ms) {
|
while (tm.elapsed() < timeout) {
|
||||||
ret = read(td, threaded_read_buffer_size);
|
ret = read(td, threaded_read_buffer_size);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
piMinSleep();
|
piMinSleep();
|
||||||
@@ -477,13 +481,13 @@ bool PIIODevice::configure(const PIString & config_file, const PIString & sectio
|
|||||||
if (ep != 0) {
|
if (ep != 0) {
|
||||||
setReopenEnabled(ep->getValue("reopenEnabled", isReopenEnabled(), &ex).toBool());
|
setReopenEnabled(ep->getValue("reopenEnabled", isReopenEnabled(), &ex).toBool());
|
||||||
if (!ex) setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool());
|
if (!ex) setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool());
|
||||||
setReopenTimeout(ep->getValue("reopenTimeout", reopenTimeout(), &ex).toInt());
|
setReopenTimeout(PISystemTime::fromMilliseconds(ep->getValue("reopenTimeout", reopenTimeout().toMilliseconds(), &ex).toInt()));
|
||||||
if (!ex) setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()).toInt());
|
if (!ex) setReopenTimeout(PISystemTime::fromMilliseconds(em.getValue("reopenTimeout", reopenTimeout().toMilliseconds()).toInt()));
|
||||||
setThreadedReadBufferSize(ep->getValue("threadedReadBufferSize", int(threaded_read_buffer_size), &ex).toInt());
|
setThreadedReadBufferSize(ep->getValue("threadedReadBufferSize", int(threaded_read_buffer_size), &ex).toInt());
|
||||||
if (!ex) setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt());
|
if (!ex) setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt());
|
||||||
} else {
|
} else {
|
||||||
setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool());
|
setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool());
|
||||||
setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()).toInt());
|
setReopenTimeout(PISystemTime::fromMilliseconds(em.getValue("reopenTimeout", reopenTimeout().toMilliseconds()).toInt()));
|
||||||
setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt());
|
setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt());
|
||||||
}
|
}
|
||||||
return configureDevice(&em, ep);
|
return configureDevice(&em, ep);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#include "piinit.h"
|
#include "piinit.h"
|
||||||
#include "piqueue.h"
|
#include "piqueue.h"
|
||||||
#include "pitimer.h"
|
#include "pithread.h"
|
||||||
|
|
||||||
/// TODO: написать документацию, тут ничего не понятно
|
/// TODO: написать документацию, тут ничего не понятно
|
||||||
// function executed from threaded read, pass readedData, sizeOfData, ThreadedReadData
|
// function executed from threaded read, pass readedData, sizeOfData, ThreadedReadData
|
||||||
@@ -201,21 +201,17 @@ public:
|
|||||||
//! \~russian Устанавливает возможность вызова \a open() при потоковом чтении на закрытом устройстве
|
//! \~russian Устанавливает возможность вызова \a open() при потоковом чтении на закрытом устройстве
|
||||||
void setReopenEnabled(bool yes = true);
|
void setReopenEnabled(bool yes = true);
|
||||||
|
|
||||||
//! \~english Set timeout in milliseconds between \a open() tryings if reopen is enabled
|
|
||||||
//! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно
|
|
||||||
void setReopenTimeout(int msecs);
|
|
||||||
|
|
||||||
//! \~english Set timeout between \a open() tryings if reopen is enabled
|
//! \~english Set timeout between \a open() tryings if reopen is enabled
|
||||||
//! \~russian Устанавливает задержку между вызовами \a open() если переоткрытие активно
|
//! \~russian Устанавливает задержку между вызовами \a open() если переоткрытие активно
|
||||||
void setReopenTimeout(PISystemTime timeout) { setReopenTimeout(timeout.toMilliseconds()); }
|
void setReopenTimeout(PISystemTime timeout);
|
||||||
|
|
||||||
//! \~english Returns reopen enable
|
//! \~english Returns reopen enable
|
||||||
//! \~russian Возвращает активно ли переоткрытие
|
//! \~russian Возвращает активно ли переоткрытие
|
||||||
bool isReopenEnabled() const { return property("reopenEnabled").toBool(); }
|
bool isReopenEnabled() const { return property("reopenEnabled").toBool(); }
|
||||||
|
|
||||||
//! \~english Returns reopen timeout in milliseconds
|
//! \~english Returns reopen timeout
|
||||||
//! \~russian Возвращает задержку переоткрытия в миллисекундах
|
//! \~russian Возвращает задержку переоткрытия
|
||||||
int reopenTimeout() { return property("reopenTimeout").toInt(); }
|
PISystemTime reopenTimeout() { return property("reopenTimeout").toSystemTime(); }
|
||||||
|
|
||||||
|
|
||||||
//! \~english Set threaded read callback
|
//! \~english Set threaded read callback
|
||||||
@@ -266,13 +262,9 @@ public:
|
|||||||
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
||||||
void terminateThreadedRead();
|
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".
|
//! \~english Wait for threaded read finish no longer than "timeout".
|
||||||
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout".
|
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout".
|
||||||
bool waitThreadedReadFinished(PISystemTime timeout) { return waitThreadedReadFinished(timeout.toMilliseconds()); }
|
bool waitThreadedReadFinished(PISystemTime timeout = {});
|
||||||
|
|
||||||
|
|
||||||
//! \~english Returns if threaded write is started
|
//! \~english Returns if threaded write is started
|
||||||
@@ -294,13 +286,9 @@ public:
|
|||||||
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
||||||
void terminateThreadedWrite();
|
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".
|
//! \~english Wait for threaded write finish no longer than "timeout".
|
||||||
//! \~russian Ожидает завершения потоковой записи в течении не более "timeout".
|
//! \~russian Ожидает завершения потоковой записи в течении не более "timeout".
|
||||||
bool waitThreadedWriteFinished(PISystemTime timeout) { return waitThreadedWriteFinished(timeout.toMilliseconds()); }
|
bool waitThreadedWriteFinished(PISystemTime timeout = {});
|
||||||
|
|
||||||
//! \~english Clear threaded write task queue
|
//! \~english Clear threaded write task queue
|
||||||
//! \~russian Очищает очередь потоковой записи
|
//! \~russian Очищает очередь потоковой записи
|
||||||
@@ -317,11 +305,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Stop both threaded read and threaded write and wait for finish.
|
//! \~english Stop both threaded read and threaded write and wait for finish.
|
||||||
//! \~russian Останавливает потоковое чтение и запись и ожидает завершения.
|
//! \~russian Останавливает потоковое чтение и запись и ожидает завершения.
|
||||||
void stopAndWait(int timeout_ms = -1);
|
void stopAndWait(PISystemTime timeout = {});
|
||||||
|
|
||||||
//! \~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 Прерывает блокирующую операцию.
|
||||||
@@ -355,15 +339,9 @@ public:
|
|||||||
//! \~russian Пишет в устройство не более "max_size" байт из "data"
|
//! \~russian Пишет в устройство не более "max_size" байт из "data"
|
||||||
ssize_t write(const void * data, ssize_t max_size);
|
ssize_t write(const void * data, ssize_t max_size);
|
||||||
|
|
||||||
//! \~english Read from device for "timeout_ms" milliseconds and return readed data as PIByteArray.
|
|
||||||
//! Timeout should to be greater than 0
|
|
||||||
//! \~russian Читает из устройства в течении "timeout_ms" миллисекунд и возвращает данные как PIByteArray.
|
|
||||||
//! Таймаут должен быть больше 0
|
|
||||||
PIByteArray readForTime(double timeout_ms);
|
|
||||||
|
|
||||||
//! \~english Read from device for "timeout" and return readed data as PIByteArray.
|
//! \~english Read from device for "timeout" and return readed data as PIByteArray.
|
||||||
//! \~russian Читает из устройства в течении "timeout" и возвращает данные как PIByteArray.
|
//! \~russian Читает из устройства в течении "timeout" и возвращает данные как PIByteArray.
|
||||||
PIByteArray readForTime(PISystemTime timeout) { return readForTime(timeout.toMilliseconds()); }
|
PIByteArray readForTime(PISystemTime timeout);
|
||||||
|
|
||||||
|
|
||||||
//! \~english Add task to threaded write queue and return task ID
|
//! \~english Add task to threaded write queue and return task ID
|
||||||
@@ -506,8 +484,8 @@ public:
|
|||||||
//! \~russian setReopenEnabled, по умолчанию "true"
|
//! \~russian setReopenEnabled, по умолчанию "true"
|
||||||
bool reopenEnabled;
|
bool reopenEnabled;
|
||||||
|
|
||||||
//! \~english setReopenTimeout in milliseconds, default 1000
|
//! \~english setReopenTimeout, default 1_s
|
||||||
//! \~russian setReopenTimeout в миллисекундах, по умолчанию 1000
|
//! \~russian setReopenTimeout, по умолчанию 1_s
|
||||||
int reopenTimeout;
|
int reopenTimeout;
|
||||||
|
|
||||||
//! \~english setThreadedReadBufferSize in bytes, default 4096
|
//! \~english setThreadedReadBufferSize in bytes, default 4096
|
||||||
@@ -609,8 +587,9 @@ private:
|
|||||||
PIThread read_thread, write_thread;
|
PIThread read_thread, write_thread;
|
||||||
PIByteArray buffer_in, buffer_tr;
|
PIByteArray buffer_in, buffer_tr;
|
||||||
PIQueue<PIPair<PIByteArray, ullong>> write_queue;
|
PIQueue<PIPair<PIByteArray, ullong>> write_queue;
|
||||||
|
PISystemTime reopen_timeout;
|
||||||
ullong tri = 0;
|
ullong tri = 0;
|
||||||
uint threaded_read_buffer_size, reopen_timeout = 1000;
|
uint threaded_read_buffer_size;
|
||||||
bool reopen_enabled = true, destroying = false;
|
bool reopen_enabled = true, destroying = false;
|
||||||
|
|
||||||
static PIMutex nfp_mutex;
|
static PIMutex nfp_mutex;
|
||||||
|
|||||||
@@ -21,7 +21,9 @@
|
|||||||
|
|
||||||
#include "piconfig.h"
|
#include "piconfig.h"
|
||||||
#include "pidatatransfer.h"
|
#include "pidatatransfer.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pipropertystorage.h"
|
#include "pipropertystorage.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
#define _PIPEER_MSG_SIZE 4000
|
#define _PIPEER_MSG_SIZE 4000
|
||||||
#define _PIPEER_MSG_TTL 100
|
#define _PIPEER_MSG_TTL 100
|
||||||
@@ -85,7 +87,7 @@ PIPeer::PeerData::~PeerData() {
|
|||||||
dt_in.stop();
|
dt_in.stop();
|
||||||
dt_out.stop();
|
dt_out.stop();
|
||||||
t.stop();
|
t.stop();
|
||||||
if (!t.waitForFinish(1000)) t.terminate();
|
if (!t.waitForFinish(1_s)) t.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -182,12 +184,12 @@ PIPeer::PIPeer(const PIString & n)
|
|||||||
PIMutexLocker pl(peers_mutex);
|
PIMutexLocker pl(peers_mutex);
|
||||||
PIMutexLocker sl(send_mutex);
|
PIMutexLocker sl(send_mutex);
|
||||||
changeName(n);
|
changeName(n);
|
||||||
setReopenTimeout(100);
|
setReopenTimeout(100_ms);
|
||||||
read_buffer_size = 128;
|
read_buffer_size = 128;
|
||||||
self_info.dist = 0;
|
self_info.dist = 0;
|
||||||
self_info.time = PISystemTime::current();
|
self_info.time = PISystemTime::current();
|
||||||
randomize();
|
randomize();
|
||||||
CONNECT2(void, void *, int, &sync_timer, tickEvent, this, timerEvent);
|
CONNECT1(void, int, &sync_timer, tickEvent, this, timerEvent);
|
||||||
prev_ifaces = PIEthernet::interfaces();
|
prev_ifaces = PIEthernet::interfaces();
|
||||||
no_timer = false;
|
no_timer = false;
|
||||||
sync_timer.addDelimiter(5);
|
sync_timer.addDelimiter(5);
|
||||||
@@ -199,9 +201,9 @@ PIPeer::~PIPeer() {
|
|||||||
stop();
|
stop();
|
||||||
if (destroyed) return;
|
if (destroyed) return;
|
||||||
destroyed = true;
|
destroyed = true;
|
||||||
sync_timer.stop();
|
sync_timer.stopAndWait();
|
||||||
diag_s.stop();
|
diag_s.stopAndWait();
|
||||||
diag_d.stop();
|
diag_d.stopAndWait();
|
||||||
PIMutexLocker ml(peers_mutex);
|
PIMutexLocker ml(peers_mutex);
|
||||||
piForeach(PeerInfo & p, peers)
|
piForeach(PeerInfo & p, peers)
|
||||||
if (p._data) {
|
if (p._data) {
|
||||||
@@ -212,15 +214,15 @@ PIPeer::~PIPeer() {
|
|||||||
destroyEths();
|
destroyEths();
|
||||||
piForeach(PIEthernet * i, eths_mcast) {
|
piForeach(PIEthernet * i, eths_mcast) {
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
i->stopThreadedRead();
|
i->stopAndWait();
|
||||||
}
|
}
|
||||||
piForeach(PIEthernet * i, eths_bcast) {
|
piForeach(PIEthernet * i, eths_bcast) {
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
i->stopThreadedRead();
|
i->stopAndWait();
|
||||||
}
|
}
|
||||||
eth_lo.stopThreadedRead();
|
eth_lo.stopAndWait();
|
||||||
eth_tcp_srv.stopThreadedRead();
|
eth_tcp_srv.stopAndWait();
|
||||||
eth_tcp_cli.stopThreadedRead();
|
eth_tcp_cli.stopAndWait();
|
||||||
sendSelfRemove();
|
sendSelfRemove();
|
||||||
destroyMBcasts();
|
destroyMBcasts();
|
||||||
eth_send.close();
|
eth_send.close();
|
||||||
@@ -229,7 +231,7 @@ PIPeer::~PIPeer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIPeer::timerEvent(void * data, int delim) {
|
void PIPeer::timerEvent(int delim) {
|
||||||
// piCoutObj << "timerEvent" << delim;
|
// piCoutObj << "timerEvent" << delim;
|
||||||
if (no_timer) return;
|
if (no_timer) return;
|
||||||
switch (delim) {
|
switch (delim) {
|
||||||
@@ -362,46 +364,32 @@ void PIPeer::initMBcasts(PIStringList al) {
|
|||||||
|
|
||||||
|
|
||||||
void PIPeer::destroyEths() {
|
void PIPeer::destroyEths() {
|
||||||
piForeach(PIEthernet * i, eths_traffic) {
|
for (auto * i: eths_traffic) {
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
((PIThread *)i)->stop();
|
i->stopAndWait();
|
||||||
((PIThread *)i)->waitForFinish(100);
|
|
||||||
i->stopThreadedRead();
|
|
||||||
i->close();
|
i->close();
|
||||||
delete i;
|
|
||||||
i = 0;
|
|
||||||
}
|
}
|
||||||
eths_traffic.clear();
|
piDeleteAllAndClear(eths_traffic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIPeer::destroyMBcasts() {
|
void PIPeer::destroyMBcasts() {
|
||||||
piForeach(PIEthernet * i, eths_mcast) {
|
for (auto * i: eths_mcast) {
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
((PIThread *)i)->stop();
|
|
||||||
((PIThread *)i)->waitForFinish(100);
|
|
||||||
i->stopThreadedRead();
|
|
||||||
i->leaveMulticastGroup(_PIPEER_MULTICAST_IP);
|
i->leaveMulticastGroup(_PIPEER_MULTICAST_IP);
|
||||||
|
i->stopAndWait();
|
||||||
i->close();
|
i->close();
|
||||||
delete i;
|
|
||||||
i = 0;
|
|
||||||
}
|
}
|
||||||
eths_mcast.clear();
|
for (auto * i: eths_bcast) {
|
||||||
piForeach(PIEthernet * i, eths_bcast) {
|
|
||||||
if (!i) continue;
|
if (!i) continue;
|
||||||
((PIThread *)i)->stop();
|
i->stopAndWait();
|
||||||
((PIThread *)i)->waitForFinish(100);
|
|
||||||
i->stopThreadedRead();
|
|
||||||
i->close();
|
i->close();
|
||||||
delete i;
|
|
||||||
i = 0;
|
|
||||||
}
|
}
|
||||||
eths_bcast.clear();
|
piDeleteAllAndClear(eths_mcast);
|
||||||
((PIThread *)ð_lo)->stop();
|
piDeleteAllAndClear(eths_bcast);
|
||||||
((PIThread *)ð_lo)->waitForFinish(100);
|
eth_lo.stopAndWait();
|
||||||
eth_lo.stopThreadedRead();
|
|
||||||
eth_lo.close();
|
eth_lo.close();
|
||||||
eth_tcp_srv.stop();
|
eth_tcp_srv.stopAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -918,7 +906,7 @@ void PIPeer::reinit() {
|
|||||||
initNetwork();
|
initNetwork();
|
||||||
sendSelfInfo();
|
sendSelfInfo();
|
||||||
no_timer = false;
|
no_timer = false;
|
||||||
if (!sync_timer.isRunning()) sync_timer.start(1000);
|
if (!sync_timer.isRunning()) sync_timer.start(1_Hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ protected:
|
|||||||
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EVENT_HANDLER2(void, timerEvent, void *, data, int, delim);
|
EVENT_HANDLER1(void, timerEvent, int, delim);
|
||||||
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
||||||
EVENT_HANDLER2(void, dtReceived, const PIString &, from, const PIByteArray &, data);
|
EVENT_HANDLER2(void, dtReceived, const PIString &, from, const PIByteArray &, data);
|
||||||
EVENT_HANDLER1(void, newTcpClient, PIEthernet *, client);
|
EVENT_HANDLER1(void, newTcpClient, PIEthernet *, client);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "pidir.h"
|
#include "pidir.h"
|
||||||
#include "piincludes_p.h"
|
#include "piincludes_p.h"
|
||||||
#include "pipropertystorage.h"
|
#include "pipropertystorage.h"
|
||||||
|
#include "pitime.h"
|
||||||
#include "piwaitevent_p.h"
|
#include "piwaitevent_p.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "pibasetransfer.h"
|
#include "pibasetransfer.h"
|
||||||
|
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
const uint PIBaseTransfer::signature = 0x54424950;
|
const uint PIBaseTransfer::signature = 0x54424950;
|
||||||
|
|
||||||
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||||
@@ -33,7 +35,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
|||||||
send_queue = 0;
|
send_queue = 0;
|
||||||
send_up = 0;
|
send_up = 0;
|
||||||
timeout_ = 10.;
|
timeout_ = 10.;
|
||||||
diag.setDisconnectTimeout(timeout_ / 10);
|
diag.setDisconnectTimeout(PISystemTime::fromSeconds(timeout_ / 10.));
|
||||||
diag.setName("PIBaseTransfer");
|
diag.setName("PIBaseTransfer");
|
||||||
diag.start(50);
|
diag.start(50);
|
||||||
packets_count = 10;
|
packets_count = 10;
|
||||||
@@ -47,7 +49,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
|||||||
|
|
||||||
|
|
||||||
PIBaseTransfer::~PIBaseTransfer() {
|
PIBaseTransfer::~PIBaseTransfer() {
|
||||||
diag.stop();
|
diag.stopAndWait();
|
||||||
break_ = true;
|
break_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +79,12 @@ void PIBaseTransfer::setPause(bool pause_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIBaseTransfer::setTimeout(double sec) {
|
||||||
|
timeout_ = sec;
|
||||||
|
diag.setDisconnectTimeout(PISystemTime::fromSeconds(sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIBaseTransfer::received(PIByteArray data) {
|
void PIBaseTransfer::received(PIByteArray data) {
|
||||||
packet_header_size = sizeof(PacketHeader) + customHeader().size();
|
packet_header_size = sizeof(PacketHeader) + customHeader().size();
|
||||||
if (data.size() < sizeof(PacketHeader)) {
|
if (data.size() < sizeof(PacketHeader)) {
|
||||||
|
|||||||
@@ -65,10 +65,7 @@ public:
|
|||||||
void setPacketSize(int size) { packet_size = size; }
|
void setPacketSize(int size) { packet_size = size; }
|
||||||
int packetSize() const { return packet_size; }
|
int packetSize() const { return packet_size; }
|
||||||
|
|
||||||
void setTimeout(double sec) {
|
void setTimeout(double sec);
|
||||||
timeout_ = sec;
|
|
||||||
diag.setDisconnectTimeout(sec);
|
|
||||||
}
|
|
||||||
double timeout() const { return timeout_; }
|
double timeout() const { return timeout_; }
|
||||||
|
|
||||||
void setCRCEnabled(bool en = true) { crc_enabled = en; }
|
void setCRCEnabled(bool en = true) { crc_enabled = en; }
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "piconfig.h"
|
#include "piconfig.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
/** \class PIConnection
|
/** \class PIConnection
|
||||||
* \brief Complex Input/Output point
|
* \brief Complex Input/Output point
|
||||||
@@ -160,7 +162,9 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
|||||||
PIConfig::Entry de = ce.getValue("device." + n);
|
PIConfig::Entry de = ce.getValue("device." + n);
|
||||||
dev->setThreadedReadBufferSize(de.getValue("bufferSize", dev->threadedReadBufferSize()).toInt());
|
dev->setThreadedReadBufferSize(de.getValue("bufferSize", dev->threadedReadBufferSize()).toInt());
|
||||||
PIDiagnostics * diag = diags_.value(dev, nullptr);
|
PIDiagnostics * diag = diags_.value(dev, nullptr);
|
||||||
if (diag) diag->setDisconnectTimeout(de.getValue("disconnectTimeout", diag->disconnectTimeout()).toFloat());
|
if (diag)
|
||||||
|
diag->setDisconnectTimeout(
|
||||||
|
PISystemTime::fromSeconds(de.getValue("disconnectTimeout", diag->disconnectTimeout().toSeconds()).toFloat()));
|
||||||
}
|
}
|
||||||
int added(0), padded(-1), tries(0);
|
int added(0), padded(-1), tries(0);
|
||||||
bool pdebug = debug();
|
bool pdebug = debug();
|
||||||
@@ -223,9 +227,11 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PIDiagnostics * diag = diags_.value(pe, nullptr);
|
PIDiagnostics * diag = diags_.value(pe, nullptr);
|
||||||
if (diag) diag->setDisconnectTimeout(e->getValue("disconnectTimeout", diag->disconnectTimeout()).toFloat());
|
if (diag)
|
||||||
|
diag->setDisconnectTimeout(
|
||||||
|
PISystemTime::fromSeconds(e->getValue("disconnectTimeout", diag->disconnectTimeout().toSeconds()).toFloat()));
|
||||||
pe->setPayloadSize(e->getValue("payloadSize", pe->payloadSize()).toInt());
|
pe->setPayloadSize(e->getValue("payloadSize", pe->payloadSize()).toInt());
|
||||||
pe->setTimeout(e->getValue("timeout", pe->timeout()).toDouble());
|
pe->setTimeout(PISystemTime::fromMilliseconds(e->getValue("timeout", pe->timeout().toMilliseconds()).toDouble()));
|
||||||
pe->setHeader(PIByteArray::fromUserInput(e->getValue("header", "").toString()));
|
pe->setHeader(PIByteArray::fromUserInput(e->getValue("header", "").toString()));
|
||||||
pe->setFooter(PIByteArray::fromUserInput(e->getValue("footer", "").toString()));
|
pe->setFooter(PIByteArray::fromUserInput(e->getValue("footer", "").toString()));
|
||||||
}
|
}
|
||||||
@@ -271,7 +277,7 @@ PIString PIConnection::makeConfig() const {
|
|||||||
ts << "device." << dname << " = " << d->constructFullPath() << " #s\n";
|
ts << "device." << dname << " = " << d->constructFullPath() << " #s\n";
|
||||||
ts << "device." << dname << ".bufferSize = " << d->threadedReadBufferSize() << " #n\n";
|
ts << "device." << dname << ".bufferSize = " << d->threadedReadBufferSize() << " #n\n";
|
||||||
PIDiagnostics * diag = diags_.value(const_cast<PIIODevice *>(d), nullptr);
|
PIDiagnostics * diag = diags_.value(const_cast<PIIODevice *>(d), nullptr);
|
||||||
if (diag) ts << "device." << dname << ".disconnectTimeout = " << diag->disconnectTimeout() << " #f\n";
|
if (diag) ts << "device." << dname << ".disconnectTimeout = " << diag->disconnectTimeout().toSeconds() << " #f\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto ite = extractors.makeIterator();
|
auto ite = extractors.makeIterator();
|
||||||
@@ -285,7 +291,7 @@ PIString PIConnection::makeConfig() const {
|
|||||||
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
||||||
}
|
}
|
||||||
PIDiagnostics * diag = diags_.value(ite.value()->extractor, nullptr);
|
PIDiagnostics * diag = diags_.value(ite.value()->extractor, nullptr);
|
||||||
if (diag) ts << prefix << ".disconnectTimeout = " << diag->disconnectTimeout() << " #f\n";
|
if (diag) ts << prefix << ".disconnectTimeout = " << diag->disconnectTimeout().toSeconds() << " #f\n";
|
||||||
ts << prefix << ".splitMode = ";
|
ts << prefix << ".splitMode = ";
|
||||||
switch (ite.value()->extractor->splitMode()) {
|
switch (ite.value()->extractor->splitMode()) {
|
||||||
case PIPacketExtractor::None: ts << "none"; break;
|
case PIPacketExtractor::None: ts << "none"; break;
|
||||||
@@ -297,7 +303,7 @@ PIString PIConnection::makeConfig() const {
|
|||||||
}
|
}
|
||||||
ts << " #s\n";
|
ts << " #s\n";
|
||||||
ts << prefix << ".payloadSize = " << ite.value()->extractor->payloadSize() << " #n\n";
|
ts << prefix << ".payloadSize = " << ite.value()->extractor->payloadSize() << " #n\n";
|
||||||
ts << prefix << ".timeout = " << ite.value()->extractor->timeout() << " #f\n";
|
ts << prefix << ".timeout = " << ite.value()->extractor->timeout().toMilliseconds() << " #f\n";
|
||||||
ts << prefix << ".header = " << ite.value()->extractor->header().toString() << " #s\n";
|
ts << prefix << ".header = " << ite.value()->extractor->header().toString() << " #s\n";
|
||||||
ts << prefix << ".footer = " << ite.value()->extractor->footer().toString() << " #s\n";
|
ts << prefix << ".footer = " << ite.value()->extractor->footer().toString() << " #s\n";
|
||||||
}
|
}
|
||||||
@@ -324,8 +330,8 @@ PIString PIConnection::makeConfig() const {
|
|||||||
if (dname.isEmpty()) dname = devPath(its.value()->devices[i]);
|
if (dname.isEmpty()) dname = devPath(its.value()->devices[i]);
|
||||||
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
||||||
}
|
}
|
||||||
double int_ = its.value()->int_;
|
auto int_ = its.value()->int_;
|
||||||
if (int_ > 0.) ts << prefix << ".frequency = " << (1000. / int_) << " #f\n";
|
if (!int_.isNull()) ts << prefix << ".frequency = " << (1. / int_.toSeconds()) << " #f\n";
|
||||||
if (!its.value()->sdata.isEmpty()) ts << prefix << ".fixedData = " << its.value()->sdata.toString() << " #s\n";
|
if (!its.value()->sdata.isEmpty()) ts << prefix << ".fixedData = " << its.value()->sdata.toString() << " #s\n";
|
||||||
}
|
}
|
||||||
ts << "[]\n";
|
ts << "[]\n";
|
||||||
@@ -342,7 +348,7 @@ PIIODevice * PIConnection::addDevice(const PIString & full_path, PIIODevice::Dev
|
|||||||
__device_pool__->lock();
|
__device_pool__->lock();
|
||||||
if (!diags_.value(dev, nullptr)) {
|
if (!diags_.value(dev, nullptr)) {
|
||||||
PIDiagnostics * d = new PIDiagnostics(false);
|
PIDiagnostics * d = new PIDiagnostics(false);
|
||||||
d->setInterval(100.);
|
d->setInterval(10_Hz);
|
||||||
diags_[dev] = d;
|
diags_[dev] = d;
|
||||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||||
__device_pool__->init();
|
__device_pool__->init();
|
||||||
@@ -476,7 +482,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
|||||||
__device_pool__->lock();
|
__device_pool__->lock();
|
||||||
if (!diags_.value(e->extractor, nullptr)) {
|
if (!diags_.value(e->extractor, nullptr)) {
|
||||||
PIDiagnostics * d = new PIDiagnostics(false);
|
PIDiagnostics * d = new PIDiagnostics(false);
|
||||||
d->setInterval(100.);
|
d->setInterval(10_Hz);
|
||||||
diags_[e->extractor] = d;
|
diags_[e->extractor] = d;
|
||||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||||
}
|
}
|
||||||
@@ -514,7 +520,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
|
|||||||
__device_pool__->lock();
|
__device_pool__->lock();
|
||||||
if (diags_.value(e->extractor, 0) == 0) {
|
if (diags_.value(e->extractor, 0) == 0) {
|
||||||
PIDiagnostics * d = new PIDiagnostics(false);
|
PIDiagnostics * d = new PIDiagnostics(false);
|
||||||
d->setInterval(100.);
|
d->setInterval(10_Hz);
|
||||||
diags_[e->extractor] = d;
|
diags_[e->extractor] = d;
|
||||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||||
}
|
}
|
||||||
@@ -728,7 +734,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
|
|||||||
if (!s) {
|
if (!s) {
|
||||||
s = new Sender(this);
|
s = new Sender(this);
|
||||||
s->setName(fname_);
|
s->setName(fname_);
|
||||||
s->int_ = 1000. / frequency;
|
s->int_ = PISystemTime::fromSeconds(1. / frequency);
|
||||||
senders[fname_] = s;
|
senders[fname_] = s;
|
||||||
}
|
}
|
||||||
PIIODevice * dev = devByString(full_path_name);
|
PIIODevice * dev = devByString(full_path_name);
|
||||||
@@ -797,9 +803,9 @@ PIByteArray PIConnection::senderFixedData(const PIString & name) const {
|
|||||||
float PIConnection::senderFrequency(const PIString & name) const {
|
float PIConnection::senderFrequency(const PIString & name) const {
|
||||||
Sender * s = senders.value(name, nullptr);
|
Sender * s = senders.value(name, nullptr);
|
||||||
if (!s) return -1.f;
|
if (!s) return -1.f;
|
||||||
double i = s->interval();
|
auto i = s->interval();
|
||||||
if (i == 0.) return 0.f;
|
if (i.isNull()) return 0.f;
|
||||||
return 1000. / s->interval();
|
return 1. / s->interval().toSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -865,14 +871,14 @@ void PIConnection::stopAllThreadedReads() {
|
|||||||
void PIConnection::stopSender(const PIString & name) {
|
void PIConnection::stopSender(const PIString & name) {
|
||||||
Sender * s = senders.value(name, nullptr);
|
Sender * s = senders.value(name, nullptr);
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
if (s->isRunning()) s->stop();
|
if (s->isRunning()) s->stopAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIConnection::stopAllSenders() {
|
void PIConnection::stopAllSenders() {
|
||||||
for (auto s = senders.begin(); s != senders.end(); s++) {
|
for (auto s = senders.begin(); s != senders.end(); s++) {
|
||||||
if (!s.value()) continue;
|
if (!s.value()) continue;
|
||||||
if (s.value()->isRunning()) s.value()->stop();
|
if (s.value()->isRunning()) s.value()->stopAndWait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,7 +955,7 @@ bool PIConnection::isFakeMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIConnection::DevicePool::DevicePool(): PIThread(false, 10) {
|
PIConnection::DevicePool::DevicePool(): PIThread(false, 100_Hz) {
|
||||||
setName("PIConnection::DevicePool");
|
setName("PIConnection::DevicePool");
|
||||||
needLockRun(true);
|
needLockRun(true);
|
||||||
fake = false;
|
fake = false;
|
||||||
@@ -960,7 +966,7 @@ PIConnection::DevicePool::~DevicePool() {}
|
|||||||
|
|
||||||
|
|
||||||
void PIConnection::DevicePool::init() {
|
void PIConnection::DevicePool::init() {
|
||||||
if (!isRunning()) start(100);
|
if (!isRunning()) start(10_Hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1111,7 +1117,7 @@ PIConnection::DevicePool::DeviceData::~DeviceData() {
|
|||||||
if (rthread) {
|
if (rthread) {
|
||||||
rthread->stop();
|
rthread->stop();
|
||||||
if (dev) dev->interrupt();
|
if (dev) dev->interrupt();
|
||||||
if (!rthread->waitForFinish(1000)) rthread->terminate();
|
if (!rthread->waitForFinish(1_s)) rthread->terminate();
|
||||||
delete rthread;
|
delete rthread;
|
||||||
rthread = nullptr;
|
rthread = nullptr;
|
||||||
}
|
}
|
||||||
@@ -1128,7 +1134,7 @@ void PIConnection::DevicePool::run() {
|
|||||||
for (PIConnection * c: conns) {
|
for (PIConnection * c: conns) {
|
||||||
for (auto d = c->diags_.begin(); d != c->diags_.end(); d++) {
|
for (auto d = c->diags_.begin(); d != c->diags_.end(); d++) {
|
||||||
if (!d.value()) continue;
|
if (!d.value()) continue;
|
||||||
d.value()->tick(0, 1);
|
d.value()->tick(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1143,9 +1149,9 @@ void __DevicePool_threadReadDP(void * ddp) {
|
|||||||
}
|
}
|
||||||
if (dev->isClosed()) {
|
if (dev->isClosed()) {
|
||||||
if (!dev->open()) {
|
if (!dev->open()) {
|
||||||
|
auto timeout = dev->reopenTimeout();
|
||||||
PITimeMeasurer tm;
|
PITimeMeasurer tm;
|
||||||
int timeout = dev->reopenTimeout();
|
while (tm.elapsed() < timeout) {
|
||||||
while (tm.elapsed_m() < timeout) {
|
|
||||||
if (dd->rthread->isStopping()) return;
|
if (dd->rthread->isStopping()) return;
|
||||||
piMSleep(50);
|
piMSleep(50);
|
||||||
}
|
}
|
||||||
@@ -1204,13 +1210,13 @@ PIConnection::Extractor::~Extractor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_), int_(0.f) {
|
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) {
|
||||||
setName("__S__.PIConnection.Sender");
|
setName("__S__.PIConnection.Sender");
|
||||||
needLockRun(true);
|
needLockRun(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIConnection::Sender::tick(void *, int) {
|
void PIConnection::Sender::tick(int) {
|
||||||
if (!parent) return;
|
if (!parent) return;
|
||||||
PIByteArray data;
|
PIByteArray data;
|
||||||
if (!sdata.isEmpty())
|
if (!sdata.isEmpty())
|
||||||
|
|||||||
@@ -387,12 +387,12 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Sender(PIConnection * parent_ = 0);
|
Sender(PIConnection * parent_ = 0);
|
||||||
~Sender() { stop(); }
|
~Sender() { stopAndWait(); }
|
||||||
PIConnection * parent;
|
PIConnection * parent;
|
||||||
PIVector<PIIODevice *> devices;
|
PIVector<PIIODevice *> devices;
|
||||||
PIByteArray sdata;
|
PIByteArray sdata;
|
||||||
float int_;
|
PISystemTime int_;
|
||||||
void tick(void *, int) override;
|
void tick(int) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
PIMap<PIString, Extractor *> extractors;
|
PIMap<PIString, Extractor *> extractors;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "pidiagnostics.h"
|
#include "pidiagnostics.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
|
|
||||||
/** \class PIDiagnostics
|
/** \class PIDiagnostics
|
||||||
* \brief Connection quality diagnostics
|
* \brief Connection quality diagnostics
|
||||||
@@ -42,18 +44,18 @@ PIDiagnostics::State::State() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) {
|
PIDiagnostics::PIDiagnostics(bool start_): PITimer() {
|
||||||
// piCout << "PIDiagnostics construct";
|
// piCout << "PIDiagnostics construct";
|
||||||
setInterval(100);
|
setInterval(10_Hz);
|
||||||
reset();
|
reset();
|
||||||
setDisconnectTimeout(3.);
|
setDisconnectTimeout(3_s);
|
||||||
changeDisconnectTimeout(3.);
|
changeDisconnectTimeout(3_s);
|
||||||
if (start_) PITimer::start(100);
|
if (start_) PITimer::start(10_Hz);
|
||||||
// piCout << "PIDiagnostics construct done";
|
// piCout << "PIDiagnostics construct done";
|
||||||
}
|
}
|
||||||
|
|
||||||
PIDiagnostics::~PIDiagnostics() {
|
PIDiagnostics::~PIDiagnostics() {
|
||||||
PITimer::stop();
|
PITimer::stopAndWait();
|
||||||
// piCout << "~PIDiagnostics start...";
|
// piCout << "~PIDiagnostics start...";
|
||||||
// piCout << "~PIDiagnostics done!";
|
// piCout << "~PIDiagnostics done!";
|
||||||
}
|
}
|
||||||
@@ -92,14 +94,14 @@ PIString PIDiagnostics::sendSpeed() const {
|
|||||||
|
|
||||||
|
|
||||||
void PIDiagnostics::start() {
|
void PIDiagnostics::start() {
|
||||||
PITimer::start(100.);
|
PITimer::start(10_Hz);
|
||||||
changeDisconnectTimeout(disconn_);
|
changeDisconnectTimeout(disconn_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIDiagnostics::start(double msecs) {
|
void PIDiagnostics::start(double msecs) {
|
||||||
if (msecs > 0.) {
|
if (msecs > 0.) {
|
||||||
PITimer::start(msecs);
|
PITimer::start(PISystemTime::fromMilliseconds(msecs));
|
||||||
changeDisconnectTimeout(disconn_);
|
changeDisconnectTimeout(disconn_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +110,7 @@ void PIDiagnostics::start(double msecs) {
|
|||||||
void PIDiagnostics::reset() {
|
void PIDiagnostics::reset() {
|
||||||
mutex_state.lock();
|
mutex_state.lock();
|
||||||
cur_state = State();
|
cur_state = State();
|
||||||
if (disconn_ != 0.) {
|
if (disconn_.isNotNull()) {
|
||||||
int hist_size = history_rec.size();
|
int hist_size = history_rec.size();
|
||||||
history_rec.clear();
|
history_rec.clear();
|
||||||
history_send.clear();
|
history_send.clear();
|
||||||
@@ -150,16 +152,16 @@ void PIDiagnostics::sended(int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIDiagnostics::tick(void *, int) {
|
void PIDiagnostics::tick(int) {
|
||||||
mutex_state.lock();
|
mutex_state.lock();
|
||||||
// piCoutObj << "lock";
|
// piCoutObj << "lock";
|
||||||
int tcnt_recv = 0;
|
int tcnt_recv = 0;
|
||||||
int tcnt_send = 0;
|
int tcnt_send = 0;
|
||||||
Entry send = calcHistory(history_send, tcnt_send);
|
Entry send = calcHistory(history_send, tcnt_send);
|
||||||
Entry recv = calcHistory(history_rec, tcnt_recv);
|
Entry recv = calcHistory(history_rec, tcnt_recv);
|
||||||
float itr = disconn_ * (float(tcnt_recv) / history_rec.size());
|
float itr = disconn_.toSeconds() * (float(tcnt_recv) / history_rec.size());
|
||||||
float its = disconn_ * (float(tcnt_send) / history_send.size());
|
float its = disconn_.toSeconds() * (float(tcnt_send) / history_send.size());
|
||||||
float hz = interval() / 1000.f;
|
float hz = 1. / interval().toSeconds();
|
||||||
if (tcnt_recv == 0) {
|
if (tcnt_recv == 0) {
|
||||||
cur_state.integral_freq = cur_state.immediate_freq = 0;
|
cur_state.integral_freq = cur_state.immediate_freq = 0;
|
||||||
cur_state.received_packets_per_sec = cur_state.received_bytes_per_sec = 0;
|
cur_state.received_packets_per_sec = cur_state.received_bytes_per_sec = 0;
|
||||||
@@ -229,16 +231,15 @@ PIDiagnostics::Entry PIDiagnostics::calcHistory(PIQueue<Entry> & hist, int & cnt
|
|||||||
|
|
||||||
|
|
||||||
void PIDiagnostics::propertyChanged(const char *) {
|
void PIDiagnostics::propertyChanged(const char *) {
|
||||||
float disct = property("disconnectTimeout").toFloat();
|
changeDisconnectTimeout(property("disconnectTimeout").toSystemTime());
|
||||||
changeDisconnectTimeout(disct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIDiagnostics::changeDisconnectTimeout(float disct) {
|
void PIDiagnostics::changeDisconnectTimeout(PISystemTime disct) {
|
||||||
mutex_state.lock();
|
mutex_state.lock();
|
||||||
disconn_ = piMaxf(disct, interval() / 1000.f);
|
disconn_ = piMax(disct, interval());
|
||||||
if (interval() > 0) {
|
if (!interval().isNull()) {
|
||||||
int hist_size = piClampi(int(disconn_ * 1000.f / float(interval())), 1, 65536);
|
int hist_size = piClampi(piRound(disconn_.toSeconds() / interval().toSeconds()), 1, 65536);
|
||||||
// piCoutObj << hist_size << interval();
|
// piCoutObj << hist_size << interval();
|
||||||
history_rec.resize(hist_size);
|
history_rec.resize(hist_size);
|
||||||
history_send.resize(hist_size);
|
history_send.resize(hist_size);
|
||||||
|
|||||||
@@ -75,13 +75,15 @@ public:
|
|||||||
PIDiagnostics::State state() const;
|
PIDiagnostics::State state() const;
|
||||||
|
|
||||||
//! Returns period of full disconnect in seconds and period of averaging frequency
|
//! Returns period of full disconnect in seconds and period of averaging frequency
|
||||||
float disconnectTimeout() const { return disconn_; }
|
PISystemTime disconnectTimeout() const { return disconn_; }
|
||||||
|
|
||||||
//! 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) DEPRECATEDM("use setDisconnectTimeout(PISystemTime)") {
|
||||||
|
setDisconnectTimeout(PISystemTime::fromSeconds(s));
|
||||||
|
}
|
||||||
|
|
||||||
//! Returns period of full disconnect and period of averaging frequency
|
//! Returns period of full disconnect and period of averaging frequency
|
||||||
void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm.toSeconds()); }
|
void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm); }
|
||||||
|
|
||||||
//! Returns connection quality
|
//! Returns connection quality
|
||||||
PIDiagnostics::Quality quality() const;
|
PIDiagnostics::Quality quality() const;
|
||||||
@@ -139,13 +141,13 @@ private:
|
|||||||
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);
|
||||||
|
|
||||||
void tick(void *, int) override;
|
void tick(int) override;
|
||||||
Entry calcHistory(PIQueue<Entry> & hist, int & cnt);
|
Entry calcHistory(PIQueue<Entry> & hist, int & cnt);
|
||||||
void propertyChanged(const char *) override;
|
void propertyChanged(const char *) override;
|
||||||
void changeDisconnectTimeout(float disct);
|
void changeDisconnectTimeout(PISystemTime disct);
|
||||||
|
|
||||||
PIQueue<Entry> history_rec, history_send;
|
PIQueue<Entry> history_rec, history_send;
|
||||||
float disconn_ = 0.f;
|
PISystemTime disconn_;
|
||||||
State cur_state;
|
State cur_state;
|
||||||
mutable PIMutex mutex_state;
|
mutable PIMutex mutex_state;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ void PIPacketExtractor::construct() {
|
|||||||
func_footer = nullptr;
|
func_footer = nullptr;
|
||||||
func_payload = nullptr;
|
func_payload = nullptr;
|
||||||
setPayloadSize(0);
|
setPayloadSize(0);
|
||||||
setTimeout(100);
|
setTimeout(100_ms);
|
||||||
#ifdef MICRO_PIP
|
#ifdef MICRO_PIP
|
||||||
setThreadedReadBufferSize(512);
|
setThreadedReadBufferSize(512);
|
||||||
#else
|
#else
|
||||||
@@ -115,7 +115,7 @@ void PIPacketExtractor::propertyChanged(const char *) {
|
|||||||
dataSize = property("payloadSize").toInt();
|
dataSize = property("payloadSize").toInt();
|
||||||
src_header = property("header").toByteArray();
|
src_header = property("header").toByteArray();
|
||||||
src_footer = property("footer").toByteArray();
|
src_footer = property("footer").toByteArray();
|
||||||
time_ = property("timeout").toDouble();
|
time_ = property("timeout").toSystemTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
Footer /** Detect packets with \a footer() and leading \a payloadSize() */,
|
Footer /** Detect packets with \a footer() and leading \a payloadSize() */,
|
||||||
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */,
|
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */,
|
||||||
Size /** Detect packets with \a packetSize() */,
|
Size /** Detect packets with \a packetSize() */,
|
||||||
Timeout /** Wait for first read, then read for \a timeout() milliseconds */
|
Timeout /** Wait for first read, then read for \a timeout() */
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Contructs extractor with child device "device_" and extract algorithm "mode"
|
//! Contructs extractor with child device "device_" and extract algorithm "mode"
|
||||||
@@ -87,8 +87,8 @@ public:
|
|||||||
//! Set footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
//! Set footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
||||||
void setFooter(const PIByteArray & data);
|
void setFooter(const PIByteArray & data);
|
||||||
|
|
||||||
//! Set timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
//! Set timeout, used for PIPacketExtractor::Timeout algorithm
|
||||||
void setTimeout(double msecs) { setProperty("timeout", msecs); }
|
void setTimeout(PISystemTime tm) { setProperty("timeout", tm); }
|
||||||
|
|
||||||
|
|
||||||
//! Returns current extract algorithm
|
//! Returns current extract algorithm
|
||||||
@@ -105,7 +105,7 @@ public:
|
|||||||
PIByteArray footer() const { return src_footer; }
|
PIByteArray footer() const { return src_footer; }
|
||||||
|
|
||||||
//! Returns current timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
//! Returns current timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||||
double timeout() const { return time_; }
|
PISystemTime timeout() const { return time_; }
|
||||||
|
|
||||||
//! Returns missed by validating functions bytes count
|
//! Returns missed by validating functions bytes count
|
||||||
ullong missedBytes() const { return missed; }
|
ullong missedBytes() const { return missed; }
|
||||||
@@ -165,7 +165,7 @@ private:
|
|||||||
PacketExtractorFooterFunc func_footer;
|
PacketExtractorFooterFunc func_footer;
|
||||||
SplitMode mode_;
|
SplitMode mode_;
|
||||||
int dataSize, packetSize_pending, footerInd;
|
int dataSize, packetSize_pending, footerInd;
|
||||||
double time_;
|
PISystemTime time_;
|
||||||
bool header_found;
|
bool header_found;
|
||||||
ullong missed;
|
ullong missed;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
#include "pigeomodule.h"
|
#include "pigeomodule.h"
|
||||||
#include "piiodevicesmodule.h"
|
#include "piiodevicesmodule.h"
|
||||||
#include "piioutilsmodule.h"
|
#include "piioutilsmodule.h"
|
||||||
|
#include "piliterals.h"
|
||||||
#include "pimathmodule.h"
|
#include "pimathmodule.h"
|
||||||
|
#include "pistatemachinemodule.h"
|
||||||
#include "pisystemmodule.h"
|
#include "pisystemmodule.h"
|
||||||
#include "pithreadmodule.h"
|
#include "pithreadmodule.h"
|
||||||
|
|
||||||
|
|||||||
37
libs/main/state_machine/pistatemachine.cpp
Normal file
37
libs/main/state_machine/pistatemachine.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pistatemachine.h"
|
||||||
|
|
||||||
|
|
||||||
|
PIStateMachine::PIStateMachine(const PIString & n): PIStateBase(n) {
|
||||||
|
is_root = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIStateMachine::start() {
|
||||||
|
setActiveRecursive(false);
|
||||||
|
is_running = PIStateBase::start();
|
||||||
|
return is_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateMachine::onFinish() {
|
||||||
|
need_finish = true;
|
||||||
|
}
|
||||||
78
libs/main/state_machine/pistatemachine.h
Normal file
78
libs/main/state_machine/pistatemachine.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*! \file pistatemachine.h
|
||||||
|
* \ingroup StateMachine
|
||||||
|
* \~\brief
|
||||||
|
* \~english State machine.
|
||||||
|
* \~russian Машина состояний.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pistatemachine_H
|
||||||
|
#define pistatemachine_H
|
||||||
|
|
||||||
|
#include "pistatemachine_state.h"
|
||||||
|
#include "pistatemachine_transition.h"
|
||||||
|
|
||||||
|
|
||||||
|
//! \ingroup StateMachine
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english
|
||||||
|
//! \~russian
|
||||||
|
class PIP_EXPORT PIStateMachine: public PIStateBase {
|
||||||
|
public:
|
||||||
|
PIStateMachine(const PIString & n = {});
|
||||||
|
|
||||||
|
bool start();
|
||||||
|
bool isRunning() const { return is_running; }
|
||||||
|
void addOnFinish(std::function<void()> f) { on_finish = f; }
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
bool postEvent(int event_id, Args... args) {
|
||||||
|
if (!is_running) return false;
|
||||||
|
need_finish = false;
|
||||||
|
PIScopeExitCall exit_call([this] {
|
||||||
|
if (need_finish) {
|
||||||
|
is_running = false;
|
||||||
|
if (on_finish) on_finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
PIVector<PIStateBase *> active_states;
|
||||||
|
gatherActiveStates(active_states);
|
||||||
|
// piCout << "active" << active_states;
|
||||||
|
for (auto * s: active_states) {
|
||||||
|
for (auto * t: s->transitions) {
|
||||||
|
if (t->eventID != event_id) continue;
|
||||||
|
if (t->testGuard(args...)) {
|
||||||
|
t->trigger();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onFinish() override;
|
||||||
|
|
||||||
|
bool is_running = false, need_finish = false;
|
||||||
|
std::function<void()> on_finish;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
82
libs/main/state_machine/pistatemachine_base.h
Normal file
82
libs/main/state_machine/pistatemachine_base.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*! \file pistatemachine_base.h
|
||||||
|
* \ingroup StateMachine
|
||||||
|
* \~\brief
|
||||||
|
* \~english Some template helpers for PIStateMachine
|
||||||
|
* \~russian Несколько шаблонов для PIStateMachine
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
Some template helpers for PIStateMachine
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pistatemachine_base_H
|
||||||
|
#define pistatemachine_base_H
|
||||||
|
|
||||||
|
#include "piconstchars.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PIStateMachineHelpers {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct FunctionType {
|
||||||
|
using Type = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Args>
|
||||||
|
struct FunctionType<Ret (Class::*)(Args...) const> {
|
||||||
|
using Type = std::function<Ret(Args...)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionBase {
|
||||||
|
public:
|
||||||
|
virtual ~FunctionBase() {}
|
||||||
|
virtual uint formatHash() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
class Function: public FunctionBase {
|
||||||
|
public:
|
||||||
|
uint formatHash() override {
|
||||||
|
static uint ret = PIConstChars(typeid(std::function<void(Args...)>).name()).hash();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::function<bool(Args...)> func;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename... Args>
|
||||||
|
FunctionBase * makeFunction(std::function<Ret(Args...)> func) {
|
||||||
|
auto * ret = new Function<Args...>();
|
||||||
|
ret->func = func;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PIStateMachineHelpers
|
||||||
|
|
||||||
|
class PITransitionBase;
|
||||||
|
class PITransitionTimeout;
|
||||||
|
class PIStateBase;
|
||||||
|
class PIStateLambda;
|
||||||
|
class PIStateFinal;
|
||||||
|
class PIStateMachine;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
225
libs/main/state_machine/pistatemachine_state.cpp
Normal file
225
libs/main/state_machine/pistatemachine_state.cpp
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pistatemachine_state.h"
|
||||||
|
|
||||||
|
#include "pistatemachine_transition.h"
|
||||||
|
|
||||||
|
|
||||||
|
PIStateBase::~PIStateBase() {
|
||||||
|
piDeleteAll(transitions);
|
||||||
|
piDeleteAll(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIVector<PIStateBase *> PIStateBase::activeChildren() const {
|
||||||
|
if (!isParallel()) {
|
||||||
|
if (active_state) return {active_state};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (isActive()) return children;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIVector<PIStateBase *> PIStateBase::activeAtomics() const {
|
||||||
|
PIVector<PIStateBase *> ret;
|
||||||
|
gatherActiveAtomicStates(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::addState(PIStateBase * s) {
|
||||||
|
children << s;
|
||||||
|
s->parent_state = this;
|
||||||
|
propagateRoot(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::addStates(PIVector<PIStateBase *> s) {
|
||||||
|
children << s;
|
||||||
|
for (auto * i: s)
|
||||||
|
i->parent_state = this;
|
||||||
|
propagateRoot(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::setInitialState(PIStateBase * s) {
|
||||||
|
if (children.contains(s))
|
||||||
|
initial_state = s;
|
||||||
|
else
|
||||||
|
initial_state = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionBase * PIStateBase::addTransition(PIStateBase * target, int event_id) {
|
||||||
|
PITransitionBase * ret = new PITransitionBase(this, target, event_id);
|
||||||
|
ret->root = root;
|
||||||
|
transitions << ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionTimeout * PIStateBase::addTimeoutTransition(PIStateBase * target, PISystemTime timeout) {
|
||||||
|
PITransitionTimeout * ret = new PITransitionTimeout(this, target, timeout);
|
||||||
|
ret->root = root;
|
||||||
|
transitions << ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::print(PIString prefix) {
|
||||||
|
auto ac = activeChildren();
|
||||||
|
PICout(PICoutManipulators::AddNone) << prefix << "[" << (isActive() ? "*" : " ") << "] \"" << getName() << "\"";
|
||||||
|
if (ac.isNotEmpty())
|
||||||
|
piCout << ", active" << activeChildren();
|
||||||
|
else
|
||||||
|
piCout << "";
|
||||||
|
prefix += " ";
|
||||||
|
for (auto * c: children)
|
||||||
|
c->print(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIStateBase::start() {
|
||||||
|
if (isActive()) return true;
|
||||||
|
if (isAtomic()) {
|
||||||
|
setActive(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!isParallel()) {
|
||||||
|
if (initial_state) {
|
||||||
|
setActive(true);
|
||||||
|
return initial_state->start();
|
||||||
|
} else {
|
||||||
|
piCout << "error:" << getName() << "no initial state!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setActive(true);
|
||||||
|
for (auto * s: children) {
|
||||||
|
if (!s->start()) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::setActive(bool yes) {
|
||||||
|
bool prev_active = is_active;
|
||||||
|
is_active = yes;
|
||||||
|
if (parent_state && yes) parent_state->childActived(this);
|
||||||
|
if (!prev_active && is_active) {
|
||||||
|
onEnter();
|
||||||
|
for (auto * t: transitions)
|
||||||
|
t->enabled();
|
||||||
|
// if (isParallel()) setChildrenActive(true);
|
||||||
|
}
|
||||||
|
if (prev_active && !is_active) {
|
||||||
|
active_state = nullptr;
|
||||||
|
if (isParallel()) setChildrenActiveRecursive(false);
|
||||||
|
onExit();
|
||||||
|
for (auto * t: transitions)
|
||||||
|
t->disabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::setActiveRecursive(bool yes) {
|
||||||
|
if (yes) setActive(true);
|
||||||
|
for (auto * c: children)
|
||||||
|
c->setActiveRecursive(yes);
|
||||||
|
if (!yes) setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::setChildrenActive(bool yes) {
|
||||||
|
for (auto * c: children)
|
||||||
|
c->setActive(yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::setChildrenActiveRecursive(bool yes) {
|
||||||
|
for (auto * c: children)
|
||||||
|
c->setActiveRecursive(yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::activeChild(PIStateBase * c) {
|
||||||
|
setActive(true);
|
||||||
|
if (isParallel())
|
||||||
|
for (auto * s: children) {
|
||||||
|
if (c != s) s->start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!c) c = initial_state;
|
||||||
|
if (c) c->setActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::childActived(PIStateBase * s) {
|
||||||
|
if (!isParallel()) {
|
||||||
|
active_state = s;
|
||||||
|
if (active_state->isFinal()) onFinish();
|
||||||
|
} else
|
||||||
|
active_state = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::propagateRoot(PIStateMachine * r) {
|
||||||
|
if (is_root)
|
||||||
|
root = reinterpret_cast<PIStateMachine *>(this);
|
||||||
|
else
|
||||||
|
root = r;
|
||||||
|
for (auto * t: transitions)
|
||||||
|
t->root = root;
|
||||||
|
for (auto * c: children)
|
||||||
|
c->propagateRoot(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::gatherActiveStates(PIVector<PIStateBase *> & output) {
|
||||||
|
for (auto * c: children)
|
||||||
|
c->gatherActiveStates(output);
|
||||||
|
if (isActive()) output << this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::gatherActiveAtomicStates(PIVector<PIStateBase *> & output) const {
|
||||||
|
for (auto * c: children)
|
||||||
|
c->gatherActiveAtomicStates(output);
|
||||||
|
if (isActive() && isAtomic()) output << const_cast<PIStateBase *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIStateBase::gatherPathToMachine(PIVector<PIStateBase *> & output) {
|
||||||
|
if (isStateMachine()) return;
|
||||||
|
output << this;
|
||||||
|
if (parent()) parent()->gatherPathToMachine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIVector<PIStateBase *> PIStateBase::pathToMachine() {
|
||||||
|
PIVector<PIStateBase *> ret;
|
||||||
|
gatherPathToMachine(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
142
libs/main/state_machine/pistatemachine_state.h
Normal file
142
libs/main/state_machine/pistatemachine_state.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*! \file pistatemachine_state.h
|
||||||
|
* \ingroup StateMachine
|
||||||
|
* \~\brief
|
||||||
|
* \~english State machine node
|
||||||
|
* \~russian Узел машины состояний
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine node
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pistatemachine_state_H
|
||||||
|
#define pistatemachine_state_H
|
||||||
|
|
||||||
|
#include "pistatemachine_base.h"
|
||||||
|
#include "pistring.h"
|
||||||
|
#include "pisystemtime.h"
|
||||||
|
|
||||||
|
|
||||||
|
//! \ingroup StateMachine
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english
|
||||||
|
//! \~russian
|
||||||
|
class PIP_EXPORT PIStateBase {
|
||||||
|
friend class PIStateMachine;
|
||||||
|
friend class PITransitionBase;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PIStateBase(const PIString & n = {}): name_(n) { ; }
|
||||||
|
virtual ~PIStateBase();
|
||||||
|
|
||||||
|
virtual void onEnter() {}
|
||||||
|
virtual void onExit() {}
|
||||||
|
virtual void onFinish() {}
|
||||||
|
|
||||||
|
PIStateMachine * machine() const { return root; }
|
||||||
|
PIStateBase * parent() const { return parent_state; }
|
||||||
|
PIStateBase * activeChild() const { return active_state; }
|
||||||
|
PIVector<PIStateBase *> activeChildren() const;
|
||||||
|
PIVector<PIStateBase *> activeAtomics() const;
|
||||||
|
|
||||||
|
void addState(PIStateBase * s);
|
||||||
|
void addStates(PIVector<PIStateBase *> s);
|
||||||
|
void setInitialState(PIStateBase * s);
|
||||||
|
|
||||||
|
PITransitionBase * addTransition(PIStateBase * target, int event_id);
|
||||||
|
PITransitionTimeout * addTimeoutTransition(PIStateBase * target, PISystemTime timeout);
|
||||||
|
|
||||||
|
void setParallel(bool yes) { is_parallel = yes; }
|
||||||
|
|
||||||
|
const PIString & getName() const { return name_; }
|
||||||
|
bool isStateMachine() const { return is_root; }
|
||||||
|
bool isActive() const { return is_active; }
|
||||||
|
bool isParallel() const { return is_parallel; }
|
||||||
|
bool isFinal() const { return is_final; }
|
||||||
|
bool isAtomic() const { return children.isEmpty(); }
|
||||||
|
bool isCompound() const { return children.isNotEmpty(); }
|
||||||
|
const PIVector<PIStateBase *> & getChildren() const { return children; }
|
||||||
|
const PIVector<PITransitionBase *> & getTransitions() const { return transitions; }
|
||||||
|
|
||||||
|
void print(PIString prefix = {});
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool start();
|
||||||
|
void setActive(bool yes);
|
||||||
|
void setActiveRecursive(bool yes);
|
||||||
|
void setChildrenActive(bool yes);
|
||||||
|
void setChildrenActiveRecursive(bool yes);
|
||||||
|
void activeChild(PIStateBase * c);
|
||||||
|
void childActived(PIStateBase * s);
|
||||||
|
void propagateRoot(PIStateMachine * r);
|
||||||
|
void gatherActiveStates(PIVector<PIStateBase *> & output);
|
||||||
|
void gatherActiveAtomicStates(PIVector<PIStateBase *> & output) const;
|
||||||
|
void gatherPathToMachine(PIVector<PIStateBase *> & output);
|
||||||
|
PIVector<PIStateBase *> pathToMachine();
|
||||||
|
|
||||||
|
bool is_active = false, is_root = false, is_parallel = false, is_final = false;
|
||||||
|
PIVector<PIStateBase *> children;
|
||||||
|
PIVector<PITransitionBase *> transitions;
|
||||||
|
PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr;
|
||||||
|
PIStateMachine * root = nullptr;
|
||||||
|
PIString name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PIP_EXPORT PIStateLambda: public PIStateBase {
|
||||||
|
public:
|
||||||
|
PIStateLambda(std::function<void()> on_enter, std::function<void()> on_exit = nullptr, const PIString & n = {}): PIStateBase(n) {
|
||||||
|
enter = on_enter;
|
||||||
|
exit = on_exit;
|
||||||
|
}
|
||||||
|
void onEnter() override {
|
||||||
|
if (enter) enter();
|
||||||
|
}
|
||||||
|
void onExit() override {
|
||||||
|
if (exit) exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> enter, exit;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PIP_EXPORT PIStateFinal: public PIStateBase {
|
||||||
|
public:
|
||||||
|
PIStateFinal(std::function<void()> on_finish = nullptr, const PIString & n = {}): PIStateBase(n) {
|
||||||
|
is_final = true;
|
||||||
|
enter = on_finish;
|
||||||
|
}
|
||||||
|
void onEnter() override {
|
||||||
|
if (enter) enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> enter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline PICout operator<<(PICout c, PIStateBase * s) {
|
||||||
|
if (!s)
|
||||||
|
c << "state(nullptr)";
|
||||||
|
else
|
||||||
|
c << ("state(\"" + s->getName() + "\")");
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
122
libs/main/state_machine/pistatemachine_transition.cpp
Normal file
122
libs/main/state_machine/pistatemachine_transition.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pistatemachine_transition.h"
|
||||||
|
|
||||||
|
#include "pistatemachine_state.h"
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionBase::PITransitionBase(PIStateBase * source, PIStateBase * target, int event_id) {
|
||||||
|
target_state = target;
|
||||||
|
source_state = source;
|
||||||
|
eventID = event_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionBase::~PITransitionBase() {
|
||||||
|
piDeleteSafety(guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionBase * PITransitionBase::addAction(std::function<void()> a) {
|
||||||
|
action = a;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PITransitionBase::makeAction() {
|
||||||
|
if (action) action();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PITransitionBase::trigger() {
|
||||||
|
if (!target_state || (source_state == target_state)) {
|
||||||
|
makeAction();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// source_state->setActiveRecursive(false);
|
||||||
|
auto source_path = source_state->pathToMachine();
|
||||||
|
auto target_path = target_state->pathToMachine();
|
||||||
|
auto source_target_path = target_path;
|
||||||
|
source_target_path.reverse();
|
||||||
|
// piCout << "source_path" << source_path;
|
||||||
|
// piCout << "target_path" << target_path;
|
||||||
|
ssize_t common_count = 0;
|
||||||
|
for (common_count = 0; common_count < piMini(source_path.size_s(), target_path.size_s()); ++common_count) {
|
||||||
|
// piCout << "check" << source_path[source_path.size_s() - common_count - 1] << target_path[target_path.size_s() - common_count -
|
||||||
|
// 1];
|
||||||
|
if (source_path[source_path.size_s() - common_count - 1] != target_path[target_path.size_s() - common_count - 1]) {
|
||||||
|
// piCout << "diff" << common_count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// piCout << "common" << common_count;
|
||||||
|
source_path.remove(source_path.size_s() - common_count, common_count);
|
||||||
|
target_path.remove(target_path.size_s() - common_count, common_count);
|
||||||
|
// piCout << "source_target_path" << source_target_path;
|
||||||
|
// piCout << "source_path" << source_path;
|
||||||
|
// piCout << "target_path" << target_path;
|
||||||
|
// piCout << "source_state before" << source_state;
|
||||||
|
for (int i = target_path.size_s() - 1; i >= 0; --i) {
|
||||||
|
// piCout << "check" << source_state->activeChild() << target_path[i];
|
||||||
|
if (source_state->activeChild() == target_path[i])
|
||||||
|
source_state = target_path[i];
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// piCout << "source_state after" << source_state;
|
||||||
|
source_state->setChildrenActiveRecursive(false);
|
||||||
|
for (auto * s: source_path)
|
||||||
|
s->setActive(false);
|
||||||
|
makeAction();
|
||||||
|
for (int i = 0; i < source_target_path.size_s(); ++i) {
|
||||||
|
if (i == source_target_path.size_s() - 1)
|
||||||
|
source_target_path[i]->start();
|
||||||
|
else
|
||||||
|
source_target_path[i]->activeChild(source_target_path[i + 1]);
|
||||||
|
}
|
||||||
|
if (target_state->isCompound()) target_state->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PITransitionTimeout
|
||||||
|
|
||||||
|
PITransitionTimeout::PITransitionTimeout(PIStateBase * source, PIStateBase * target, PISystemTime timeout)
|
||||||
|
: PITransitionBase(source, target, 0) {
|
||||||
|
timer.setInterval(timeout);
|
||||||
|
timer.setSlot([this] {
|
||||||
|
trigger();
|
||||||
|
timer.stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITransitionTimeout::~PITransitionTimeout() {
|
||||||
|
timer.stopAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PITransitionTimeout::enabled() {
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PITransitionTimeout::disabled() {
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
101
libs/main/state_machine/pistatemachine_transition.h
Normal file
101
libs/main/state_machine/pistatemachine_transition.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*! \file pistatemachine_transition.h
|
||||||
|
* \ingroup StateMachine
|
||||||
|
* \~\brief
|
||||||
|
* \~english State machine transition
|
||||||
|
* \~russian Переход машины состояний
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
State machine transition
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pistatemachine_transition_H
|
||||||
|
#define pistatemachine_transition_H
|
||||||
|
|
||||||
|
#include "pistatemachine_base.h"
|
||||||
|
#include "pitimer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//! \ingroup StateMachine
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english
|
||||||
|
//! \~russian
|
||||||
|
class PIP_EXPORT PITransitionBase {
|
||||||
|
friend class PIStateMachine;
|
||||||
|
friend class PIStateBase;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PITransitionBase(PIStateBase * source, PIStateBase * target, int event_id);
|
||||||
|
virtual ~PITransitionBase();
|
||||||
|
|
||||||
|
PIStateMachine * machine() const { return root; }
|
||||||
|
PIStateBase * source() const { return source_state; }
|
||||||
|
PIStateBase * target() const { return target_state; }
|
||||||
|
|
||||||
|
template<typename R, typename... Args>
|
||||||
|
PITransitionBase * addGuard(std::function<R(Args...)> f) {
|
||||||
|
static_assert(std::is_same<R, bool>::value, "guard function should return bool!");
|
||||||
|
piDeleteSafety(guard);
|
||||||
|
guard = PIStateMachineHelpers::makeFunction(f);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
PITransitionBase * addGuard(L f) {
|
||||||
|
return addGuard(PIStateMachineHelpers::toStdFunction(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
bool testGuard(Args... args) {
|
||||||
|
if (!guard) return true;
|
||||||
|
if (guard->formatHash() != PIStateMachineHelpers::Function<Args...>().formatHash()) {
|
||||||
|
piCout << "invalid arguments format!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<PIStateMachineHelpers::Function<Args...> *>(guard)->func(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITransitionBase * addAction(std::function<void()> a);
|
||||||
|
void makeAction();
|
||||||
|
|
||||||
|
void trigger();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void enabled() {}
|
||||||
|
virtual void disabled() {}
|
||||||
|
|
||||||
|
int eventID = 0;
|
||||||
|
PIStateBase *source_state = nullptr, *target_state = nullptr;
|
||||||
|
PIStateMachine * root = nullptr;
|
||||||
|
PIStateMachineHelpers::FunctionBase * guard = nullptr;
|
||||||
|
std::function<void()> action;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PIP_EXPORT PITransitionTimeout: public PITransitionBase {
|
||||||
|
public:
|
||||||
|
PITransitionTimeout(PIStateBase * source, PIStateBase * target, PISystemTime timeout);
|
||||||
|
~PITransitionTimeout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void enabled() override;
|
||||||
|
void disabled() override;
|
||||||
|
|
||||||
|
PITimer timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
56
libs/main/state_machine/pistatemachinemodule.h
Normal file
56
libs/main/state_machine/pistatemachinemodule.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
Module includes
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
//! \defgroup StateMachine StateMachine
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english State machine.
|
||||||
|
//! \~russian Машина состояний.
|
||||||
|
//!
|
||||||
|
//! \~\details
|
||||||
|
//! \~english \section cmake_module_StateMachine Building with CMake
|
||||||
|
//! \~russian \section cmake_module_StateMachine Сборка с использованием CMake
|
||||||
|
//!
|
||||||
|
//! \~\code
|
||||||
|
//! find_package(PIP REQUIRED)
|
||||||
|
//! target_link_libraries([target] PIP)
|
||||||
|
//! \endcode
|
||||||
|
//!
|
||||||
|
//! \~english \par Common
|
||||||
|
//! \~russian \par Общее
|
||||||
|
//!
|
||||||
|
//! \~english
|
||||||
|
//!
|
||||||
|
//! \~russian
|
||||||
|
//!
|
||||||
|
//! \~\authors
|
||||||
|
//! \~english
|
||||||
|
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||||
|
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||||
|
//! \~russian
|
||||||
|
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||||
|
//! Андрей Бычков work.a.b@yandex.ru;
|
||||||
|
//!
|
||||||
|
|
||||||
|
#ifndef PISTATEMACHINEMODULE_H
|
||||||
|
#define PISTATEMACHINEMODULE_H
|
||||||
|
|
||||||
|
#include "pistatemachine.h"
|
||||||
|
#include "pistatemachine_state.h"
|
||||||
|
#include "pistatemachine_transition.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,11 +17,12 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
#include "pitime.h"
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
|
|
||||||
# include "piprocess.h"
|
|
||||||
|
|
||||||
# include "piincludes_p.h"
|
# include "piincludes_p.h"
|
||||||
|
# include "piprocess.h"
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
# include <csignal>
|
# include <csignal>
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
@@ -88,6 +89,7 @@ PIProcess::PIProcess(): PIThread() {
|
|||||||
|
|
||||||
|
|
||||||
PIProcess::~PIProcess() {
|
PIProcess::~PIProcess() {
|
||||||
|
PIThread::stopAndWait();
|
||||||
if (t_in) f_in.remove();
|
if (t_in) f_in.remove();
|
||||||
if (t_out) f_out.remove();
|
if (t_out) f_out.remove();
|
||||||
if (t_err) f_err.remove();
|
if (t_err) f_err.remove();
|
||||||
@@ -232,6 +234,11 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIProcess::waitForFinish() {
|
||||||
|
return PIThread::waitForFinish(1_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
|
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
|
||||||
PIProcess p;
|
PIProcess p;
|
||||||
p.args << program << args_;
|
p.args << program << args_;
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ public:
|
|||||||
exec_();
|
exec_();
|
||||||
}
|
}
|
||||||
EVENT_HANDLER(void, terminate);
|
EVENT_HANDLER(void, terminate);
|
||||||
EVENT_HANDLER(bool, waitForFinish) { return waitForFinish(60000); }
|
EVENT_HANDLER(bool, waitForFinish);
|
||||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) { return PIThread::waitForFinish(timeout_msecs); }
|
EVENT_HANDLER1(bool, waitForFinish, PISystemTime, timeout) { return PIThread::waitForFinish(timeout); }
|
||||||
|
|
||||||
EVENT1(execStarted, PIString, program);
|
EVENT1(execStarted, PIString, program);
|
||||||
EVENT2(execFinished, PIString, program, int, exit_code);
|
EVENT2(execFinished, PIString, program, int, exit_code);
|
||||||
@@ -202,9 +202,9 @@ public:
|
|||||||
//! \~english Wait for attached execution finish maximum for 60 seconds
|
//! \~english Wait for attached execution finish maximum for 60 seconds
|
||||||
//! \~russian
|
//! \~russian
|
||||||
|
|
||||||
//! \fn bool waitForFinish(int timeout_msecs)
|
//! \fn bool waitForFinish(PISystemTime timeout)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Wait for attached execution finish maximum for "timeout_msecs" milliseconds
|
//! \~english Wait for attached execution finish maximum for "timeout_"
|
||||||
//! \~russian
|
//! \~russian
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
#include "pisingleapplication.h"
|
#include "pisingleapplication.h"
|
||||||
|
|
||||||
#include "piliterals.h"
|
#include "piliterals_bytes.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pisharedmemory.h"
|
#include "pisharedmemory.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
|
|
||||||
//! \class PISingleApplication pisingleapplication.h
|
//! \class PISingleApplication pisingleapplication.h
|
||||||
@@ -70,7 +72,7 @@ PISingleApplication::PISingleApplication(const PIString & app_name): PIThread()
|
|||||||
started = false;
|
started = false;
|
||||||
sacnt = 0;
|
sacnt = 0;
|
||||||
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
|
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
|
||||||
start(100);
|
start(10_Hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ PISystemMonitor::~PISystemMonitor() {
|
|||||||
|
|
||||||
|
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
|
bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
|
||||||
stop();
|
stop();
|
||||||
pID_ = pID;
|
pID_ = pID;
|
||||||
Pool::instance()->add(this);
|
Pool::instance()->add(this);
|
||||||
@@ -118,17 +118,17 @@ bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
|
|||||||
}
|
}
|
||||||
PRIVATE->tm.reset();
|
PRIVATE->tm.reset();
|
||||||
# endif
|
# endif
|
||||||
return start(interval_ms);
|
return start(interval);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool PISystemMonitor::startOnSelf(int interval_ms) {
|
bool PISystemMonitor::startOnSelf(PISystemTime interval) {
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms);
|
bool ret = startOnProcess(PIProcess::currentPID(), interval);
|
||||||
cycle = -1;
|
cycle = -1;
|
||||||
#else
|
#else
|
||||||
bool ret = start(interval_ms);
|
bool ret = start(interval);
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,8 @@ void PISystemMonitor::run() {
|
|||||||
if (t->isPIObject()) gatherThread(t->tid());
|
if (t->isPIObject()) gatherThread(t->tid());
|
||||||
#else
|
#else
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
tbid[pID_] = "main";
|
double delay_ms = delay_.toMilliseconds();
|
||||||
|
tbid[pID_] = "main";
|
||||||
# ifdef MAC_OS
|
# ifdef MAC_OS
|
||||||
rusage_info_current ru;
|
rusage_info_current ru;
|
||||||
proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t *)&ru);
|
proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t *)&ru);
|
||||||
@@ -203,10 +204,10 @@ void PISystemMonitor::run() {
|
|||||||
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
|
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
|
||||||
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
|
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
|
||||||
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
|
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
|
||||||
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_;
|
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_ms;
|
||||||
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
|
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
|
||||||
cycle = 0;
|
cycle = 0;
|
||||||
// piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
|
// piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
|
||||||
# else
|
# else
|
||||||
PRIVATE->file.seekToBegin();
|
PRIVATE->file.seekToBegin();
|
||||||
PIString str = PIString::fromAscii(PRIVATE->file.readAll(true));
|
PIString str = PIString::fromAscii(PRIVATE->file.readAll(true));
|
||||||
@@ -236,8 +237,8 @@ void PISystemMonitor::run() {
|
|||||||
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
|
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
|
||||||
PRIVATE->cpu_u_cur = sl[12].toLLong();
|
PRIVATE->cpu_u_cur = sl[12].toLLong();
|
||||||
PRIVATE->cpu_s_cur = sl[13].toLLong();
|
PRIVATE->cpu_s_cur = sl[13].toLLong();
|
||||||
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ / 1000.);
|
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ms / 1000.);
|
||||||
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ / 1000.);
|
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ms / 1000.);
|
||||||
tstat.cpu_load_system /= cpu_count;
|
tstat.cpu_load_system /= cpu_count;
|
||||||
tstat.cpu_load_user /= cpu_count;
|
tstat.cpu_load_user /= cpu_count;
|
||||||
cycle = 0;
|
cycle = 0;
|
||||||
@@ -394,8 +395,8 @@ void PISystemMonitor::gatherThread(llong id) {
|
|||||||
|
|
||||||
|
|
||||||
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
|
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
|
||||||
if (delay_ <= 0) return -1.;
|
if (delay_.isNull()) return -1.;
|
||||||
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f);
|
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_.toMilliseconds()), 0.f, 100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -203,12 +203,12 @@ public:
|
|||||||
|
|
||||||
//! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds
|
//! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds
|
||||||
//! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд
|
//! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд
|
||||||
bool startOnProcess(int pID, int interval_ms = 1000);
|
bool startOnProcess(int pID, PISystemTime interval = PISystemTime::fromSeconds(1.));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
|
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
|
||||||
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
|
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
|
||||||
bool startOnSelf(int interval_ms = 1000);
|
bool startOnSelf(PISystemTime interval = PISystemTime::fromSeconds(1.));
|
||||||
|
|
||||||
//! \~english Stop monitoring
|
//! \~english Stop monitoring
|
||||||
//! \~russian Останавливает мониторинг
|
//! \~russian Останавливает мониторинг
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#define PIBLOCKINGQUEUE_H
|
#define PIBLOCKINGQUEUE_H
|
||||||
|
|
||||||
#include "piconditionvar.h"
|
#include "piconditionvar.h"
|
||||||
#include "pideque.h"
|
#include "piqueue.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
|
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
|
||||||
@@ -96,16 +96,16 @@ public:
|
|||||||
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
|
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
|
||||||
*
|
*
|
||||||
* @param v the element to add
|
* @param v the element to add
|
||||||
* @param timeoutMs the timeout waiting for inserting if que is full, if timeout = 0, then returns immediately
|
* @param timeout the timeout waiting for inserting if que is full, if timeout is null, then returns immediately
|
||||||
* @return true if the element was added to this queue, else false
|
* @return true if the element was added to this queue, else false
|
||||||
*/
|
*/
|
||||||
bool offer(const T & v, int timeoutMs = 0) {
|
bool offer(const T & v, PISystemTime timeout = {}) {
|
||||||
bool isOk;
|
bool isOk;
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (timeoutMs == 0)
|
if (timeout.isNull())
|
||||||
isOk = PIDeque<T>::size() < max_size;
|
isOk = PIDeque<T>::size() < max_size;
|
||||||
else
|
else
|
||||||
isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; });
|
isOk = cond_var_rem->waitFor(mutex, timeout, [&]() { return PIDeque<T>::size() < max_size; });
|
||||||
if (isOk) PIDeque<T>::push_back(v);
|
if (isOk) PIDeque<T>::push_back(v);
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if (isOk) cond_var_add->notifyOne();
|
if (isOk) cond_var_add->notifyOne();
|
||||||
@@ -133,20 +133,20 @@ public:
|
|||||||
* \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
|
* \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
|
||||||
* element to become available.
|
* element to become available.
|
||||||
*
|
*
|
||||||
* @param timeoutMs how long to wait before giving up, in milliseconds
|
* @param timeout how long to wait before giving up
|
||||||
* @param defaultVal value, which returns if the specified waiting time elapses before an element is available
|
* @param defaultVal value, which returns if the specified waiting time elapses before an element is available
|
||||||
* @param isOk flag, which indicates result of method execution. It will be set to false if timeout, or true if
|
* @param isOk flag, which indicates result of method execution. It will be set to false if timeout, or true if
|
||||||
* return value is retrieved value
|
* return value is retrieved value
|
||||||
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
|
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
|
||||||
*/
|
*/
|
||||||
T poll(int timeoutMs = 0, const T & defaultVal = T(), bool * isOk = nullptr) {
|
T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) {
|
||||||
T t = defaultVal;
|
T t = defaultVal;
|
||||||
bool isNotEmpty;
|
bool isNotEmpty;
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (timeoutMs == 0)
|
if (timeout.isNull())
|
||||||
isNotEmpty = !PIDeque<T>::isEmpty();
|
isNotEmpty = !PIDeque<T>::isEmpty();
|
||||||
else
|
else
|
||||||
isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
|
isNotEmpty = cond_var_add->waitFor(mutex, timeout, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||||
if (isNotEmpty) t = PIDeque<T>::take_front();
|
if (isNotEmpty) t = PIDeque<T>::take_front();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
|
|
||||||
#include "piconditionvar.h"
|
#include "piconditionvar.h"
|
||||||
#include "piincludes_p.h"
|
#include "piincludes_p.h"
|
||||||
#include "pithread.h"
|
|
||||||
#include "pitime.h"
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
# include <synchapi.h>
|
# include <synchapi.h>
|
||||||
# include <winbase.h>
|
# include <winbase.h>
|
||||||
@@ -105,19 +103,18 @@ void PIConditionVariable::wait(PIMutex & lk, const std::function<bool()> & condi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) {
|
bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout) {
|
||||||
bool isNotTimeout;
|
bool isNotTimeout;
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
|
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeout.toMilliseconds()) != 0;
|
||||||
#elif defined(FREERTOS)
|
#elif defined(FREERTOS)
|
||||||
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
||||||
EventBits_t uxBits;
|
EventBits_t uxBits;
|
||||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
|
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeout.toMilliseconds() / portTICK_PERIOD_MS);
|
||||||
isNotTimeout = (uxBits & 1) != 0;
|
isNotTimeout = (uxBits & 1) != 0;
|
||||||
#else
|
#else
|
||||||
|
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||||
timespec expire_ts;
|
timespec expire_ts;
|
||||||
PISystemTime st = PISystemTime::current(true);
|
|
||||||
st.addMilliseconds(timeoutMs);
|
|
||||||
st.toTimespec(&expire_ts);
|
st.toTimespec(&expire_ts);
|
||||||
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0;
|
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -125,14 +122,13 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition) {
|
bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition) {
|
||||||
bool isCondition;
|
bool isCondition;
|
||||||
#if defined(WINDOWS) || defined(FREERTOS)
|
#if defined(WINDOWS) || defined(FREERTOS)
|
||||||
PITimeMeasurer measurer;
|
PITimeMeasurer measurer;
|
||||||
#else
|
#else
|
||||||
|
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||||
timespec expire_ts;
|
timespec expire_ts;
|
||||||
PISystemTime st = PISystemTime::current(true);
|
|
||||||
st.addMilliseconds(timeoutMs);
|
|
||||||
st.toTimespec(&expire_ts);
|
st.toTimespec(&expire_ts);
|
||||||
#endif
|
#endif
|
||||||
#ifdef FREERTOS
|
#ifdef FREERTOS
|
||||||
@@ -143,12 +139,16 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::functi
|
|||||||
if (isCondition) break;
|
if (isCondition) break;
|
||||||
bool isTimeout;
|
bool isTimeout;
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
isTimeout =
|
isTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle,
|
||||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0;
|
(PCRITICAL_SECTION)lk.handle(),
|
||||||
|
timeout.toMilliseconds() - (int)measurer.elapsed_m()) == 0;
|
||||||
#elif defined(FREERTOS)
|
#elif defined(FREERTOS)
|
||||||
EventBits_t uxBits;
|
EventBits_t uxBits;
|
||||||
uxBits =
|
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle,
|
||||||
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
1,
|
||||||
|
pdTRUE,
|
||||||
|
pdTRUE,
|
||||||
|
(timeout.toMilliseconds() - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
||||||
isTimeout = (uxBits & 1) == 0;
|
isTimeout = (uxBits & 1) == 0;
|
||||||
#else
|
#else
|
||||||
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0;
|
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0;
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
#ifndef PICONDITIONVAR_H
|
#ifndef PICONDITIONVAR_H
|
||||||
#define PICONDITIONVAR_H
|
#define PICONDITIONVAR_H
|
||||||
|
|
||||||
#include "pithread.h"
|
#include "pimutex.h"
|
||||||
|
#include "pisystemtime.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,18 +88,18 @@ public:
|
|||||||
/**
|
/**
|
||||||
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
|
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
|
||||||
*/
|
*/
|
||||||
virtual bool waitFor(PIMutex & lk, int timeoutMs);
|
virtual bool waitFor(PIMutex & lk, PISystemTime timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Wait for timeout or until notified
|
* \brief Wait for timeout or until notified
|
||||||
*
|
*
|
||||||
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
|
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
|
||||||
* during timeoutMs, or until notified (if the latter happens first).
|
* during timeout, or until notified (if the latter happens first).
|
||||||
*
|
*
|
||||||
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
|
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
|
||||||
* other locked threads to continue.
|
* other locked threads to continue.
|
||||||
*
|
*
|
||||||
* Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
|
* Once notified or once timeout has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
|
||||||
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last
|
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last
|
||||||
* mutex locking may block again the thread before returning).
|
* mutex locking may block again the thread before returning).
|
||||||
*
|
*
|
||||||
@@ -114,7 +115,7 @@ public:
|
|||||||
* as a bool. This is called repeatedly until it evaluates to true.
|
* as a bool. This is called repeatedly until it evaluates to true.
|
||||||
* @return false if timeout reached or true if wakeup condition is true
|
* @return false if timeout reached or true if wakeup condition is true
|
||||||
*/
|
*/
|
||||||
virtual bool waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition);
|
virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "pidiagnostics.h"
|
#include "pidiagnostics.h"
|
||||||
#include "pithread.h"
|
#include "pithread.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
|
|
||||||
template<typename T = PIByteArray>
|
template<typename T = PIByteArray>
|
||||||
|
|||||||
@@ -535,33 +535,33 @@ PRIVATE_DEFINITION_START(PIThread)
|
|||||||
PRIVATE_DEFINITION_END(PIThread)
|
PRIVATE_DEFINITION_END(PIThread)
|
||||||
|
|
||||||
|
|
||||||
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int loop_delay): PIObject() {
|
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, PISystemTime loop_delay): PIObject() {
|
||||||
PIINTROSPECTION_THREAD_NEW(this);
|
PIINTROSPECTION_THREAD_NEW(this);
|
||||||
data_ = data;
|
data_ = data;
|
||||||
ret_func = func;
|
ret_func = func;
|
||||||
terminating = running_ = lockRun = false;
|
terminating = running_ = lockRun = false;
|
||||||
priority_ = piNormal;
|
priority_ = piNormal;
|
||||||
delay_ = loop_delay;
|
delay_ = loop_delay;
|
||||||
if (startNow) start(loop_delay);
|
if (startNow) start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIThread::PIThread(std::function<void()> func, bool startNow, int loop_delay) {
|
PIThread::PIThread(std::function<void()> func, bool startNow, PISystemTime loop_delay) {
|
||||||
PIINTROSPECTION_THREAD_NEW(this);
|
PIINTROSPECTION_THREAD_NEW(this);
|
||||||
ret_func = [func](void *) { func(); };
|
ret_func = [func](void *) { func(); };
|
||||||
terminating = running_ = lockRun = false;
|
terminating = running_ = lockRun = false;
|
||||||
priority_ = piNormal;
|
priority_ = piNormal;
|
||||||
delay_ = loop_delay;
|
delay_ = loop_delay;
|
||||||
if (startNow) start(loop_delay);
|
if (startNow) start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIThread::PIThread(bool startNow, int loop_delay): PIObject() {
|
PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
|
||||||
PIINTROSPECTION_THREAD_NEW(this);
|
PIINTROSPECTION_THREAD_NEW(this);
|
||||||
terminating = running_ = lockRun = false;
|
terminating = running_ = lockRun = false;
|
||||||
priority_ = piNormal;
|
priority_ = piNormal;
|
||||||
delay_ = loop_delay;
|
delay_ = loop_delay;
|
||||||
if (startNow) start(loop_delay);
|
if (startNow) start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -573,7 +573,7 @@ PIThread::~PIThread() {
|
|||||||
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
||||||
// PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
|
// PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
|
||||||
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
|
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
|
||||||
stop(true);
|
stopAndWait();
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
|
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
|
||||||
#else
|
#else
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
@@ -591,15 +591,47 @@ PIThread::~PIThread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::start(ThreadFunc func, int loop_delay) {
|
bool PIThread::start() {
|
||||||
ret_func = func;
|
if (running_) return false;
|
||||||
return start(loop_delay);
|
return _startThread((void *)thread_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::start(std::function<void()> func, int loop_delay) {
|
bool PIThread::start(PISystemTime loop_delay) {
|
||||||
|
delay_ = loop_delay;
|
||||||
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIThread::start(ThreadFunc func) {
|
||||||
|
ret_func = func;
|
||||||
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIThread::start(ThreadFunc func, PISystemTime loop_delay) {
|
||||||
|
ret_func = func;
|
||||||
|
delay_ = loop_delay;
|
||||||
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIThread::start(std::function<void()> func) {
|
||||||
ret_func = [func](void *) { func(); };
|
ret_func = [func](void *) { func(); };
|
||||||
return start(loop_delay);
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIThread::start(std::function<void()> func, PISystemTime loop_delay) {
|
||||||
|
ret_func = [func](void *) { func(); };
|
||||||
|
delay_ = loop_delay;
|
||||||
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIThread::startOnce() {
|
||||||
|
if (running_) return false;
|
||||||
|
return _startThread((void *)thread_function_once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -609,9 +641,15 @@ bool PIThread::startOnce(ThreadFunc func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIThread::stopAndWait(int timeout_ms) {
|
bool PIThread::startOnce(std::function<void()> func) {
|
||||||
|
ret_func = [func](void *) { func(); };
|
||||||
|
return startOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIThread::stopAndWait(PISystemTime timeout) {
|
||||||
stop();
|
stop();
|
||||||
waitForFinish(timeout_ms);
|
waitForFinish(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -621,19 +659,6 @@ void PIThread::stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::start(int loop_delay) {
|
|
||||||
if (running_) return false;
|
|
||||||
delay_ = loop_delay;
|
|
||||||
return _startThread((void *)thread_function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::startOnce() {
|
|
||||||
if (running_) return false;
|
|
||||||
return _startThread((void *)thread_function_once);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PIThread::terminate() {
|
void PIThread::terminate() {
|
||||||
piCoutObj << "Warning, terminate!";
|
piCoutObj << "Warning, terminate!";
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
|
||||||
@@ -766,7 +791,7 @@ void PIThread::setPriority(PIThread::Priority prior) {
|
|||||||
#else
|
#else
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
|
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
|
||||||
policy_ = 0;
|
int policy_ = 0;
|
||||||
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
|
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
|
||||||
pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
|
pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
|
||||||
PRIVATE->sparam.
|
PRIVATE->sparam.
|
||||||
@@ -785,16 +810,6 @@ void PIThread::setPriority(PIThread::Priority prior) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::waitForStart(PISystemTime timeout) {
|
|
||||||
return waitForStart(timeout.toMilliseconds());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::waitForFinish(PISystemTime timeout) {
|
|
||||||
return waitForFinish(timeout.toMilliseconds());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
bool isExists(HANDLE hThread) {
|
bool isExists(HANDLE hThread) {
|
||||||
// errorClear();
|
// errorClear();
|
||||||
@@ -808,11 +823,12 @@ bool isExists(HANDLE hThread) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool PIThread::waitForFinish(int timeout_msecs) {
|
|
||||||
|
bool PIThread::waitForFinish(PISystemTime timeout) {
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
|
||||||
// timeout_msecs;
|
// timeout_msecs;
|
||||||
if (!running_) return true;
|
if (!running_) return true;
|
||||||
if (timeout_msecs < 0) {
|
if (timeout.isNull()) {
|
||||||
while (running_) {
|
while (running_) {
|
||||||
piMinSleep();
|
piMinSleep();
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
@@ -825,7 +841,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tmf_.reset();
|
tmf_.reset();
|
||||||
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
|
while (running_ && tmf_.elapsed() < timeout) {
|
||||||
piMinSleep();
|
piMinSleep();
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (!isExists(PRIVATE->thread)) {
|
if (!isExists(PRIVATE->thread)) {
|
||||||
@@ -834,21 +850,21 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return tmf_.elapsed_m() < timeout_msecs;
|
return tmf_.elapsed() < timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThread::waitForStart(int timeout_msecs) {
|
bool PIThread::waitForStart(PISystemTime timeout) {
|
||||||
if (running_) return true;
|
if (running_) return true;
|
||||||
if (timeout_msecs < 0) {
|
if (timeout.isNull()) {
|
||||||
while (!running_)
|
while (!running_)
|
||||||
piMinSleep();
|
piMinSleep();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tms_.reset();
|
tms_.reset();
|
||||||
while (!running_ && tms_.elapsed_m() < timeout_msecs)
|
while (!running_ && tms_.elapsed() < timeout)
|
||||||
piMinSleep();
|
piMinSleep();
|
||||||
return tms_.elapsed_m() < timeout_msecs;
|
return tms_.elapsed() < timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -940,11 +956,11 @@ void PIThread::__thread_func__() {
|
|||||||
_runThread();
|
_runThread();
|
||||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
|
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
|
||||||
PIINTROSPECTION_THREAD_WAIT(this);
|
PIINTROSPECTION_THREAD_WAIT(this);
|
||||||
if (delay_ > 0) {
|
if (delay_.isNotNull()) {
|
||||||
tmr_.reset();
|
tmr_.reset();
|
||||||
double sl(0.);
|
double sl(0.);
|
||||||
while (1) {
|
while (1) {
|
||||||
sl = piMind(delay_ - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
|
sl = piMind(delay_.toMilliseconds() - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
|
||||||
if (terminating) break;
|
if (terminating) break;
|
||||||
if (sl <= 0.) break;
|
if (sl <= 0.) break;
|
||||||
piMSleep(sl);
|
piMSleep(sl);
|
||||||
|
|||||||
@@ -79,15 +79,15 @@ public:
|
|||||||
|
|
||||||
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay"
|
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay"
|
||||||
//! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay"
|
//! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay"
|
||||||
PIThread(void * data, ThreadFunc func, bool startNow = false, int loop_delay = -1);
|
PIThread(void * data, ThreadFunc func, bool startNow = false, PISystemTime loop_delay = {});
|
||||||
|
|
||||||
//! \~english Contructs thread with external function "func" and main loop delay "loop_delay"
|
//! \~english Contructs thread with external function "func" and main loop delay "loop_delay"
|
||||||
//! \~russian Создает поток с функцией "func" и задержкой цикла "loop_delay"
|
//! \~russian Создает поток с функцией "func" и задержкой цикла "loop_delay"
|
||||||
PIThread(std::function<void()> func, bool startNow = false, int loop_delay = -1);
|
PIThread(std::function<void()> func, bool startNow = false, PISystemTime loop_delay = {});
|
||||||
|
|
||||||
//! \~english Contructs thread with main loop delay "loop_delay"
|
//! \~english Contructs thread with main loop delay "loop_delay"
|
||||||
//! \~russian Создает поток с задержкой цикла "loop_delay"
|
//! \~russian Создает поток с задержкой цикла "loop_delay"
|
||||||
PIThread(bool startNow = false, int loop_delay = -1);
|
PIThread(bool startNow = false, PISystemTime loop_delay = {});
|
||||||
|
|
||||||
virtual ~PIThread();
|
virtual ~PIThread();
|
||||||
|
|
||||||
@@ -103,27 +103,55 @@ public:
|
|||||||
piHighest /** \~english Highest \~russian Высший */
|
piHighest /** \~english Highest \~russian Высший */
|
||||||
};
|
};
|
||||||
|
|
||||||
EVENT_HANDLER0(bool, start) { return start(-1); }
|
|
||||||
EVENT_HANDLER1(bool, start, int, loop_delay);
|
//! \~english Start thread
|
||||||
bool start(PISystemTime loop_delay) { return start(loop_delay.toMilliseconds()); }
|
//! \~russian Запускает поток
|
||||||
bool start(ThreadFunc func) { return start(func, -1); }
|
bool start();
|
||||||
bool start(ThreadFunc func, int loop_delay);
|
|
||||||
bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
//! \~english Start thread
|
||||||
bool start(std::function<void()> func) { return start(func, -1); }
|
//! \~russian Запускает поток
|
||||||
bool start(std::function<void()> func, int loop_delay);
|
bool start(PISystemTime loop_delay);
|
||||||
bool start(std::function<void()> func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
|
||||||
EVENT_HANDLER0(bool, startOnce);
|
//! \~english Start thread
|
||||||
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func);
|
//! \~russian Запускает поток
|
||||||
|
bool start(ThreadFunc func);
|
||||||
|
|
||||||
|
//! \~english Start thread
|
||||||
|
//! \~russian Запускает поток
|
||||||
|
bool start(ThreadFunc func, PISystemTime loop_delay);
|
||||||
|
|
||||||
|
//! \~english Start thread
|
||||||
|
//! \~russian Запускает поток
|
||||||
|
bool start(std::function<void()> func);
|
||||||
|
|
||||||
|
//! \~english Start thread
|
||||||
|
//! \~russian Запускает поток
|
||||||
|
bool start(std::function<void()> func, PISystemTime loop_delay);
|
||||||
|
|
||||||
|
//! \~english Start thread without internal loop
|
||||||
|
//! \~russian Запускает поток без внутреннего цикла
|
||||||
|
bool startOnce();
|
||||||
|
|
||||||
|
//! \~english Start thread without internal loop
|
||||||
|
//! \~russian Запускает поток без внутреннего цикла
|
||||||
|
bool startOnce(ThreadFunc func);
|
||||||
|
|
||||||
|
//! \~english Start thread without internal loop
|
||||||
|
//! \~russian Запускает поток без внутреннего цикла
|
||||||
|
bool startOnce(std::function<void()> func);
|
||||||
|
|
||||||
EVENT_HANDLER0(void, stop);
|
EVENT_HANDLER0(void, stop);
|
||||||
EVENT_HANDLER0(void, terminate);
|
EVENT_HANDLER0(void, terminate);
|
||||||
|
|
||||||
//! \~english Stop thread and wait for finish.
|
//! \~english Stop thread and wait for finish.
|
||||||
//! \~russian Останавливает поток и ожидает завершения.
|
//! \~russian Останавливает поток и ожидает завершения.
|
||||||
void stopAndWait(int timeout_ms = -1);
|
void stopAndWait(int timeout_ms) DEPRECATEDM("use waitForStart(PISystemTime)") {
|
||||||
|
stopAndWait(PISystemTime::fromMilliseconds(timeout_ms));
|
||||||
|
}
|
||||||
|
|
||||||
//! \~english Stop thread and wait for finish.
|
//! \~english Stop thread and wait for finish.
|
||||||
//! \~russian Останавливает поток и ожидает завершения.
|
//! \~russian Останавливает поток и ожидает завершения.
|
||||||
void stopAndWait(PISystemTime timeout) { stopAndWait(timeout.toMilliseconds()); }
|
void stopAndWait(PISystemTime timeout = {});
|
||||||
|
|
||||||
//! \~english Set common data passed to external function
|
//! \~english Set common data passed to external function
|
||||||
//! \~russian Устанавливает данные, передаваемые в функцию потока
|
//! \~russian Устанавливает данные, передаваемые в функцию потока
|
||||||
@@ -159,12 +187,19 @@ public:
|
|||||||
//! \~russian Возвращает останавливается ли поток
|
//! \~russian Возвращает останавливается ли поток
|
||||||
bool isStopping() const { return running_ && terminating; }
|
bool isStopping() const { return running_ && terminating; }
|
||||||
|
|
||||||
EVENT_HANDLER0(bool, waitForStart) { return waitForStart(-1); }
|
//! \~english Wait for thread start
|
||||||
EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs);
|
//! \~russian Ожидает старта потока
|
||||||
bool waitForStart(PISystemTime timeout);
|
bool waitForStart(PISystemTime timeout = {});
|
||||||
EVENT_HANDLER0(bool, waitForFinish) { return waitForFinish(-1); }
|
bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") {
|
||||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
|
return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs));
|
||||||
bool waitForFinish(PISystemTime timeout);
|
}
|
||||||
|
|
||||||
|
//! \~english Wait for thread finish
|
||||||
|
//! \~russian Ожидает завершения потока
|
||||||
|
bool waitForFinish(PISystemTime timeout = {});
|
||||||
|
bool waitForFinish(int timeout_msecs) DEPRECATEDM("use waitForFinish(PISystemTime)") {
|
||||||
|
return waitForFinish(PISystemTime::fromMilliseconds(timeout_msecs));
|
||||||
|
}
|
||||||
|
|
||||||
//! \~english Set necessity of lock every \a run() with internal mutex
|
//! \~english Set necessity of lock every \a run() with internal mutex
|
||||||
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
|
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
|
||||||
@@ -198,21 +233,6 @@ public:
|
|||||||
//! \handlers
|
//! \handlers
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \fn bool start(int loop_delay = -1)
|
|
||||||
//! \brief
|
|
||||||
//! \~english Start thread
|
|
||||||
//! \~russian Запускает поток
|
|
||||||
|
|
||||||
//! \fn bool startOnce()
|
|
||||||
//! \brief
|
|
||||||
//! \~english Start thread without internal loop
|
|
||||||
//! \~russian Запускает поток без внутреннего цикла
|
|
||||||
|
|
||||||
//! \fn bool startOnce(ThreadFunc func)
|
|
||||||
//! \brief
|
|
||||||
//! \~english Start thread without internal loop
|
|
||||||
//! \~russian Запускает поток без внутреннего цикла
|
|
||||||
|
|
||||||
//! \fn void stop()
|
//! \fn void stop()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Stop thread
|
//! \~english Stop thread
|
||||||
@@ -223,16 +243,6 @@ public:
|
|||||||
//! \~english Strongly stop thread
|
//! \~english Strongly stop thread
|
||||||
//! \~russian Жёстко прерывает поток
|
//! \~russian Жёстко прерывает поток
|
||||||
|
|
||||||
//! \fn bool waitForStart(int timeout_msecs = -1)
|
|
||||||
//! \brief
|
|
||||||
//! \~english Wait for thread start
|
|
||||||
//! \~russian Ожидает старта потока
|
|
||||||
|
|
||||||
//! \fn bool waitForFinish(int timeout_msecs = -1)
|
|
||||||
//! \brief
|
|
||||||
//! \~english Wait for thread finish
|
|
||||||
//! \~russian Ожидает завершения потока
|
|
||||||
|
|
||||||
//! \fn void lock()
|
//! \fn void lock()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Lock internal mutex
|
//! \~english Lock internal mutex
|
||||||
@@ -275,7 +285,7 @@ protected:
|
|||||||
virtual void end() { ; }
|
virtual void end() { ; }
|
||||||
|
|
||||||
std::atomic_bool terminating, running_, lockRun;
|
std::atomic_bool terminating, running_, lockRun;
|
||||||
int delay_, policy_;
|
PISystemTime delay_;
|
||||||
llong tid_ = -1;
|
llong tid_ = -1;
|
||||||
void * data_ = nullptr;
|
void * data_ = nullptr;
|
||||||
mutable PIMutex thread_mutex;
|
mutable PIMutex thread_mutex;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "pithreadpoolexecutor.h"
|
#include "pithreadpoolexecutor.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
/*! \class PIThreadPoolExecutor
|
/*! \class PIThreadPoolExecutor
|
||||||
* \brief Thread pools address two different problems: they usually provide improved performance when executing large
|
* \brief Thread pools address two different problems: they usually provide improved performance when executing large
|
||||||
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
|
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
|
||||||
@@ -29,7 +31,7 @@
|
|||||||
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) {
|
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) {
|
||||||
for (int i = 0; i < corePoolSize; ++i) {
|
for (int i = 0; i < corePoolSize; ++i) {
|
||||||
PIThread * thread = new PIThread([&, i]() {
|
PIThread * thread = new PIThread([&, i]() {
|
||||||
auto runnable = taskQueue.poll(100, std::function<void()>());
|
auto runnable = taskQueue.poll(100_ms, std::function<void()>());
|
||||||
if (runnable) {
|
if (runnable) {
|
||||||
runnable();
|
runnable();
|
||||||
}
|
}
|
||||||
@@ -41,11 +43,11 @@ PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
|
bool PIThreadPoolExecutor::awaitTermination(PISystemTime timeout) {
|
||||||
PITimeMeasurer measurer;
|
PITimeMeasurer measurer;
|
||||||
for (size_t i = 0; i < threadPool.size(); ++i) {
|
for (size_t i = 0; i < threadPool.size(); ++i) {
|
||||||
int dif = timeoutMs - (int)measurer.elapsed_m();
|
auto dif = timeout - measurer.elapsed();
|
||||||
if (dif < 0) return false;
|
if (dif.isNegative()) return false;
|
||||||
if (!threadPool[i]->waitForFinish(dif)) return false;
|
if (!threadPool[i]->waitForFinish(dif)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define PITHREADPOOLEXECUTOR_H
|
#define PITHREADPOOLEXECUTOR_H
|
||||||
|
|
||||||
#include "piblockingqueue.h"
|
#include "piblockingqueue.h"
|
||||||
|
#include "pithread.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ public:
|
|||||||
|
|
||||||
bool isShutdown() const;
|
bool isShutdown() const;
|
||||||
|
|
||||||
bool awaitTermination(int timeoutMs);
|
bool awaitTermination(PISystemTime timeout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic_bool isShutdown_;
|
std::atomic_bool isShutdown_;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "pithreadpoolloop.h"
|
#include "pithreadpoolloop.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pisysteminfo.h"
|
#include "pisysteminfo.h"
|
||||||
#include "pithread.h"
|
#include "pithread.h"
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
|
|||||||
PIThreadPoolLoop::~PIThreadPoolLoop() {
|
PIThreadPoolLoop::~PIThreadPoolLoop() {
|
||||||
for (auto * t: threads) {
|
for (auto * t: threads) {
|
||||||
t->stop();
|
t->stop();
|
||||||
if (!t->waitForFinish(100)) t->terminate();
|
if (!t->waitForFinish(100_ms)) t->terminate();
|
||||||
delete t;
|
delete t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,8 @@
|
|||||||
#include "pitimer.h"
|
#include "pitimer.h"
|
||||||
|
|
||||||
#include "piconditionvar.h"
|
#include "piconditionvar.h"
|
||||||
#include "piincludes_p.h"
|
#include "piliterals_time.h"
|
||||||
#include "piliterals.h"
|
#include "pithread.h"
|
||||||
#ifdef PIP_TIMER_RT
|
|
||||||
# include <csignal>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//! \addtogroup Thread
|
//! \addtogroup Thread
|
||||||
@@ -52,22 +49,22 @@
|
|||||||
//! \~russian \section PITimer_sec1 Варианты уведомления
|
//! \~russian \section PITimer_sec1 Варианты уведомления
|
||||||
//! \~english
|
//! \~english
|
||||||
//! Notify variants:
|
//! Notify variants:
|
||||||
//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda
|
//! * "slot" - static function with format void func(int delimiter) or [lambda
|
||||||
//! expression](https://en.cppreference.com/w/cpp/language/lambda);
|
//! expression](https://en.cppreference.com/w/cpp/language/lambda);
|
||||||
//! * event - \a tickEvent();
|
//! * event - \a tickEvent();
|
||||||
//! * virtual function - \a tick().
|
//! * virtual function - \a tick().
|
||||||
//!
|
//!
|
||||||
//! Lambda should be [ ]( ){ } or [ ](void*){ } format.
|
//! Lambda should be [ ]( ){ } or [ ](int){ } format.
|
||||||
//!
|
//!
|
||||||
//! All these variants are equivalent, use most applicable.
|
//! All these variants are equivalent, use most applicable.
|
||||||
//! \~russian
|
//! \~russian
|
||||||
//! Варианты уведомления:
|
//! Варианты уведомления:
|
||||||
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или
|
//! * "slot" - статический метод в формате void func(int delimiter) или
|
||||||
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
|
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
|
||||||
//! * event - \a tickEvent();
|
//! * event - \a tickEvent();
|
||||||
//! * виртуальный метод - \a tick().
|
//! * виртуальный метод - \a tick().
|
||||||
//!
|
//!
|
||||||
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](void*){ }.
|
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](int){ }.
|
||||||
//!
|
//!
|
||||||
//! Все варианты аналогичны друг другу, используйте самый удобный.
|
//! Все варианты аналогичны друг другу, используйте самый удобный.
|
||||||
//!
|
//!
|
||||||
@@ -89,10 +86,10 @@
|
|||||||
//! Пример:
|
//! Пример:
|
||||||
//!
|
//!
|
||||||
//! \~\code
|
//! \~\code
|
||||||
//! void tfunc(void * , int delim) {
|
//! void tfunc(int delim) {
|
||||||
//! piCout << "tick with delimiter" << delim;
|
//! piCout << "tick with delimiter" << delim;
|
||||||
//! };
|
//! };
|
||||||
//! void tfunc4(void * , int delim) {
|
//! void tfunc4(int delim) {
|
||||||
//! piCout << "tick4 with delimiter" << delim;
|
//! piCout << "tick4 with delimiter" << delim;
|
||||||
//! };
|
//! };
|
||||||
//! int main() {
|
//! int main() {
|
||||||
@@ -101,8 +98,7 @@
|
|||||||
//! timer.addDelimiter(4, tfunc4);
|
//! timer.addDelimiter(4, tfunc4);
|
||||||
//! timer.start(50);
|
//! timer.start(50);
|
||||||
//! piMSleep(200);
|
//! piMSleep(200);
|
||||||
//! timer.stop();
|
//! timer.stopAndWait();
|
||||||
//! timer.waitForFinish();
|
|
||||||
//! return 0;
|
//! return 0;
|
||||||
//! };
|
//! };
|
||||||
//! /* Result:
|
//! /* Result:
|
||||||
@@ -119,596 +115,163 @@
|
|||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
|
||||||
_PITimerBase::_PITimerBase() {
|
PITimer::PITimer(): PIObject() {
|
||||||
running_ = false;
|
initFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _PITimerBase::setInterval(double i) {
|
PITimer::PITimer(std::function<void(int)> func) {
|
||||||
interval_ = i;
|
initFirst();
|
||||||
|
ret_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITimer::PITimer(std::function<void()> func) {
|
||||||
|
initFirst();
|
||||||
|
ret_func = [func](int) { func(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITimer::~PITimer() {
|
||||||
|
stopAndWait();
|
||||||
|
piDeleteSafety(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PISystemTime PITimer::interval() const {
|
||||||
|
return m_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PITimer::setInterval(PISystemTime interval) {
|
||||||
|
if (m_interval == interval) return;
|
||||||
|
m_interval = interval;
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
// piCout << "change interval runtime";
|
// piCout << "change interval runtime";
|
||||||
stop();
|
stopAndWait();
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerBase::start(double interval_ms) {
|
|
||||||
if (isRunning()) stop();
|
|
||||||
deferred_ = false;
|
|
||||||
setInterval(interval_ms);
|
|
||||||
// piCout << "_PITimerBase::startTimer"<<interval_ms<<"...";
|
|
||||||
running_ = startTimer(interval_ms);
|
|
||||||
return running_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerBase::startDeferred(double interval_ms, PIDateTime start_datetime) {
|
|
||||||
if (isRunning()) stop();
|
|
||||||
deferred_ = true;
|
|
||||||
deferred_mode = true;
|
|
||||||
deferred_datetime = start_datetime;
|
|
||||||
setInterval(interval_ms);
|
|
||||||
running_ = startTimer(interval_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerBase::startDeferred(double interval_ms, double delay_ms) {
|
|
||||||
if (isRunning()) stop();
|
|
||||||
deferred_ = true;
|
|
||||||
deferred_mode = false;
|
|
||||||
deferred_delay = delay_ms;
|
|
||||||
setInterval(interval_ms);
|
|
||||||
running_ = startTimer(interval_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerBase::stop() {
|
|
||||||
// piCout << GetCurrentThreadId() << "_PITimerBase::stop" << wait << isRunning();
|
|
||||||
if (!isRunning()) return true;
|
|
||||||
// piCout << "_PITimerBase::stopTimer ...";
|
|
||||||
running_ = !stopTimer();
|
|
||||||
return !running_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class _PITimerImp_Thread: public _PITimerBase {
|
|
||||||
public:
|
|
||||||
_PITimerImp_Thread();
|
|
||||||
virtual ~_PITimerImp_Thread() { stop(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void prepareStart(double interval_ms);
|
|
||||||
bool threadFunc(); // returns true if repeat is needed
|
|
||||||
int wait_dt, wait_dd, wait_tick;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool startTimer(double interval_ms) override;
|
|
||||||
bool stopTimer() override;
|
|
||||||
static void threadFuncS(void * d) { ((_PITimerImp_Thread *)d)->threadFunc(); }
|
|
||||||
void adjustTimes();
|
|
||||||
bool smallWait(int ms);
|
|
||||||
|
|
||||||
PIThread thread_;
|
|
||||||
PISystemTime st_time, st_inc, st_wait, st_odt;
|
|
||||||
PIConditionVariable event;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef PIP_TIMER_RT
|
|
||||||
struct _PITimerImp_RT_Private_;
|
|
||||||
class _PITimerImp_RT: public _PITimerBase {
|
|
||||||
public:
|
|
||||||
_PITimerImp_RT();
|
|
||||||
virtual ~_PITimerImp_RT();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool startTimer(double interval_ms) override;
|
|
||||||
bool stopTimer() override;
|
|
||||||
|
|
||||||
int ti;
|
|
||||||
_PITimerImp_RT_Private_ * priv;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class _PITimerImp_Pool: public _PITimerImp_Thread {
|
|
||||||
public:
|
|
||||||
_PITimerImp_Pool();
|
|
||||||
virtual ~_PITimerImp_Pool() { stop(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Pool: public PIThread {
|
|
||||||
public:
|
|
||||||
static Pool * instance();
|
|
||||||
void add(_PITimerImp_Pool * t);
|
|
||||||
void remove(_PITimerImp_Pool * t);
|
|
||||||
void run() override;
|
|
||||||
PIVector<_PITimerImp_Pool *> timers, to_remove;
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit Pool();
|
|
||||||
virtual ~Pool();
|
|
||||||
};
|
|
||||||
bool startTimer(double interval_ms) override;
|
|
||||||
bool stopTimer() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_Thread::_PITimerImp_Thread() {
|
|
||||||
thread_.setName("__S__PITimerImp_Thread::thread"_a);
|
|
||||||
wait_dt = 1000;
|
|
||||||
wait_dd = 2000;
|
|
||||||
wait_tick = 1000;
|
|
||||||
// piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_;
|
|
||||||
// piCout << "new _PITimerImp_Thread";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerImp_Thread::prepareStart(double interval_ms) {
|
|
||||||
if (interval_ms <= 0.) {
|
|
||||||
piCout << "Achtung! Start PITimer with interval <= 0!";
|
|
||||||
piCout << "Achtung! Parent" << parent;
|
|
||||||
assert(interval_ms > 0.);
|
|
||||||
}
|
|
||||||
st_inc = PISystemTime::fromMilliseconds(interval_ms);
|
|
||||||
st_odt = st_inc * 5;
|
|
||||||
if (st_odt.toSeconds() < 1.) st_odt = 1_s;
|
|
||||||
if (deferred_) {
|
|
||||||
if (!deferred_mode) st_time = PISystemTime::current(true) + PISystemTime::fromMilliseconds(deferred_delay);
|
|
||||||
st_time -= st_inc;
|
|
||||||
} else
|
|
||||||
st_time = PISystemTime::current(true) + st_inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Thread::startTimer(double interval_ms) {
|
|
||||||
prepareStart(interval_ms);
|
|
||||||
thread_.setData(this);
|
|
||||||
return thread_.start(threadFuncS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Thread::stopTimer() {
|
|
||||||
thread_.stop();
|
|
||||||
event.notifyAll();
|
|
||||||
thread_.waitForFinish();
|
|
||||||
// if (wait)
|
|
||||||
// if (!thread_.waitForFinish(10))
|
|
||||||
// if (thread_.isRunning())
|
|
||||||
// thread_.terminate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Thread::threadFunc() {
|
|
||||||
if (!running_) return false;
|
|
||||||
if (deferred_) {
|
|
||||||
PISystemTime dwt;
|
|
||||||
int wth(wait_dt);
|
|
||||||
if (deferred_mode) {
|
|
||||||
dwt = deferred_datetime.toSystemTime() - PISystemTime::current();
|
|
||||||
wth = wait_dd;
|
|
||||||
} else
|
|
||||||
dwt = st_time - PISystemTime::current(true);
|
|
||||||
if (wth > 0) {
|
|
||||||
if (dwt.toMilliseconds() > wth + 1.) {
|
|
||||||
smallWait(wth);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!smallWait(dwt.toMilliseconds())) return false;
|
|
||||||
deferred_ = false;
|
|
||||||
st_time = PISystemTime::current(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dwt.toMilliseconds() > 0.1) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
st_wait = st_time - PISystemTime::current(true);
|
|
||||||
// piCout << "wait" << this << st_wait;
|
|
||||||
if (st_wait.abs() > st_odt || st_wait.seconds <= -5) {
|
|
||||||
// piCout << &thread_ << "adjust" << "...";
|
|
||||||
adjustTimes();
|
|
||||||
// piCout << &thread_ << "adjust" << "ok";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (wait_tick > 0) {
|
|
||||||
if (st_wait.toMilliseconds() > wait_tick + 1.) {
|
|
||||||
smallWait(wait_tick);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// piCout << &thread_ << "sleep for" << st_wait;
|
|
||||||
if (!smallWait(st_wait.toMilliseconds())) return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (st_wait.toMilliseconds() > 0.1) return false;
|
|
||||||
}
|
|
||||||
st_time += st_inc;
|
|
||||||
if (!parent->isPIObject()) {
|
|
||||||
piCout << "Achtung! PITimer \"parent\" is not PIObject!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// piCout << &thread_ << "tfunc" << "...";
|
|
||||||
tfunc(parent);
|
|
||||||
// piCout << &thread_ << "tfunc" << "ok";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerImp_Thread::adjustTimes() {
|
|
||||||
PISystemTime cst = PISystemTime::current(true);
|
|
||||||
if (st_time < cst) {
|
|
||||||
int rs = (cst - st_time).toSeconds() / st_inc.toSeconds();
|
|
||||||
if (rs >= 100)
|
|
||||||
st_time = cst + st_inc;
|
|
||||||
else {
|
|
||||||
while (st_time < cst)
|
|
||||||
st_time += st_inc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int rs = (st_time - cst).toSeconds() / st_inc.toSeconds();
|
|
||||||
if (rs >= 100)
|
|
||||||
st_time = cst - st_inc;
|
|
||||||
else {
|
|
||||||
cst += st_inc;
|
|
||||||
while (st_time > cst)
|
|
||||||
st_time -= st_inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Thread::smallWait(int ms) {
|
|
||||||
if (thread_.isStopping()) return false;
|
|
||||||
if (ms > 0) {
|
|
||||||
thread_.mutex().lock();
|
|
||||||
event.waitFor(thread_.mutex(), ms);
|
|
||||||
thread_.mutex().unlock();
|
|
||||||
}
|
|
||||||
return !thread_.isStopping();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef PIP_TIMER_RT
|
|
||||||
|
|
||||||
void threadFuncS(sigval sv) {
|
|
||||||
((_PITimerImp_RT *)sv.sival_ptr)->tfunc(((_PITimerImp_RT *)sv.sival_ptr)->parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct _PITimerImp_RT_Private_ {
|
|
||||||
itimerspec spec;
|
|
||||||
timer_t tt;
|
|
||||||
sigevent se;
|
|
||||||
};
|
|
||||||
|
|
||||||
_PITimerImp_RT::_PITimerImp_RT() {
|
|
||||||
// piCout << "new _PITimerImp_RT";
|
|
||||||
priv = new _PITimerImp_RT_Private_();
|
|
||||||
priv->tt = 0;
|
|
||||||
ti = -1;
|
|
||||||
memset(&(priv->se), 0, sizeof(priv->se));
|
|
||||||
priv->se.sigev_notify = SIGEV_THREAD;
|
|
||||||
priv->se.sigev_value.sival_ptr = this;
|
|
||||||
priv->se.sigev_notify_function = threadFuncS;
|
|
||||||
priv->se.sigev_notify_attributes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_RT::~_PITimerImp_RT() {
|
|
||||||
stop();
|
|
||||||
delete priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_RT::startTimer(double interval_ms) {
|
|
||||||
int flags(0);
|
|
||||||
priv->spec.it_interval.tv_nsec = ((int)(interval_ms * 1000) % 1000000) * 1000;
|
|
||||||
priv->spec.it_interval.tv_sec = (time_t)(interval_ms / 1000);
|
|
||||||
if (deferred_) {
|
|
||||||
if (deferred_mode) {
|
|
||||||
PISystemTime dtm = deferred_datetime.toSystemTime();
|
|
||||||
priv->spec.it_value.tv_nsec = dtm.nanoseconds;
|
|
||||||
priv->spec.it_value.tv_sec = dtm.seconds;
|
|
||||||
flags = TIMER_ABSTIME;
|
|
||||||
} else {
|
|
||||||
priv->spec.it_value.tv_nsec = ((int)(deferred_delay * 1000) % 1000000) * 1000;
|
|
||||||
priv->spec.it_value.tv_sec = (time_t)(deferred_delay / 1000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
priv->spec.it_value = priv->spec.it_interval;
|
|
||||||
}
|
|
||||||
ti = timer_create(CLOCK_REALTIME, &(priv->se), &(priv->tt));
|
|
||||||
// cout << "***create timer " << msecs << " msecs\n";
|
|
||||||
if (ti == -1) {
|
|
||||||
piCout << "Can`t create RT timer for " << interval_ms << " msecs: " << errorString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
timer_settime(priv->tt, flags, &(priv->spec), 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_RT::stopTimer() {
|
|
||||||
if (ti < 0) return true;
|
|
||||||
timer_delete(priv->tt);
|
|
||||||
ti = -1;
|
|
||||||
priv->tt = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_Pool::_PITimerImp_Pool(): _PITimerImp_Thread() {
|
|
||||||
wait_dt = wait_dd = wait_tick = 0;
|
|
||||||
// piCout << "new _PITimerImp_Pool";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_Pool::Pool::Pool(): PIThread() {
|
|
||||||
setName("__S__PITimerImp_Pool::Pool"_a);
|
|
||||||
needLockRun(true);
|
|
||||||
#ifndef FREERTOS
|
|
||||||
timers.reserve(64);
|
|
||||||
start(PIP_MIN_MSLEEP * 5);
|
|
||||||
#else
|
|
||||||
start(PIP_MIN_MSLEEP);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_Pool::Pool::~Pool() {
|
|
||||||
stop();
|
|
||||||
if (!waitForFinish(500)) terminate();
|
|
||||||
unlock();
|
|
||||||
timers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_PITimerImp_Pool::Pool * _PITimerImp_Pool::Pool::instance() {
|
|
||||||
static Pool pool;
|
|
||||||
return &pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerImp_Pool::Pool::add(_PITimerImp_Pool * t) {
|
|
||||||
// piCout << "add ...";
|
|
||||||
lock();
|
|
||||||
to_remove.removeAll(t);
|
|
||||||
if (!timers.contains(t)) timers << t;
|
|
||||||
unlock();
|
|
||||||
// piCout << "add done";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerImp_Pool::Pool::remove(_PITimerImp_Pool * t) {
|
|
||||||
// piCout << "remove ...";
|
|
||||||
lock();
|
|
||||||
to_remove << t;
|
|
||||||
unlock();
|
|
||||||
// piCout << "remove done";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _PITimerImp_Pool::Pool::run() {
|
|
||||||
if (!to_remove.isEmpty()) {
|
|
||||||
piForeach(_PITimerImp_Pool * t, to_remove)
|
|
||||||
timers.removeAll(t);
|
|
||||||
to_remove.clear();
|
|
||||||
}
|
|
||||||
piForeach(_PITimerImp_Pool * t, timers)
|
|
||||||
t->threadFunc();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Pool::startTimer(double interval_ms) {
|
|
||||||
prepareStart(interval_ms);
|
|
||||||
Pool::instance()->add(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool _PITimerImp_Pool::stopTimer() {
|
|
||||||
Pool::instance()->remove(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::PITimer(): PIObject() {
|
|
||||||
#ifdef FREERTOS
|
|
||||||
imp_mode = PITimer::Thread;
|
|
||||||
#else
|
|
||||||
imp_mode = PITimer::Thread;
|
|
||||||
#endif
|
|
||||||
initFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::PITimer(PITimer::TimerImplementation ti): PIObject() {
|
|
||||||
imp_mode = ti;
|
|
||||||
initFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::PITimer(TimerEvent slot, void * data, PITimer::TimerImplementation ti): PIObject() {
|
|
||||||
imp_mode = ti;
|
|
||||||
initFirst();
|
|
||||||
data_t = data;
|
|
||||||
ret_func = slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::PITimer(std::function<void()> slot, PITimer::TimerImplementation ti) {
|
|
||||||
imp_mode = ti;
|
|
||||||
initFirst();
|
|
||||||
ret_func = [slot](void *, int) { slot(); };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::PITimer(std::function<void(void *)> slot, void * data, PITimer::TimerImplementation ti) {
|
|
||||||
imp_mode = ti;
|
|
||||||
initFirst();
|
|
||||||
data_t = data;
|
|
||||||
ret_func = [slot](void * d, int) { slot(d); };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PITimer::~PITimer() {
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double PITimer::interval() const {
|
|
||||||
init();
|
|
||||||
return imp->interval_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PITimer::setInterval(double ms) {
|
|
||||||
init();
|
|
||||||
setProperty("interval", ms);
|
|
||||||
imp->setInterval(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::isRunning() const {
|
bool PITimer::isRunning() const {
|
||||||
init();
|
return thread->isRunning();
|
||||||
return imp->running_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::isStopped() const {
|
bool PITimer::isStopping() const {
|
||||||
init();
|
return thread->isStopping();
|
||||||
return !imp->running_;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PITimer::waitForFinish(PISystemTime timeout) {
|
||||||
|
return thread->waitForFinish(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PITimer::initFirst() {
|
void PITimer::initFirst() {
|
||||||
lockRun = false;
|
thread = new PIThread([this] { threadFunc(); });
|
||||||
callEvents = true;
|
thread->setName("__S__.PITimer.thread");
|
||||||
setProperty("interval", 0.);
|
setProperty("interval", PISystemTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PITimer::init() const {
|
void PITimer::threadFunc() {
|
||||||
if (imp) return;
|
PISystemTime st_wait = m_time_next - PISystemTime::current(true);
|
||||||
switch (imp_mode) {
|
// piCout << "wait" << this << st_wait;
|
||||||
case PITimer::Pool: imp = new _PITimerImp_Pool(); break;
|
if (st_wait.abs() > m_interval_x5 || st_wait.seconds <= -5) {
|
||||||
case PITimer::ThreadRT:
|
// piCout << &thread_ << "adjust" << "...";
|
||||||
#ifdef PIP_TIMER_RT
|
adjustTimes();
|
||||||
imp = new _PITimerImp_RT();
|
// piCout << &thread_ << "adjust" << "ok";
|
||||||
break;
|
return;
|
||||||
#else
|
|
||||||
piCoutObj << "Warning: \"ThreadRT\" is not available at this system! Using \"Thread\".";
|
|
||||||
#endif
|
|
||||||
case PITimer::Thread: imp = new _PITimerImp_Thread(); break;
|
|
||||||
default: piCout << "Fatal: invalid implementation() of" << this << "!"; assert(0);
|
|
||||||
}
|
}
|
||||||
if (!imp) return;
|
if (thread->isStopping()) return;
|
||||||
// piCout << this << "init" << imp;
|
if (st_wait.isPositive()) {
|
||||||
imp->tfunc = tickImpS;
|
thread->mutex().lock();
|
||||||
imp->parent = const_cast<PITimer *>(this);
|
event.waitFor(thread->mutex(), st_wait);
|
||||||
|
thread->mutex().unlock();
|
||||||
|
}
|
||||||
|
if (thread->isStopping()) return;
|
||||||
|
m_time_next += m_interval;
|
||||||
|
// piCout << &thread_ << "tfunc" << "...";
|
||||||
|
execTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PITimer::destroy() {
|
void PITimer::adjustTimes() {
|
||||||
if (!imp) return;
|
PISystemTime cst = PISystemTime::current(true);
|
||||||
// piCout << this << "destroy" << imp;
|
if (m_time_next < cst) {
|
||||||
imp->stop();
|
int rs = (cst - m_time_next).toSeconds() / m_interval.toSeconds();
|
||||||
delete imp;
|
if (rs >= 100)
|
||||||
imp = 0;
|
m_time_next = cst + m_interval;
|
||||||
|
else {
|
||||||
|
while (m_time_next < cst)
|
||||||
|
m_time_next += m_interval;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int rs = (m_time_next - cst).toSeconds() / m_interval.toSeconds();
|
||||||
|
if (rs >= 100)
|
||||||
|
m_time_next = cst - m_interval;
|
||||||
|
else {
|
||||||
|
cst += m_interval;
|
||||||
|
while (m_time_next > cst)
|
||||||
|
m_time_next -= m_interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PITimer::tickImp() {
|
void PITimer::execTick() {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
if (lockRun) lock();
|
if (lockRun) lock();
|
||||||
if (ret_func) ret_func(data_t, 1);
|
if (ret_func) ret_func(1);
|
||||||
tick(data_t, 1);
|
tick(1);
|
||||||
tickEvent(data_t, 1);
|
tickEvent(1);
|
||||||
if (callEvents) maybeCallQueuedEvents();
|
if (callEvents) maybeCallQueuedEvents();
|
||||||
piForeach(Delimiter & i, delims) {
|
for (Delimiter & i: delims) {
|
||||||
if (i.delim > ++(i.tick)) continue;
|
if (i.delim > ++(i.tick)) continue;
|
||||||
i.tick = 0;
|
i.tick = 0;
|
||||||
if (i.slot)
|
if (i.func)
|
||||||
i.slot(data_t, i.delim);
|
i.func(i.delim);
|
||||||
else if (ret_func)
|
else if (ret_func)
|
||||||
ret_func(data_t, i.delim);
|
ret_func(i.delim);
|
||||||
tick(data_t, i.delim);
|
tick(i.delim);
|
||||||
tickEvent(data_t, i.delim);
|
tickEvent(i.delim);
|
||||||
}
|
}
|
||||||
if (lockRun) unlock();
|
if (lockRun) unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::start() {
|
bool PITimer::start() {
|
||||||
init();
|
if (isRunning()) return true;
|
||||||
// piCout << this << "start" << imp;
|
m_interval_x5 = m_interval * 5;
|
||||||
return imp->start();
|
if (m_interval_x5.toSeconds() < 1.) m_interval_x5 = 1_s;
|
||||||
|
m_time_next = PISystemTime::current(true) + m_interval;
|
||||||
|
if (!thread->start()) return false;
|
||||||
|
return thread->waitForStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::start(double interval_ms_d) {
|
bool PITimer::start(PISystemTime interval) {
|
||||||
init();
|
if (isRunning()) stopAndWait();
|
||||||
// piCout << this << "start" << imp << interval_ms_d;
|
setInterval(interval);
|
||||||
setProperty("interval", interval_ms_d);
|
return start();
|
||||||
return imp->start(interval_ms_d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::start(int interval_ms_i) {
|
void PITimer::stopAndWait(PISystemTime timeout) {
|
||||||
return start((double)interval_ms_i);
|
stop();
|
||||||
|
thread->waitForFinish(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
void PITimer::addDelimiter(int delim, std::function<void(int)> func) {
|
||||||
//! \~english
|
delims << Delimiter(func, delim);
|
||||||
//! Timer wait "delay_msecs" milliseconds and then normally starts with \a interval() loop delay
|
|
||||||
//! \~russian
|
|
||||||
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом \a interval()
|
|
||||||
void PITimer::startDeferred(double delay_ms) {
|
|
||||||
init();
|
|
||||||
imp->startDeferred(delay_ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
void PITimer::addDelimiter(int delim, std::function<void()> func) {
|
||||||
//! \~english
|
delims << Delimiter([func](int) { func(); }, delim);
|
||||||
//! Timer wait "delay_msecs" milliseconds and then normally starts with "interval_msecs" loop delay
|
|
||||||
//! \~russian
|
|
||||||
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом "interval_msecs"
|
|
||||||
void PITimer::startDeferred(double interval_ms, double delay_ms) {
|
|
||||||
init();
|
|
||||||
imp->startDeferred(interval_ms, delay_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
|
||||||
//! \~english
|
|
||||||
//! Timer wait until "start_datetime" and then normally starts with \a interval() loop delay
|
|
||||||
//! \~russian
|
|
||||||
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом \a interval()
|
|
||||||
void PITimer::startDeferred(PIDateTime start_datetime) {
|
|
||||||
startDeferred(imp->interval_, start_datetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
|
||||||
//! \~english
|
|
||||||
//! Timer wait until "start_datetime" and then normally starts with "interval_msecs" loop delay
|
|
||||||
//! \~russian
|
|
||||||
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом "interval_msecs"
|
|
||||||
void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) {
|
|
||||||
init();
|
|
||||||
imp->startDeferred(interval_ms, start_datetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PITimer::addDelimiter(int delim, std::function<void(void *)> slot) {
|
|
||||||
delims << Delimiter([slot](void * d, int) { slot(d); }, delim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -722,14 +285,12 @@ void PITimer::removeDelimiter(int delim) {
|
|||||||
|
|
||||||
|
|
||||||
bool PITimer::restart() {
|
bool PITimer::restart() {
|
||||||
init();
|
stopAndWait();
|
||||||
imp->stop();
|
return start();
|
||||||
return imp->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PITimer::stop() {
|
void PITimer::stop() {
|
||||||
init();
|
thread->stop();
|
||||||
// piCout << this << "stop" << imp << wait;
|
event.notifyAll();
|
||||||
return imp->stop();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,50 +26,12 @@
|
|||||||
#ifndef PITIMER_H
|
#ifndef PITIMER_H
|
||||||
#define PITIMER_H
|
#define PITIMER_H
|
||||||
|
|
||||||
#include "pithread.h"
|
#include "piconditionvar.h"
|
||||||
#include "pitime.h"
|
#include "piobject.h"
|
||||||
|
#include "pisystemtime.h"
|
||||||
|
|
||||||
typedef std::function<void(void *, int)> 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 = nullptr;
|
|
||||||
PITimer * parent = nullptr;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool startTimer(double interval_ms) = 0;
|
|
||||||
virtual bool stopTimer() = 0;
|
|
||||||
|
|
||||||
double interval_ = 1000., deferred_delay = 0.;
|
|
||||||
bool deferred_ = false, deferred_mode = false; // mode: true - date, false - delay
|
|
||||||
std::atomic_bool running_;
|
|
||||||
PIDateTime deferred_datetime;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
class PIThread;
|
||||||
|
|
||||||
class PIP_EXPORT PITimer: public PIObject {
|
class PIP_EXPORT PITimer: public PIObject {
|
||||||
PIOBJECT_SUBCLASS(PITimer, PIObject);
|
PIOBJECT_SUBCLASS(PITimer, PIObject);
|
||||||
@@ -77,118 +39,70 @@ class PIP_EXPORT PITimer: public PIObject {
|
|||||||
public:
|
public:
|
||||||
NO_COPY_CLASS(PITimer);
|
NO_COPY_CLASS(PITimer);
|
||||||
|
|
||||||
//! \~english Constructs timer with PITimer::Thread implementation
|
//! \~english Constructs timer
|
||||||
//! \~russian Создает таймер с реализацией PITimer::Thread
|
//! \~russian Создает таймер
|
||||||
explicit PITimer();
|
explicit PITimer();
|
||||||
|
|
||||||
//! \~english Timer implementations
|
//! \~english Constructs timer with method void(int)
|
||||||
//! \~russian Реализация таймера
|
//! \~russian Создает таймер с функцией void(int)
|
||||||
enum TimerImplementation {
|
explicit PITimer(std::function<void(int)> func);
|
||||||
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
|
//! \~english Constructs timer with method void()
|
||||||
//! \~russian Создает таймер с реализацией "ti"
|
//! \~russian Создает таймер с функцией void()
|
||||||
explicit PITimer(TimerImplementation ti);
|
explicit PITimer(std::function<void()> func);
|
||||||
|
|
||||||
//! \~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<void()> 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<void(void *)> slot, void * data, TimerImplementation ti = Thread);
|
|
||||||
|
|
||||||
virtual ~PITimer();
|
virtual ~PITimer();
|
||||||
|
|
||||||
|
//! \~english Returns timer loop delay
|
||||||
|
//! \~russian Возвращает задержку цикла таймера
|
||||||
|
PISystemTime interval() const;
|
||||||
|
|
||||||
//! \~english Returns timer implementation
|
//! \~english Set timer loop delay
|
||||||
//! \~russian Возвращает реализацию таймера
|
//! \~russian Установить интервал таймера
|
||||||
PITimer::TimerImplementation implementation() const { return imp_mode; }
|
void setInterval(PISystemTime interval);
|
||||||
|
|
||||||
//! \~english Returns timer loop delay in milliseconds
|
|
||||||
//! \~russian Возвращает задержку цикла таймера в миллисекундах
|
|
||||||
double interval() const;
|
|
||||||
|
|
||||||
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 Возвращает работает ли таймер
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
|
|
||||||
//! \~english Returns if timer is not started
|
//! \~english Return if timer is stopping
|
||||||
//! \~russian Возвращает остановлен ли таймер
|
//! \~russian Возвращает останавливается ли таймер
|
||||||
bool isStopped() const;
|
bool isStopping() const;
|
||||||
|
|
||||||
|
//! \~english Wait for timer stop
|
||||||
|
//! \~russian Ожидает остановки таймера
|
||||||
|
bool waitForFinish(PISystemTime timeout = {});
|
||||||
|
|
||||||
|
//! \fn bool start(PISystemTime interval)
|
||||||
|
//! \brief
|
||||||
|
//! \~english Start timer with "interval" loop delay
|
||||||
|
//! \~russian Запустить таймер с интервалом "interval"
|
||||||
|
bool start(PISystemTime interval);
|
||||||
|
|
||||||
|
bool start(double interval_ms) DEPRECATEDM("use start(PISystemTime)") { return start(PISystemTime::fromMilliseconds(interval_ms)); }
|
||||||
EVENT_HANDLER0(bool, start);
|
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);
|
EVENT_HANDLER0(bool, restart);
|
||||||
|
|
||||||
|
EVENT_HANDLER0(void, stop);
|
||||||
|
|
||||||
//! \~english Start timer with \a interval() loop delay after "delay_msecs" delay
|
//! \~english Stop timer and wait for finish.
|
||||||
//! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs"
|
//! \~russian Останавливает таймер и ожидает завершения.
|
||||||
void startDeferred(double delay_ms);
|
void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); }
|
||||||
|
|
||||||
//! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay
|
//! \~english Stop timer and wait for finish.
|
||||||
//! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs"
|
//! \~russian Останавливает таймер и ожидает завершения.
|
||||||
void startDeferred(double interval_ms, double delay_ms);
|
void stopAndWait(PISystemTime timeout = {});
|
||||||
|
|
||||||
//! \~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
|
//! \~english Set timer tick function
|
||||||
//! \~russian Установить вызываемый метод
|
//! \~russian Установить вызываемый метод
|
||||||
void setSlot(TimerEvent slot) { ret_func = slot; }
|
void setSlot(std::function<void()> func) {
|
||||||
|
ret_func = [func](int) { func(); };
|
||||||
//! \~english Set timer tick function
|
|
||||||
//! \~russian Установить вызываемый метод
|
|
||||||
void setSlot(std::function<void()> slot) {
|
|
||||||
ret_func = [slot](void *, int) { slot(); };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \~english Set timer tick function
|
//! \~english Set timer tick function
|
||||||
//! \~russian Установить вызываемый метод
|
//! \~russian Установить вызываемый метод
|
||||||
void setSlot(std::function<void(void *)> slot) {
|
void setSlot(std::function<void(int)> func) { ret_func = func; }
|
||||||
ret_func = [slot](void * d, int) { slot(d); };
|
|
||||||
}
|
|
||||||
|
|
||||||
void needLockRun(bool need) { lockRun = need; }
|
void needLockRun(bool need) { lockRun = need; }
|
||||||
EVENT_HANDLER0(void, lock) { mutex_.lock(); }
|
EVENT_HANDLER0(void, lock) { mutex_.lock(); }
|
||||||
@@ -204,13 +118,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, TimerEvent slot = 0) { delims << Delimiter(slot, delim); }
|
void addDelimiter(int delim, std::function<void(int)> func = nullptr);
|
||||||
|
|
||||||
//! \~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()> slot) {
|
void addDelimiter(int delim, std::function<void()> func);
|
||||||
delims << Delimiter([slot](void *, int) { slot(); }, delim);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~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"
|
||||||
@@ -222,39 +134,15 @@ public:
|
|||||||
|
|
||||||
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
|
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
|
||||||
|
|
||||||
EVENT2(tickEvent, void *, data_, int, delimiter);
|
EVENT1(tickEvent, int, delimiter);
|
||||||
|
|
||||||
//! \handlers
|
//! \handlers
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \fn void setInterval(double ms)
|
|
||||||
//! \brief
|
|
||||||
//! \~english Set timer loop delay in milliseconds
|
|
||||||
//! \~russian Установить интервал таймера "ms" миллисекунд
|
|
||||||
|
|
||||||
//! \fn bool start()
|
//! \fn bool start()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Start timer with \a interval() loop delay
|
//! \~english Start timer with \a interval() loop delay
|
||||||
//! \~russian Запустить таймер с интервалом \a interval()
|
//! \~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()
|
//! \fn bool restart()
|
||||||
//! \brief
|
//! \brief
|
||||||
@@ -263,8 +151,8 @@ public:
|
|||||||
|
|
||||||
//! \fn bool stop()
|
//! \fn bool stop()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Stop timer and wait for it finish
|
//! \~english Stop timer (don`t wait for finish)
|
||||||
//! \~russian Остановить таймер и дождаться остановки
|
//! \~russian Остановить таймер (не дожидается остановки)
|
||||||
|
|
||||||
//! \fn void clearDelimiters()
|
//! \fn void clearDelimiters()
|
||||||
//! \brief
|
//! \brief
|
||||||
@@ -275,16 +163,14 @@ public:
|
|||||||
//! \events
|
//! \events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \fn void tickEvent(void * data, int delimiter)
|
//! \fn void tickEvent(int delimiter)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Raise on timer tick
|
//! \~english Raise on timer tick
|
||||||
//! \~russian Вызывается каждый тик таймера
|
//! \~russian Вызывается каждый тик таймера
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~english
|
//! \~english
|
||||||
//! "data" can be set with function \a setData() or from constructor.
|
|
||||||
//! "delimiter" is frequency delimiter, 1 for main loop.
|
//! "delimiter" is frequency delimiter, 1 for main loop.
|
||||||
//! \~russian
|
//! \~russian
|
||||||
//! "data" устанавливается методом \a setData() или в конструкторе.
|
|
||||||
//! "delimiter" - делитель частоты, 1 для основного цикла
|
//! "delimiter" - делитель частоты, 1 для основного цикла
|
||||||
|
|
||||||
|
|
||||||
@@ -292,33 +178,33 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct PIP_EXPORT Delimiter {
|
struct PIP_EXPORT Delimiter {
|
||||||
Delimiter(TimerEvent slot_ = 0, int delim_ = 1) {
|
Delimiter(std::function<void(int)> func_ = nullptr, int delim_ = 1) {
|
||||||
slot = slot_;
|
func = func_;
|
||||||
delim = delim_;
|
delim = delim_;
|
||||||
}
|
}
|
||||||
TimerEvent slot;
|
std::function<void(int)> func;
|
||||||
int delim = 0;
|
int delim = 0;
|
||||||
int tick = 0;
|
int tick = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initFirst();
|
void initFirst();
|
||||||
void init() const;
|
void init() const;
|
||||||
void destroy();
|
|
||||||
|
|
||||||
static void tickImpS(PITimer * t) { t->tickImp(); }
|
void threadFunc();
|
||||||
void tickImp();
|
void adjustTimes();
|
||||||
|
void execTick();
|
||||||
|
|
||||||
//! 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(int delimiter) {}
|
||||||
|
|
||||||
void * data_t = nullptr;
|
PIThread * thread = nullptr;
|
||||||
std::atomic_bool lockRun, callEvents;
|
std::atomic_bool lockRun = {false}, callEvents = {true};
|
||||||
PIMutex mutex_;
|
PIMutex mutex_;
|
||||||
TimerEvent ret_func = nullptr;
|
PISystemTime m_interval, m_interval_x5;
|
||||||
TimerImplementation imp_mode = Thread;
|
PISystemTime m_time_next;
|
||||||
|
std::function<void(int)> ret_func = nullptr;
|
||||||
PIVector<Delimiter> delims;
|
PIVector<Delimiter> delims;
|
||||||
|
PIConditionVariable event;
|
||||||
mutable _PITimerBase * imp = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,18 @@ public:
|
|||||||
//! \~russian Возвращает нулевое ли время
|
//! \~russian Возвращает нулевое ли время
|
||||||
bool isNull() const { return (seconds == 0) && (nanoseconds == 0); }
|
bool isNull() const { return (seconds == 0) && (nanoseconds == 0); }
|
||||||
|
|
||||||
|
//! \~english Returns if time is not null
|
||||||
|
//! \~russian Возвращает не нулевое ли время
|
||||||
|
bool isNotNull() const { return !isNull(); }
|
||||||
|
|
||||||
|
//! \~english Returns if time is greater than 0
|
||||||
|
//! \~russian Возвращает больше ли 0 время
|
||||||
|
bool isPositive() const { return (seconds >= 0) && (nanoseconds >= 0); }
|
||||||
|
|
||||||
|
//! \~english Returns if time is lesser than 0
|
||||||
|
//! \~russian Возвращает меньше ли 0 время
|
||||||
|
bool isNegative() const { return (seconds < 0) || (nanoseconds < 0); }
|
||||||
|
|
||||||
//! \~english Returns time value in seconds
|
//! \~english Returns time value in seconds
|
||||||
//! \~russian Возвращает значение времени в секундах
|
//! \~russian Возвращает значение времени в секундах
|
||||||
double toSeconds() const { return double(seconds) + nanoseconds / 1.e+9; }
|
double toSeconds() const { return double(seconds) + nanoseconds / 1.e+9; }
|
||||||
|
|||||||
@@ -282,9 +282,9 @@ public:
|
|||||||
const PIValueTree & operator[](const PIString & name) const { return child(name); }
|
const PIValueTree & operator[](const PIString & name) const { return child(name); }
|
||||||
|
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Recursive call "func" for every child. "full_name" is a name with path, joined with ".".
|
//! \~english Recursive call "func" for every child. "path" is a name with path, joined with ".".
|
||||||
//! \~russian Рекурсивно выполняет "func" для каждого узла. "full_name" - это имя с путём, соединены ".".
|
//! \~russian Рекурсивно выполняет "func" для каждого узла. "path" - это имя с путём, соединены ".".
|
||||||
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & full_name)> func);
|
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & path)> func);
|
||||||
|
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Returns a list of standard attribute names.
|
//! \~english Returns a list of standard attribute names.
|
||||||
|
|||||||
87
main.cpp
87
main.cpp
@@ -9,7 +9,85 @@
|
|||||||
|
|
||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
|
|
||||||
|
|
||||||
|
enum MyEvent {
|
||||||
|
meVoid,
|
||||||
|
meInt,
|
||||||
|
meString,
|
||||||
|
meIntString,
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
bool posted;
|
||||||
|
PIStateMachine * root = new PIStateMachine("Machine");
|
||||||
|
root->addOnFinish([] { piCout << "finish"; });
|
||||||
|
|
||||||
|
PIStateLambda * s1 = new PIStateLambda([] { piCout << "+ enter s1"; }, [] { piCout << "- exit s1"; }, "s1");
|
||||||
|
PIStateLambda * s2 = new PIStateLambda([] { piCout << "+ enter s2"; }, [] { piCout << "- exit s2"; }, "s2");
|
||||||
|
PIStateLambda * s3 = new PIStateLambda([] { piCout << "+ enter s3"; }, [] { piCout << "- exit s3"; }, "s3");
|
||||||
|
PIStateLambda * s11 = new PIStateLambda([] { piCout << " + enter s11"; }, [] { piCout << " - exit s11"; }, "s11");
|
||||||
|
PIStateLambda * s12 = new PIStateLambda([] { piCout << " + enter s12"; }, [] { piCout << " - exit s12"; }, "s12");
|
||||||
|
PIStateLambda * s13 = new PIStateLambda([] { piCout << " + enter s13"; }, [] { piCout << " - exit s13"; }, "s13");
|
||||||
|
PIStateLambda * s21 = new PIStateLambda([] { piCout << " + enter s21"; }, [] { piCout << " - exit s21"; }, "s21");
|
||||||
|
PIStateLambda * s22 = new PIStateLambda([] { piCout << " + enter s22"; }, [] { piCout << " - exit s22"; }, "s22");
|
||||||
|
PIStateLambda * s23 = new PIStateLambda([] { piCout << " + enter s23"; }, [] { piCout << " - exit s23"; }, "s23");
|
||||||
|
PIStateLambda * s211 = new PIStateLambda([] { piCout << " + enter s211"; }, [] { piCout << " - exit s211"; }, "s211");
|
||||||
|
PIStateLambda * s212 = new PIStateLambda([] { piCout << " + enter s212"; }, [] { piCout << " - exit s212"; }, "s212");
|
||||||
|
PIStateLambda * s213 = new PIStateLambda([] { piCout << " + enter s213"; }, [] { piCout << " - exit s213"; }, "s213");
|
||||||
|
PIStateFinal * s214 = new PIStateFinal([] { piCout << " + enter s214 final"; }, "s214f");
|
||||||
|
|
||||||
|
root->addStates({s1, s2, s3});
|
||||||
|
s1->addStates({s11, s12, s13});
|
||||||
|
s2->addStates({s21, s22, s23});
|
||||||
|
s21->addStates({s211, s212, s213});
|
||||||
|
// root->addState(s214);
|
||||||
|
|
||||||
|
s2->setParallel(true);
|
||||||
|
|
||||||
|
root->setInitialState(s2);
|
||||||
|
s1->setInitialState(s11);
|
||||||
|
s2->setInitialState(s21);
|
||||||
|
s21->setInitialState(s213);
|
||||||
|
|
||||||
|
s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; });
|
||||||
|
s3->addTransition(s212, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; });
|
||||||
|
// s2->addTransition(s3, meInt)->addGuard([](int i) { return i == 1; });
|
||||||
|
// s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; });
|
||||||
|
|
||||||
|
root->start();
|
||||||
|
piCout << "initial" << root->isRunning() << "\n";
|
||||||
|
piCout << "active atomics" << root->activeAtomics();
|
||||||
|
root->print();
|
||||||
|
|
||||||
|
piCout << "\npost event";
|
||||||
|
posted = root->postEvent(meVoid);
|
||||||
|
piCout << "posted" << posted << "\n";
|
||||||
|
piCout << "active atomics" << root->activeAtomics();
|
||||||
|
root->print();
|
||||||
|
|
||||||
|
// piCout << "\npost event";
|
||||||
|
// posted = root->postEvent(meVoid);
|
||||||
|
// piCout << "posted" << posted << "\n";
|
||||||
|
// root->print();
|
||||||
|
|
||||||
|
/*root->addStates({s1, s2, s3});
|
||||||
|
root->setInitialState(s1);
|
||||||
|
root->start();
|
||||||
|
|
||||||
|
piCout << root->postEvent(meVoid);
|
||||||
|
piCout << "";
|
||||||
|
piCout << root->postEvent(meInt, 0.5f);
|
||||||
|
piCout << "";
|
||||||
|
piCout << root->postEvent(meInt, 0);
|
||||||
|
piCout << "";
|
||||||
|
piCout << root->postEvent(meInt, 1);
|
||||||
|
piCout << "";
|
||||||
|
piCout << root->postEvent(meIntString, 2, "hello");
|
||||||
|
piCout << "";
|
||||||
|
piCout << root->postEvent(meIntString, 2, PIString("hello"));
|
||||||
|
piCout << "";*/
|
||||||
|
delete root;
|
||||||
|
|
||||||
/*PISerial ser;
|
/*PISerial ser;
|
||||||
ser.setSpeed(PISerial::S115200);
|
ser.setSpeed(PISerial::S115200);
|
||||||
piCout << ser.open("COM15", PIIODevice::ReadWrite);
|
piCout << ser.open("COM15", PIIODevice::ReadWrite);
|
||||||
@@ -62,9 +140,14 @@ int main(int argc, char * argv[]) {
|
|||||||
test_str("1hz 1hz");*/
|
test_str("1hz 1hz");*/
|
||||||
|
|
||||||
// PIPair<int, PIString> p = createPIPair(0, "");
|
// PIPair<int, PIString> p = createPIPair(0, "");
|
||||||
PIVector<PIPair<int, PIString>> pv;
|
/*PIConfig conf("model.conf");
|
||||||
pv << createPIPair(0, PIString());
|
piCout << "****** config\n" << conf.allLeaves() << "******\n";
|
||||||
|
|
||||||
|
PIValueTree vt = PIValueTreeConversions::fromTextFile("model.conf");
|
||||||
|
piCout << "****** tree";
|
||||||
|
vt.forEachRecursive(
|
||||||
|
[](const PIValueTree & v, const PIString & fn) { piCout << fn << "=" << v.value().toString() << "#" << v.comment(); });
|
||||||
|
piCout << "******";*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
#include "piliterals_time.h"
|
||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
PIByteArray rnd;
|
PIByteArray rnd;
|
||||||
rnd.resize(1024 * 1024, 'x');
|
rnd.resize(1024 * 1024, 'x');
|
||||||
@@ -12,7 +12,7 @@ int main(int argc, char * argv[]) {
|
|||||||
// c.setReopenEnabled(true);
|
// c.setReopenEnabled(true);
|
||||||
PICloudServer s("127.0.0.1:10101");
|
PICloudServer s("127.0.0.1:10101");
|
||||||
auto clients = new PIVector<PICloudServer::Client *>();
|
auto clients = new PIVector<PICloudServer::Client *>();
|
||||||
CONNECTL(&tm, tickEvent, ([&](void *, int) {
|
CONNECTL(&tm, tickEvent, ([&](int) {
|
||||||
if (c.isConnected()) {
|
if (c.isConnected()) {
|
||||||
PIString str = "ping";
|
PIString str = "ping";
|
||||||
piCout << "[Client] send:" << str;
|
piCout << "[Client] send:" << str;
|
||||||
@@ -67,7 +67,7 @@ int main(int argc, char * argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
s.startThreadedRead();
|
s.startThreadedRead();
|
||||||
}
|
}
|
||||||
tm.start(1000);
|
tm.start(1_Hz);
|
||||||
PIKbdListener ls;
|
PIKbdListener ls;
|
||||||
ls.enableExitCapture(PIKbdListener::F10);
|
ls.enableExitCapture(PIKbdListener::F10);
|
||||||
ls.start();
|
ls.start();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "dispatcherserver.h"
|
#include "dispatcherserver.h"
|
||||||
|
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "piscreentiles.h"
|
#include "piscreentiles.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ DispatcherServer::~DispatcherServer() {
|
|||||||
|
|
||||||
void DispatcherServer::start() {
|
void DispatcherServer::start() {
|
||||||
eth.listen(true);
|
eth.listen(true);
|
||||||
timeout_timer.start(2000);
|
timeout_timer.start(0.5_Hz);
|
||||||
piCoutObj << "server started" << eth.readAddress();
|
piCoutObj << "server started" << eth.readAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define DISPATCHERSERVER_H
|
#define DISPATCHERSERVER_H
|
||||||
|
|
||||||
#include "cloudserver.h"
|
#include "cloudserver.h"
|
||||||
|
#include "pitimer.h"
|
||||||
|
|
||||||
class TileList;
|
class TileList;
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dispatcherserver.h"
|
#include "dispatcherserver.h"
|
||||||
#include "picrypt.h"
|
#include "picli.h"
|
||||||
|
#include "piconfig.h"
|
||||||
|
#include "pidir.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
#include "pip.h"
|
#include "piliterals_time.h"
|
||||||
|
#include "piscreen.h"
|
||||||
|
#include "piscreentiles.h"
|
||||||
|
#include "piscreentypes.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
@@ -127,7 +132,7 @@ int main(int argc, char * argv[]) {
|
|||||||
a.children()[0]->size_policy = PIScreenTypes::Fixed;
|
a.children()[0]->size_policy = PIScreenTypes::Fixed;
|
||||||
maintile.addTile(&a);
|
maintile.addTile(&a);
|
||||||
}
|
}
|
||||||
CONNECTL(&status_timer, tickEvent, [&](void *, int) {
|
CONNECTL(&status_timer, tickEvent, [&](int) {
|
||||||
screen.lock();
|
screen.lock();
|
||||||
server.updateConnectionsTile(&conn_tl);
|
server.updateConnectionsTile(&conn_tl);
|
||||||
server.updateServersTile(&server_tl, sel_servers);
|
server.updateServersTile(&server_tl, sel_servers);
|
||||||
@@ -142,7 +147,7 @@ int main(int argc, char * argv[]) {
|
|||||||
screen.rootTile()->addTile(new TilePICout());
|
screen.rootTile()->addTile(new TilePICout());
|
||||||
screen.start();
|
screen.start();
|
||||||
server.start();
|
server.start();
|
||||||
status_timer.start(100);
|
status_timer.start(10_Hz);
|
||||||
screen.waitForFinish();
|
screen.waitForFinish();
|
||||||
} else {
|
} else {
|
||||||
PIKbdListener ls;
|
PIKbdListener ls;
|
||||||
@@ -151,7 +156,7 @@ int main(int argc, char * argv[]) {
|
|||||||
server.start();
|
server.start();
|
||||||
if (cli.hasArgument("verbose")) {
|
if (cli.hasArgument("verbose")) {
|
||||||
CONNECTU(&status_timer, tickEvent, &server, picoutStatus);
|
CONNECTU(&status_timer, tickEvent, &server, picoutStatus);
|
||||||
status_timer.start(1000);
|
status_timer.start(1_Hz);
|
||||||
}
|
}
|
||||||
WAIT_FOR_EXIT
|
WAIT_FOR_EXIT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ int main(int argc, char * argv[]) {
|
|||||||
# define PIP_CONSOLE_STATIC_DEFINE
|
# define PIP_CONSOLE_STATIC_DEFINE
|
||||||
# include "../../libs/console/piterminal.cpp"
|
# include "../../libs/console/piterminal.cpp"
|
||||||
# include "pifile.h"
|
# include "pifile.h"
|
||||||
|
# include "piliterals_time.h"
|
||||||
# include "pip_console_export.h"
|
# include "pip_console_export.h"
|
||||||
# include "piscreentypes.h"
|
# include "piscreentypes.h"
|
||||||
# include "pisharedmemory.h"
|
# include "pisharedmemory.h"
|
||||||
@@ -164,9 +165,12 @@ public:
|
|||||||
PipeReader(): PIThread() {
|
PipeReader(): PIThread() {
|
||||||
wrote = readed = 0;
|
wrote = readed = 0;
|
||||||
msg_size = 0;
|
msg_size = 0;
|
||||||
start(1);
|
start(1_ms);
|
||||||
|
}
|
||||||
|
~PipeReader() {
|
||||||
|
stop();
|
||||||
|
if (!waitForFinish(100_ms)) terminate();
|
||||||
}
|
}
|
||||||
~PipeReader() { stop(); }
|
|
||||||
void run() {
|
void run() {
|
||||||
in.resize(PIPE_BUFFER_SIZE);
|
in.resize(PIPE_BUFFER_SIZE);
|
||||||
ReadFile(pipe, in.data(), in.size_s(), &readed, 0);
|
ReadFile(pipe, in.data(), in.size_s(), &readed, 0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
#include "picrypt.h"
|
#include "picrypt.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "pisysteminfo.h"
|
#include "pisysteminfo.h"
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ Daemon::Remote::Remote(const PIString & n): PIThread() {
|
|||||||
|
|
||||||
|
|
||||||
Daemon::Remote::~Remote() {
|
Daemon::Remote::~Remote() {
|
||||||
|
term_timer.stopAndWait();
|
||||||
shellClose();
|
shellClose();
|
||||||
ft.stop();
|
ft.stop();
|
||||||
stopAndWait();
|
stopAndWait();
|
||||||
@@ -34,14 +36,14 @@ void Daemon::Remote::shellOpen() {
|
|||||||
piCoutObj << "shell open";
|
piCoutObj << "shell open";
|
||||||
term = new PITerminal();
|
term = new PITerminal();
|
||||||
term->initialize();
|
term->initialize();
|
||||||
term_timer.start(50);
|
term_timer.start(20_Hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Daemon::Remote::shellClose() {
|
void Daemon::Remote::shellClose() {
|
||||||
if (!term) return;
|
if (!term) return;
|
||||||
piCoutObj << "shell close";
|
piCoutObj << "shell close";
|
||||||
term_timer.stop();
|
term_timer.stopAndWait();
|
||||||
term->destroy();
|
term->destroy();
|
||||||
delete term;
|
delete term;
|
||||||
term = 0;
|
term = 0;
|
||||||
@@ -272,7 +274,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_"
|
|||||||
localft.setCRCEnabled(false);
|
localft.setCRCEnabled(false);
|
||||||
CONNECTU(&localft, sendRequest, _self, received)
|
CONNECTU(&localft, sendRequest, _self, received)
|
||||||
dtimer.addDelimiter(5);
|
dtimer.addDelimiter(5);
|
||||||
dtimer.start(200);
|
dtimer.start(5_Hz);
|
||||||
|
|
||||||
tile_root = new PIScreenTile();
|
tile_root = new PIScreenTile();
|
||||||
tile_root->direction = Vertical;
|
tile_root->direction = Vertical;
|
||||||
@@ -320,6 +322,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_"
|
|||||||
|
|
||||||
|
|
||||||
Daemon::~Daemon() {
|
Daemon::~Daemon() {
|
||||||
|
dtimer.stopAndWait();
|
||||||
requestCloseShell();
|
requestCloseShell();
|
||||||
PIVector<Remote *> rl = remotes.values();
|
PIVector<Remote *> rl = remotes.values();
|
||||||
piForeach(Remote * r, rl) {
|
piForeach(Remote * r, rl) {
|
||||||
@@ -547,7 +550,7 @@ void Daemon::fmActionRequest(bool remote_tile, FileManager::Action type, PIVaria
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Daemon::timerEvent(void * _d, int delim) {
|
void Daemon::timerEvent(int delim) {
|
||||||
screen->lock();
|
screen->lock();
|
||||||
list_daemons->content.clear();
|
list_daemons->content.clear();
|
||||||
availableDaemons();
|
availableDaemons();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define DAEMON_H
|
#define DAEMON_H
|
||||||
|
|
||||||
#include "file_manager.h"
|
#include "file_manager.h"
|
||||||
#include "pidatatransfer.h"
|
|
||||||
#include "pifiletransfer.h"
|
#include "pifiletransfer.h"
|
||||||
#include "pipeer.h"
|
#include "pipeer.h"
|
||||||
#include "piscreentiles.h"
|
#include "piscreentiles.h"
|
||||||
@@ -165,7 +164,7 @@ private:
|
|||||||
EVENT_HANDLER3(void, fmActionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data);
|
EVENT_HANDLER3(void, fmActionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data);
|
||||||
EVENT_HANDLER(void, shResizeRequest);
|
EVENT_HANDLER(void, shResizeRequest);
|
||||||
EVENT_HANDLER1(void, shKeyEvent, PIKbdListener::KeyEvent, k);
|
EVENT_HANDLER1(void, shKeyEvent, PIKbdListener::KeyEvent, k);
|
||||||
EVENT_HANDLER2(void, timerEvent, void *, _d, int, delim);
|
EVENT_HANDLER1(void, timerEvent, int, delim);
|
||||||
EVENT_HANDLER2(void, filesReceived, const PIString &, p_name, bool, ok);
|
EVENT_HANDLER2(void, filesReceived, const PIString &, p_name, bool, ok);
|
||||||
EVENT_HANDLER2(void, filesSended, const PIString &, p_name, bool, ok);
|
EVENT_HANDLER2(void, filesSended, const PIString &, p_name, bool, ok);
|
||||||
EVENT_HANDLER2(void, dirChanged, const PIString &, p_name, const PIString &, dir);
|
EVENT_HANDLER2(void, dirChanged, const PIString &, p_name, const PIString &, dir);
|
||||||
|
|||||||
@@ -21,20 +21,19 @@
|
|||||||
#include "file_manager.h"
|
#include "file_manager.h"
|
||||||
#include "picli.h"
|
#include "picli.h"
|
||||||
#include "piintrospection_server.h"
|
#include "piintrospection_server.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
#include "piprocess.h"
|
#include "piprocess.h"
|
||||||
#include "pisingleapplication.h"
|
#include "pisingleapplication.h"
|
||||||
#include "pisysteminfo.h"
|
#include "pisysteminfo.h"
|
||||||
#include "pisystemmonitor.h"
|
#include "pisystemmonitor.h"
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
|
|
||||||
class _Init {
|
STATIC_INITIALIZER_BEGIN
|
||||||
public:
|
randomize();
|
||||||
_Init() { randomize(); }
|
STATIC_INITIALIZER_END
|
||||||
};
|
|
||||||
_Init _pisd_init;
|
|
||||||
|
|
||||||
PISystemMonitor sys_mon;
|
PISystemMonitor sys_mon;
|
||||||
PIScreen * screen = 0;
|
PIScreen * screen = nullptr;
|
||||||
|
|
||||||
|
|
||||||
class MainMenu: public PITimer {
|
class MainMenu: public PITimer {
|
||||||
@@ -93,7 +92,7 @@ public:
|
|||||||
CONNECTU(screen, tileEvent, this, tileEvent)
|
CONNECTU(screen, tileEvent, this, tileEvent)
|
||||||
CONNECTU(screen, keyPressed, this, keyEvent)
|
CONNECTU(screen, keyPressed, this, keyEvent)
|
||||||
CONNECTU(&daemon_, menuRequest, this, menuRequest)
|
CONNECTU(&daemon_, menuRequest, this, menuRequest)
|
||||||
start(25);
|
start(40_Hz);
|
||||||
}
|
}
|
||||||
PIScreenTile * menuTile() {
|
PIScreenTile * menuTile() {
|
||||||
TileList * ret = new TileList();
|
TileList * ret = new TileList();
|
||||||
@@ -185,13 +184,19 @@ public:
|
|||||||
addrs_tl->content.clear();
|
addrs_tl->content.clear();
|
||||||
peerinfo_tl->content.clear();
|
peerinfo_tl->content.clear();
|
||||||
peermap_tl->content.clear();
|
peermap_tl->content.clear();
|
||||||
peers_tl->content << TileList::Row("this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s())
|
peers_tl->content << TileList::Row(
|
||||||
// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ",
|
"this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s())
|
||||||
//" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " "sm = " +
|
// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ",
|
||||||
//PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " +
|
//" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", "
|
||||||
//PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm) + "]"
|
//"sm
|
||||||
,
|
//=
|
||||||
CellFormat());
|
//"
|
||||||
|
//+ PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " +
|
||||||
|
// PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm)
|
||||||
|
// +
|
||||||
|
// "]"
|
||||||
|
,
|
||||||
|
CellFormat());
|
||||||
piForeachC(PIPeer::PeerInfo & p, daemon_.allPeers())
|
piForeachC(PIPeer::PeerInfo & p, daemon_.allPeers())
|
||||||
peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " +
|
peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " +
|
||||||
PIString::fromNumber(p.ping()) + " | n = " + PIString::fromBool(p.isNeighbour()),
|
PIString::fromNumber(p.ping()) + " | n = " + PIString::fromBool(p.isNeighbour()),
|
||||||
@@ -246,7 +251,7 @@ public:
|
|||||||
}
|
}
|
||||||
screen->unlock();
|
screen->unlock();
|
||||||
}
|
}
|
||||||
void tick(void * data_, int delimiter) override {
|
void tick(int delimiter) override {
|
||||||
if (tpeerdiag->visible || tpeer->visible) updatePeerInfo();
|
if (tpeerdiag->visible || tpeer->visible) updatePeerInfo();
|
||||||
if (tinfo->visible) updateSysMon();
|
if (tinfo->visible) updateSysMon();
|
||||||
}
|
}
|
||||||
@@ -420,7 +425,7 @@ int main(int argc, char * argv[]) {
|
|||||||
ls.enableExitCapture(PIKbdListener::F10);
|
ls.enableExitCapture(PIKbdListener::F10);
|
||||||
ls.start();
|
ls.start();
|
||||||
WAIT_FOR_EXIT
|
WAIT_FOR_EXIT
|
||||||
ls.stop();
|
ls.stopAndWait();
|
||||||
} else {
|
} else {
|
||||||
screen->start();
|
screen->start();
|
||||||
screen->waitForFinish();
|
screen->waitForFinish();
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picli.h"
|
||||||
#include "pidatatransfer.h"
|
#include "pidatatransfer.h"
|
||||||
|
#include "piethernet.h"
|
||||||
#include "pifiletransfer.h"
|
#include "pifiletransfer.h"
|
||||||
#include "pip.h"
|
#include "piliterals_time.h"
|
||||||
#include "piscreen.h"
|
#include "piscreen.h"
|
||||||
#include "piscreentiles.h"
|
#include "piscreentiles.h"
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ public:
|
|||||||
CONNECTU(&ft, receiveFilesFinished, this, ftevent);
|
CONNECTU(&ft, receiveFilesFinished, this, ftevent);
|
||||||
}
|
}
|
||||||
CONNECT2(void, const uchar *, ssize_t, ð, threadedReadEvent, this, received);
|
CONNECT2(void, const uchar *, ssize_t, ð, threadedReadEvent, this, received);
|
||||||
start(50);
|
start(20_Hz);
|
||||||
eth.setParameter(PIEthernet::SeparateSockets);
|
eth.setParameter(PIEthernet::SeparateSockets);
|
||||||
eth.startThreadedRead();
|
eth.startThreadedRead();
|
||||||
}
|
}
|
||||||
@@ -74,7 +76,7 @@ private:
|
|||||||
PIEthernet eth;
|
PIEthernet eth;
|
||||||
bool quet_;
|
bool quet_;
|
||||||
|
|
||||||
void tick(void *, int) override {
|
void tick(int) override {
|
||||||
if (ft.isStarted()) {
|
if (ft.isStarted()) {
|
||||||
ftevent();
|
ftevent();
|
||||||
updatePMT();
|
updatePMT();
|
||||||
|
|||||||
Reference in New Issue
Block a user