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_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(PIP)
|
||||
set(PIP_MAJOR 3)
|
||||
set(PIP_MINOR 21)
|
||||
set(PIP_MAJOR 4)
|
||||
set(PIP_MINOR 0)
|
||||
set(PIP_REVISION 0)
|
||||
set(PIP_SUFFIX )
|
||||
set(PIP_SUFFIX _alpha)
|
||||
set(PIP_COMPANY SHS)
|
||||
set(PIP_DOMAIN org.SHS)
|
||||
|
||||
@@ -247,18 +247,6 @@ if(PIP_MATH_YN)
|
||||
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
|
||||
if (PIP_BUILD_DEBUG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
|
||||
@@ -317,15 +305,6 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
|
||||
#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
|
||||
if(APPLE)
|
||||
@@ -673,7 +652,6 @@ message("")
|
||||
message(" Options:")
|
||||
message(" std::iostream: ${PIP_STD_IOSTREAM}")
|
||||
message(" ICU strings : ${PIP_ICU}")
|
||||
message(" Timer types : ${PIP_TIMERS}")
|
||||
message(" Introspection: ${PIP_INTROSPECTION}")
|
||||
message(" Coverage : ${PIP_COVERAGE}")
|
||||
if(INTROSPECTION)
|
||||
|
||||
@@ -66,10 +66,6 @@ if (NOT BUILDING_PIP)
|
||||
find_library(PTHREAD_LIBRARY pthread)
|
||||
find_library(UTIL_LIBRARY util)
|
||||
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_})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "pip.h"
|
||||
|
||||
|
||||
//! [delimiter]
|
||||
void tfunc(void * , int delim) {
|
||||
void tfunc(int delim) {
|
||||
piCout << "tick with delimiter" << delim;
|
||||
};
|
||||
void tfunc4(void * , int delim) {
|
||||
void tfunc4(int delim) {
|
||||
piCout << "tick4 with delimiter" << delim;
|
||||
};
|
||||
int main() {
|
||||
@@ -13,8 +13,7 @@ int main() {
|
||||
timer.addDelimiter(4, tfunc4);
|
||||
timer.start(50);
|
||||
piMSleep(200);
|
||||
timer.stop();
|
||||
timer.waitForFinish();
|
||||
timer.stopAndWait();
|
||||
return 0;
|
||||
};
|
||||
/* Result:
|
||||
@@ -29,14 +28,14 @@ tick4 with delimiter 4
|
||||
//! [delimiter]
|
||||
//! [elapsed]
|
||||
int main() {
|
||||
PITimer timer;
|
||||
PITimeMeasurer tm;
|
||||
piMSleep(100);
|
||||
piCout << "elapsed" << timer.elapsed_m() << "ms";
|
||||
piCout << "elapsed" << tm.elapsed_m() << "ms";
|
||||
piMSleep(100);
|
||||
piCout << "elapsed" << timer.elapsed_m() << "ms";
|
||||
timer.reset();
|
||||
piCout << "elapsed" << tm.elapsed_m() << "ms";
|
||||
tm.reset();
|
||||
piMSleep(150);
|
||||
piCout << "elapsed" << timer.elapsed_s() << "s";
|
||||
piCout << "elapsed" << tm.elapsed_s() << "s";
|
||||
return 0;
|
||||
};
|
||||
/* Result:
|
||||
@@ -47,22 +46,21 @@ elapsed 0.15 s
|
||||
//! [elapsed]
|
||||
//! [system_time]
|
||||
int main() {
|
||||
PISystemTime t0; // s = ns = 0
|
||||
t0.addMilliseconds(200); // s = 0, ns = 200000000
|
||||
t0.addMilliseconds(900); // s = 1, ns = 100000000
|
||||
PISystemTime t0; // s = ns = 0
|
||||
t0.addMilliseconds(200); // s = 0, ns = 200000000
|
||||
t0.addMilliseconds(900); // s = 1, ns = 100000000
|
||||
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
|
||||
t0.sleep(); // sleep for 1 second
|
||||
t0.sleep(); // sleep for 1 second
|
||||
PISystemTime t1;
|
||||
t0 = currentSystemTime();
|
||||
t0 = PISystemTime::current();
|
||||
piMSleep(500);
|
||||
t1 = currentSystemTime();
|
||||
t1 = PISystemTime::current();
|
||||
(t1 - t0).sleep(); // sleep for 500 milliseconds
|
||||
return 0;
|
||||
};
|
||||
//! [system_time]
|
||||
|
||||
void _() {
|
||||
|
||||
void _(){
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ class MainClass: public PITimer {
|
||||
public:
|
||||
MainClass() {}
|
||||
protected:
|
||||
void tick(void * data, int delimiter) {
|
||||
void tick(int delimiter) {
|
||||
piCout << "timer tick";
|
||||
// timer tick
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ bool PICloudClient::openDevice() {
|
||||
mutex_connect.lock();
|
||||
eth.startThreadedRead();
|
||||
// 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;
|
||||
mutex_connect.unlock();
|
||||
if (!conn_ok) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "picloudserver.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
|
||||
|
||||
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
|
||||
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000);
|
||||
@@ -94,7 +96,7 @@ bool PICloudServer::openDevice() {
|
||||
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
|
||||
if (op) {
|
||||
eth.startThreadedRead();
|
||||
ping_timer.start(5000);
|
||||
ping_timer.start(5_s);
|
||||
return true;
|
||||
} else {
|
||||
ping_timer.stop();
|
||||
@@ -169,7 +171,7 @@ PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client
|
||||
PICloudServer::Client::~Client() {
|
||||
// piCoutObj << "~PICloudServer::Client..." << this;
|
||||
close();
|
||||
stopAndWait(10000);
|
||||
stopAndWait(10_s);
|
||||
// piCoutObj << "~PICloudServer::Client done" << this;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "piscreen.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals_time.h"
|
||||
#ifndef WINDOWS
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
@@ -417,8 +418,8 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
|
||||
|
||||
PIScreen::~PIScreen() {
|
||||
if (isRunning()) stop();
|
||||
PIThread::waitForFinish(10);
|
||||
listener->waitForFinish(10);
|
||||
PIThread::waitForFinish(100_ms);
|
||||
listener->waitForFinish(100_ms);
|
||||
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) {
|
||||
PIThread::stopAndWait();
|
||||
if (clear) console.clearScreen();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "piterminal.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pisharedmemory.h"
|
||||
#ifndef MICRO_PIP
|
||||
# ifdef WINDOWS
|
||||
@@ -126,7 +127,7 @@ PITerminal::PITerminal(): PIThread() {
|
||||
|
||||
PITerminal::~PITerminal() {
|
||||
if (isRunning()) stop();
|
||||
PIThread::waitForFinish(10);
|
||||
PIThread::waitForFinish(1_s);
|
||||
destroy();
|
||||
# ifdef WINDOWS
|
||||
if (PRIVATE->shm) delete PRIVATE->shm;
|
||||
@@ -915,7 +916,7 @@ bool PITerminal::initialize() {
|
||||
# endif
|
||||
cursor_blink = false;
|
||||
cursor_tm.reset();
|
||||
start(40);
|
||||
start(25_Hz);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -923,7 +924,7 @@ bool PITerminal::initialize() {
|
||||
void PITerminal::destroy() {
|
||||
// piCout << "destroy ...";
|
||||
stop();
|
||||
waitForFinish(1000);
|
||||
waitForFinish(1_s);
|
||||
# ifdef WINDOWS
|
||||
if (PRIVATE->pi.hProcess) {
|
||||
// piCout << "term";
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pibroadcast.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
|
||||
/** \class PIBroadcast
|
||||
* \brief Broadcast for all interfaces, including loopback
|
||||
*
|
||||
@@ -223,7 +225,7 @@ void PIBroadcast::startRead() {
|
||||
if (!isRunning()) {
|
||||
_started = false;
|
||||
reinit();
|
||||
PIThread::start(3000);
|
||||
PIThread::start(3_s);
|
||||
}
|
||||
if (_send_only) return;
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "pistreampacker.h"
|
||||
|
||||
#include "piiodevice.h"
|
||||
#include "piliterals_bytes.h"
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -52,7 +53,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
|
||||
aggressive_optimization = true;
|
||||
packet_size = -1;
|
||||
size_crypted_size = sizeof(int);
|
||||
crypt_frag_size = 1024 * 1024;
|
||||
crypt_frag_size = 1_MiB;
|
||||
max_packet_size = 1400;
|
||||
packet_sign = 0xAFBE;
|
||||
assignDevice(dev);
|
||||
|
||||
@@ -167,7 +167,8 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
|
||||
|
||||
|
||||
PIKbdListener::~PIKbdListener() {
|
||||
terminate();
|
||||
stop();
|
||||
if (!waitForFinish(100_ms)) terminate();
|
||||
end();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,10 +73,7 @@ public:
|
||||
|
||||
EVENT_HANDLER0(void, waitForFinish);
|
||||
EVENT_HANDLER0(void, start) { start(false); }
|
||||
EVENT_HANDLER1(void, start, bool, wait) {
|
||||
PIThread::start(40);
|
||||
if (wait) waitForFinish();
|
||||
}
|
||||
EVENT_HANDLER1(void, start, bool, wait);
|
||||
EVENT_HANDLER0(void, stop) { stop(false); }
|
||||
EVENT_HANDLER1(void, stop, bool, clear);
|
||||
|
||||
|
||||
@@ -150,11 +150,6 @@
|
||||
//! \~russian Макрос объявлен когда компилятор неизвестен
|
||||
# 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
|
||||
//! \~english Macro to declare private section, "export" is optional
|
||||
//! \~russian Макрос для объявления частной секции, "export" необязателен
|
||||
|
||||
@@ -48,7 +48,7 @@ void PIIntrospectionThreads::threadStart(PIThread * t) {
|
||||
ThreadInfo & ti(threads[t]);
|
||||
ti.id = t->tid();
|
||||
ti.priority = t->priority();
|
||||
ti.delay = t->delay_;
|
||||
ti.delay = t->delay_.toMilliseconds();
|
||||
ti.state = sStarting;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
#include "pibinarylog.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "piliterals.h"
|
||||
#include "piliterals_bytes.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#define PIBINARYLOG_VERSION_OLD 0x31
|
||||
|
||||
@@ -259,9 +261,9 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
|
||||
<< "Creating directory" << dir.path();
|
||||
dir.make(true);
|
||||
}
|
||||
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString cnpath = npath + ".binlog";
|
||||
int i = 1;
|
||||
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString cnpath = npath + ".binlog";
|
||||
int i = 1;
|
||||
while (PIFile::isExists(cnpath)) {
|
||||
cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog";
|
||||
i++;
|
||||
@@ -644,9 +646,9 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
}
|
||||
PIByteArray ba;
|
||||
Record br;
|
||||
br.id = 0;
|
||||
br.size = 0;
|
||||
bool first = true;
|
||||
br.id = 0;
|
||||
br.size = 0;
|
||||
bool first = true;
|
||||
constexpr size_t hdr_size = sizeof(Record) - sizeof(PIByteArray);
|
||||
ba.resize(hdr_size);
|
||||
while (1) {
|
||||
@@ -977,16 +979,16 @@ void PIBinaryLog::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
|
||||
|
||||
void PIBinaryLog::propertyChanged(const char * s) {
|
||||
default_id = property("defaultID").toInt();
|
||||
rapid_start = property("rapidStart").toBool();
|
||||
play_mode = (PlayMode)property("playMode").toInt();
|
||||
const double ps = property("playSpeed").toDouble();
|
||||
play_speed = ps > 0. ? 1. / ps : 0.;
|
||||
play_delay = property("playDelay").toSystemTime();
|
||||
split_mode = (SplitMode)property("splitMode").toInt();
|
||||
split_time = property("splitTime").toSystemTime();
|
||||
split_size = property("splitFileSize").toLLong();
|
||||
split_count = property("splitRecordCount").toInt();
|
||||
default_id = property("defaultID").toInt();
|
||||
rapid_start = property("rapidStart").toBool();
|
||||
play_mode = (PlayMode)property("playMode").toInt();
|
||||
const double ps = property("playSpeed").toDouble();
|
||||
play_speed = ps > 0. ? 1. / ps : 0.;
|
||||
play_delay = property("playDelay").toSystemTime();
|
||||
split_mode = (SplitMode)property("splitMode").toInt();
|
||||
split_time = property("splitTime").toSystemTime();
|
||||
split_size = property("splitFileSize").toLLong();
|
||||
split_count = property("splitRecordCount").toInt();
|
||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,8 +163,8 @@ void PIEthernet::construct() {
|
||||
setOption(BlockingWrite);
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
sock = sock_s = -1;
|
||||
setReadTimeout(10000.);
|
||||
setWriteTimeout(10000.);
|
||||
setReadTimeout(10_s);
|
||||
setWriteTimeout(10_s);
|
||||
setTTL(64);
|
||||
setMulticastTTL(1);
|
||||
server_thread_.setData(this);
|
||||
@@ -331,7 +331,7 @@ void PIEthernet::closeSocket(int & sd) {
|
||||
|
||||
void PIEthernet::applyTimeouts() {
|
||||
if (sock < 0) return;
|
||||
double rtm = readTimeout(), wtm = writeTimeout();
|
||||
PISystemTime rtm = readTimeout(), wtm = writeTimeout();
|
||||
applyTimeout(sock, SO_RCVTIMEO, rtm);
|
||||
applyTimeout(sock, SO_SNDTIMEO, wtm);
|
||||
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;
|
||||
// piCoutObj << "setReadIsBlocking" << yes;
|
||||
#ifdef WINDOWS
|
||||
DWORD _tm = ms;
|
||||
DWORD _tm = tm.toMilliseconds();
|
||||
#else
|
||||
double s = ms / 1000.;
|
||||
timeval _tm;
|
||||
_tm.tv_sec = piFloord(s);
|
||||
s -= _tm.tv_sec;
|
||||
_tm.tv_usec = s * 1000000.;
|
||||
_tm.tv_sec = tm.seconds;
|
||||
_tm.tv_usec = tm.nanoseconds / 1000;
|
||||
#endif
|
||||
ethSetsockopt(fd, SOL_SOCKET, opt, &_tm, sizeof(_tm));
|
||||
}
|
||||
|
||||
@@ -174,16 +174,16 @@ public:
|
||||
Type type() const { return eth_type; }
|
||||
|
||||
//! Returns read timeout
|
||||
double readTimeout() const { return property("readTimeout").toDouble(); }
|
||||
PISystemTime readTimeout() const { return property("readTimeout").toSystemTime(); }
|
||||
|
||||
//! Returns write timeout
|
||||
double writeTimeout() const { return property("writeTimeout").toDouble(); }
|
||||
PISystemTime writeTimeout() const { return property("writeTimeout").toSystemTime(); }
|
||||
|
||||
//! Set timeout for read
|
||||
void setReadTimeout(double ms) { setProperty("readTimeout", ms); }
|
||||
void setReadTimeout(PISystemTime tm) { setProperty("readTimeout", tm); }
|
||||
|
||||
//! Set timeout for write
|
||||
void setWriteTimeout(double ms) { setProperty("writeTimeout", ms); }
|
||||
void setWriteTimeout(PISystemTime tm) { setProperty("writeTimeout", tm); }
|
||||
|
||||
|
||||
//! Returns TTL (Time To Live)
|
||||
@@ -437,11 +437,11 @@ public:
|
||||
//! \brief ethernet parameters
|
||||
int parameters;
|
||||
|
||||
//! \brief read timeout, default 1000 ms
|
||||
double readTimeout;
|
||||
//! \brief read timeout, default 10 s
|
||||
PISystemTime readTimeout;
|
||||
|
||||
//! \brief write timeout, default 1000 ms
|
||||
double writeTimeout;
|
||||
//! \brief write timeout, default 10 s
|
||||
PISystemTime writeTimeout;
|
||||
|
||||
//! \brief time-to-live, default 64
|
||||
int TTL;
|
||||
@@ -475,7 +475,7 @@ protected:
|
||||
bool closeDevice() override;
|
||||
void closeSocket(int & sd);
|
||||
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);
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
#include "piiodevice.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "piconnection.h"
|
||||
#include "piliterals.h"
|
||||
#include "piliterals_bytes.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
//! \class PIIODevice piiodevice.h
|
||||
@@ -158,9 +160,9 @@ void PIIODevice::setReopenEnabled(bool yes) {
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::setReopenTimeout(int msecs) {
|
||||
setProperty("reopenTimeout", msecs);
|
||||
reopen_timeout = msecs;
|
||||
void PIIODevice::setReopenTimeout(PISystemTime timeout) {
|
||||
setProperty("reopenTimeout", timeout);
|
||||
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;
|
||||
while (read_thread.isRunning()) {
|
||||
if (tm.elapsed_m() > timeout_ms) return false;
|
||||
if (tm_intr.elapsed_m() > 100.) {
|
||||
if (timeout.isNotNull()) {
|
||||
if (tm.elapsed() > timeout) return false;
|
||||
}
|
||||
if (tm_intr.elapsed() > 100_ms) {
|
||||
tm_intr.reset();
|
||||
interrupt();
|
||||
}
|
||||
@@ -266,8 +270,8 @@ void PIIODevice::terminateThreadedWrite() {
|
||||
}
|
||||
|
||||
|
||||
bool PIIODevice::waitThreadedWriteFinished(int timeout_ms) {
|
||||
return write_thread.waitForFinish(timeout_ms);
|
||||
bool PIIODevice::waitThreadedWriteFinished(PISystemTime timeout) {
|
||||
return write_thread.waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -290,10 +294,10 @@ void PIIODevice::stop() {
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::stopAndWait(int timeout_ms) {
|
||||
void PIIODevice::stopAndWait(PISystemTime timeout) {
|
||||
stop();
|
||||
waitThreadedReadFinished(timeout_ms);
|
||||
waitThreadedWriteFinished(timeout_ms);
|
||||
waitThreadedReadFinished(timeout);
|
||||
waitThreadedWriteFinished(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +331,7 @@ void PIIODevice::_init() {
|
||||
opened_ = false;
|
||||
setOptions(0);
|
||||
setReopenEnabled(true);
|
||||
setReopenTimeout(1000);
|
||||
setReopenTimeout(1_s);
|
||||
#ifdef MICRO_PIP
|
||||
threaded_read_buffer_size = 512;
|
||||
#else
|
||||
@@ -375,7 +379,7 @@ void PIIODevice::read_func() {
|
||||
piMSleep(10);
|
||||
bool ok = false;
|
||||
if (reopen_enabled) {
|
||||
if (reopen_tm.elapsed_m() >= reopen_timeout) {
|
||||
if (reopen_tm.elapsed() >= reopen_timeout) {
|
||||
reopen_tm.reset();
|
||||
ok = open();
|
||||
}
|
||||
@@ -394,14 +398,14 @@ void PIIODevice::read_func() {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIIODevice::readForTime(double timeout_ms) {
|
||||
PIByteArray PIIODevice::readForTime(PISystemTime timeout) {
|
||||
PIByteArray str;
|
||||
if (timeout_ms <= 0.) return str;
|
||||
if (timeout.isNull()) return str;
|
||||
ssize_t ret;
|
||||
uchar * td = new uchar[threaded_read_buffer_size];
|
||||
bool was_br = setOption(BlockingRead, false);
|
||||
tm.reset();
|
||||
while (tm.elapsed_m() < timeout_ms) {
|
||||
while (tm.elapsed() < timeout) {
|
||||
ret = read(td, threaded_read_buffer_size);
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
@@ -477,13 +481,13 @@ bool PIIODevice::configure(const PIString & config_file, const PIString & sectio
|
||||
if (ep != 0) {
|
||||
setReopenEnabled(ep->getValue("reopenEnabled", isReopenEnabled(), &ex).toBool());
|
||||
if (!ex) setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool());
|
||||
setReopenTimeout(ep->getValue("reopenTimeout", reopenTimeout(), &ex).toInt());
|
||||
if (!ex) setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()).toInt());
|
||||
setReopenTimeout(PISystemTime::fromMilliseconds(ep->getValue("reopenTimeout", reopenTimeout().toMilliseconds(), &ex).toInt()));
|
||||
if (!ex) setReopenTimeout(PISystemTime::fromMilliseconds(em.getValue("reopenTimeout", reopenTimeout().toMilliseconds()).toInt()));
|
||||
setThreadedReadBufferSize(ep->getValue("threadedReadBufferSize", int(threaded_read_buffer_size), &ex).toInt());
|
||||
if (!ex) setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt());
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
return configureDevice(&em, ep);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "piinit.h"
|
||||
#include "piqueue.h"
|
||||
#include "pitimer.h"
|
||||
#include "pithread.h"
|
||||
|
||||
/// TODO: написать документацию, тут ничего не понятно
|
||||
// function executed from threaded read, pass readedData, sizeOfData, ThreadedReadData
|
||||
@@ -201,21 +201,17 @@ public:
|
||||
//! \~russian Устанавливает возможность вызова \a open() при потоковом чтении на закрытом устройстве
|
||||
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
|
||||
//! \~russian Устанавливает задержку между вызовами \a open() если переоткрытие активно
|
||||
void setReopenTimeout(PISystemTime timeout) { setReopenTimeout(timeout.toMilliseconds()); }
|
||||
void setReopenTimeout(PISystemTime timeout);
|
||||
|
||||
//! \~english Returns reopen enable
|
||||
//! \~russian Возвращает активно ли переоткрытие
|
||||
bool isReopenEnabled() const { return property("reopenEnabled").toBool(); }
|
||||
|
||||
//! \~english Returns reopen timeout in milliseconds
|
||||
//! \~russian Возвращает задержку переоткрытия в миллисекундах
|
||||
int reopenTimeout() { return property("reopenTimeout").toInt(); }
|
||||
//! \~english Returns reopen timeout
|
||||
//! \~russian Возвращает задержку переоткрытия
|
||||
PISystemTime reopenTimeout() { return property("reopenTimeout").toSystemTime(); }
|
||||
|
||||
|
||||
//! \~english Set threaded read callback
|
||||
@@ -266,13 +262,9 @@ public:
|
||||
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
||||
void terminateThreadedRead();
|
||||
|
||||
//! \~english Wait for threaded read finish no longer than "timeout_ms" milliseconds.
|
||||
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд.
|
||||
bool waitThreadedReadFinished(int timeout_ms = -1);
|
||||
|
||||
//! \~english Wait for threaded read finish no longer than "timeout".
|
||||
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout".
|
||||
bool waitThreadedReadFinished(PISystemTime timeout) { return waitThreadedReadFinished(timeout.toMilliseconds()); }
|
||||
bool waitThreadedReadFinished(PISystemTime timeout = {});
|
||||
|
||||
|
||||
//! \~english Returns if threaded write is started
|
||||
@@ -294,13 +286,9 @@ public:
|
||||
//! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти!
|
||||
void terminateThreadedWrite();
|
||||
|
||||
//! \~english Wait for threaded write finish no longer than "timeout_ms" milliseconds.
|
||||
//! \~russian Ожидает завершения потоковой записи в течении не более "timeout_ms" миллисекунд.
|
||||
bool waitThreadedWriteFinished(int timeout_ms = -1);
|
||||
|
||||
//! \~english Wait for threaded write finish no longer than "timeout".
|
||||
//! \~russian Ожидает завершения потоковой записи в течении не более "timeout".
|
||||
bool waitThreadedWriteFinished(PISystemTime timeout) { return waitThreadedWriteFinished(timeout.toMilliseconds()); }
|
||||
bool waitThreadedWriteFinished(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Clear threaded write task queue
|
||||
//! \~russian Очищает очередь потоковой записи
|
||||
@@ -317,11 +305,7 @@ public:
|
||||
|
||||
//! \~english Stop both threaded read and threaded write and wait for finish.
|
||||
//! \~russian Останавливает потоковое чтение и запись и ожидает завершения.
|
||||
void stopAndWait(int timeout_ms = -1);
|
||||
|
||||
//! \~english Stop both threaded read and threaded write and wait for finish.
|
||||
//! \~russian Останавливает потоковое чтение и запись и ожидает завершения.
|
||||
void stopAndWait(PISystemTime timeout) { return stopAndWait(timeout.toMilliseconds()); }
|
||||
void stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Interrupt blocking operation.
|
||||
//! \~russian Прерывает блокирующую операцию.
|
||||
@@ -355,15 +339,9 @@ public:
|
||||
//! \~russian Пишет в устройство не более "max_size" байт из "data"
|
||||
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.
|
||||
//! \~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
|
||||
@@ -506,8 +484,8 @@ public:
|
||||
//! \~russian setReopenEnabled, по умолчанию "true"
|
||||
bool reopenEnabled;
|
||||
|
||||
//! \~english setReopenTimeout in milliseconds, default 1000
|
||||
//! \~russian setReopenTimeout в миллисекундах, по умолчанию 1000
|
||||
//! \~english setReopenTimeout, default 1_s
|
||||
//! \~russian setReopenTimeout, по умолчанию 1_s
|
||||
int reopenTimeout;
|
||||
|
||||
//! \~english setThreadedReadBufferSize in bytes, default 4096
|
||||
@@ -609,8 +587,9 @@ private:
|
||||
PIThread read_thread, write_thread;
|
||||
PIByteArray buffer_in, buffer_tr;
|
||||
PIQueue<PIPair<PIByteArray, ullong>> write_queue;
|
||||
PISystemTime reopen_timeout;
|
||||
ullong tri = 0;
|
||||
uint threaded_read_buffer_size, reopen_timeout = 1000;
|
||||
uint threaded_read_buffer_size;
|
||||
bool reopen_enabled = true, destroying = false;
|
||||
|
||||
static PIMutex nfp_mutex;
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "pidatatransfer.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#define _PIPEER_MSG_SIZE 4000
|
||||
#define _PIPEER_MSG_TTL 100
|
||||
@@ -85,7 +87,7 @@ PIPeer::PeerData::~PeerData() {
|
||||
dt_in.stop();
|
||||
dt_out.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 sl(send_mutex);
|
||||
changeName(n);
|
||||
setReopenTimeout(100);
|
||||
setReopenTimeout(100_ms);
|
||||
read_buffer_size = 128;
|
||||
self_info.dist = 0;
|
||||
self_info.time = PISystemTime::current();
|
||||
randomize();
|
||||
CONNECT2(void, void *, int, &sync_timer, tickEvent, this, timerEvent);
|
||||
CONNECT1(void, int, &sync_timer, tickEvent, this, timerEvent);
|
||||
prev_ifaces = PIEthernet::interfaces();
|
||||
no_timer = false;
|
||||
sync_timer.addDelimiter(5);
|
||||
@@ -199,9 +201,9 @@ PIPeer::~PIPeer() {
|
||||
stop();
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
sync_timer.stop();
|
||||
diag_s.stop();
|
||||
diag_d.stop();
|
||||
sync_timer.stopAndWait();
|
||||
diag_s.stopAndWait();
|
||||
diag_d.stopAndWait();
|
||||
PIMutexLocker ml(peers_mutex);
|
||||
piForeach(PeerInfo & p, peers)
|
||||
if (p._data) {
|
||||
@@ -212,15 +214,15 @@ PIPeer::~PIPeer() {
|
||||
destroyEths();
|
||||
piForeach(PIEthernet * i, eths_mcast) {
|
||||
if (!i) continue;
|
||||
i->stopThreadedRead();
|
||||
i->stopAndWait();
|
||||
}
|
||||
piForeach(PIEthernet * i, eths_bcast) {
|
||||
if (!i) continue;
|
||||
i->stopThreadedRead();
|
||||
i->stopAndWait();
|
||||
}
|
||||
eth_lo.stopThreadedRead();
|
||||
eth_tcp_srv.stopThreadedRead();
|
||||
eth_tcp_cli.stopThreadedRead();
|
||||
eth_lo.stopAndWait();
|
||||
eth_tcp_srv.stopAndWait();
|
||||
eth_tcp_cli.stopAndWait();
|
||||
sendSelfRemove();
|
||||
destroyMBcasts();
|
||||
eth_send.close();
|
||||
@@ -229,7 +231,7 @@ PIPeer::~PIPeer() {
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::timerEvent(void * data, int delim) {
|
||||
void PIPeer::timerEvent(int delim) {
|
||||
// piCoutObj << "timerEvent" << delim;
|
||||
if (no_timer) return;
|
||||
switch (delim) {
|
||||
@@ -362,46 +364,32 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
|
||||
|
||||
void PIPeer::destroyEths() {
|
||||
piForeach(PIEthernet * i, eths_traffic) {
|
||||
for (auto * i: eths_traffic) {
|
||||
if (!i) continue;
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->stopAndWait();
|
||||
i->close();
|
||||
delete i;
|
||||
i = 0;
|
||||
}
|
||||
eths_traffic.clear();
|
||||
piDeleteAllAndClear(eths_traffic);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::destroyMBcasts() {
|
||||
piForeach(PIEthernet * i, eths_mcast) {
|
||||
for (auto * i: eths_mcast) {
|
||||
if (!i) continue;
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->leaveMulticastGroup(_PIPEER_MULTICAST_IP);
|
||||
i->stopAndWait();
|
||||
i->close();
|
||||
delete i;
|
||||
i = 0;
|
||||
}
|
||||
eths_mcast.clear();
|
||||
piForeach(PIEthernet * i, eths_bcast) {
|
||||
for (auto * i: eths_bcast) {
|
||||
if (!i) continue;
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->stopAndWait();
|
||||
i->close();
|
||||
delete i;
|
||||
i = 0;
|
||||
}
|
||||
eths_bcast.clear();
|
||||
((PIThread *)ð_lo)->stop();
|
||||
((PIThread *)ð_lo)->waitForFinish(100);
|
||||
eth_lo.stopThreadedRead();
|
||||
piDeleteAllAndClear(eths_mcast);
|
||||
piDeleteAllAndClear(eths_bcast);
|
||||
eth_lo.stopAndWait();
|
||||
eth_lo.close();
|
||||
eth_tcp_srv.stop();
|
||||
eth_tcp_srv.stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
@@ -918,7 +906,7 @@ void PIPeer::reinit() {
|
||||
initNetwork();
|
||||
sendSelfInfo();
|
||||
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);
|
||||
|
||||
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(void, dtReceived, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT_HANDLER1(void, newTcpClient, PIEthernet *, client);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "pidir.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
#include "piwaitevent_p.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pibasetransfer.h"
|
||||
|
||||
#include "pitime.h"
|
||||
|
||||
const uint PIBaseTransfer::signature = 0x54424950;
|
||||
|
||||
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||
@@ -33,7 +35,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||
send_queue = 0;
|
||||
send_up = 0;
|
||||
timeout_ = 10.;
|
||||
diag.setDisconnectTimeout(timeout_ / 10);
|
||||
diag.setDisconnectTimeout(PISystemTime::fromSeconds(timeout_ / 10.));
|
||||
diag.setName("PIBaseTransfer");
|
||||
diag.start(50);
|
||||
packets_count = 10;
|
||||
@@ -47,7 +49,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||
|
||||
|
||||
PIBaseTransfer::~PIBaseTransfer() {
|
||||
diag.stop();
|
||||
diag.stopAndWait();
|
||||
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) {
|
||||
packet_header_size = sizeof(PacketHeader) + customHeader().size();
|
||||
if (data.size() < sizeof(PacketHeader)) {
|
||||
|
||||
@@ -65,10 +65,7 @@ public:
|
||||
void setPacketSize(int size) { packet_size = size; }
|
||||
int packetSize() const { return packet_size; }
|
||||
|
||||
void setTimeout(double sec) {
|
||||
timeout_ = sec;
|
||||
diag.setDisconnectTimeout(sec);
|
||||
}
|
||||
void setTimeout(double sec);
|
||||
double timeout() const { return timeout_; }
|
||||
|
||||
void setCRCEnabled(bool en = true) { crc_enabled = en; }
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "piiostream.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
|
||||
/** \class PIConnection
|
||||
* \brief Complex Input/Output point
|
||||
@@ -160,7 +162,9 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
PIConfig::Entry de = ce.getValue("device." + n);
|
||||
dev->setThreadedReadBufferSize(de.getValue("bufferSize", dev->threadedReadBufferSize()).toInt());
|
||||
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);
|
||||
bool pdebug = debug();
|
||||
@@ -223,9 +227,11 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
}
|
||||
}
|
||||
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->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->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 << ".bufferSize = " << d->threadedReadBufferSize() << " #n\n";
|
||||
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();
|
||||
@@ -285,7 +291,7 @@ PIString PIConnection::makeConfig() const {
|
||||
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
||||
}
|
||||
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 = ";
|
||||
switch (ite.value()->extractor->splitMode()) {
|
||||
case PIPacketExtractor::None: ts << "none"; break;
|
||||
@@ -297,7 +303,7 @@ PIString PIConnection::makeConfig() const {
|
||||
}
|
||||
ts << " #s\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 << ".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]);
|
||||
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
||||
}
|
||||
double int_ = its.value()->int_;
|
||||
if (int_ > 0.) ts << prefix << ".frequency = " << (1000. / int_) << " #f\n";
|
||||
auto int_ = its.value()->int_;
|
||||
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";
|
||||
}
|
||||
ts << "[]\n";
|
||||
@@ -342,7 +348,7 @@ PIIODevice * PIConnection::addDevice(const PIString & full_path, PIIODevice::Dev
|
||||
__device_pool__->lock();
|
||||
if (!diags_.value(dev, nullptr)) {
|
||||
PIDiagnostics * d = new PIDiagnostics(false);
|
||||
d->setInterval(100.);
|
||||
d->setInterval(10_Hz);
|
||||
diags_[dev] = d;
|
||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||
__device_pool__->init();
|
||||
@@ -476,7 +482,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
||||
__device_pool__->lock();
|
||||
if (!diags_.value(e->extractor, nullptr)) {
|
||||
PIDiagnostics * d = new PIDiagnostics(false);
|
||||
d->setInterval(100.);
|
||||
d->setInterval(10_Hz);
|
||||
diags_[e->extractor] = d;
|
||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||
}
|
||||
@@ -514,7 +520,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
|
||||
__device_pool__->lock();
|
||||
if (diags_.value(e->extractor, 0) == 0) {
|
||||
PIDiagnostics * d = new PIDiagnostics(false);
|
||||
d->setInterval(100.);
|
||||
d->setInterval(10_Hz);
|
||||
diags_[e->extractor] = d;
|
||||
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) {
|
||||
s = new Sender(this);
|
||||
s->setName(fname_);
|
||||
s->int_ = 1000. / frequency;
|
||||
s->int_ = PISystemTime::fromSeconds(1. / frequency);
|
||||
senders[fname_] = s;
|
||||
}
|
||||
PIIODevice * dev = devByString(full_path_name);
|
||||
@@ -797,9 +803,9 @@ PIByteArray PIConnection::senderFixedData(const PIString & name) const {
|
||||
float PIConnection::senderFrequency(const PIString & name) const {
|
||||
Sender * s = senders.value(name, nullptr);
|
||||
if (!s) return -1.f;
|
||||
double i = s->interval();
|
||||
if (i == 0.) return 0.f;
|
||||
return 1000. / s->interval();
|
||||
auto i = s->interval();
|
||||
if (i.isNull()) return 0.f;
|
||||
return 1. / s->interval().toSeconds();
|
||||
}
|
||||
|
||||
|
||||
@@ -865,14 +871,14 @@ void PIConnection::stopAllThreadedReads() {
|
||||
void PIConnection::stopSender(const PIString & name) {
|
||||
Sender * s = senders.value(name, nullptr);
|
||||
if (!s) return;
|
||||
if (s->isRunning()) s->stop();
|
||||
if (s->isRunning()) s->stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::stopAllSenders() {
|
||||
for (auto s = senders.begin(); s != senders.end(); s++) {
|
||||
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");
|
||||
needLockRun(true);
|
||||
fake = false;
|
||||
@@ -960,7 +966,7 @@ PIConnection::DevicePool::~DevicePool() {}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::init() {
|
||||
if (!isRunning()) start(100);
|
||||
if (!isRunning()) start(10_Hz);
|
||||
}
|
||||
|
||||
|
||||
@@ -1111,7 +1117,7 @@ PIConnection::DevicePool::DeviceData::~DeviceData() {
|
||||
if (rthread) {
|
||||
rthread->stop();
|
||||
if (dev) dev->interrupt();
|
||||
if (!rthread->waitForFinish(1000)) rthread->terminate();
|
||||
if (!rthread->waitForFinish(1_s)) rthread->terminate();
|
||||
delete rthread;
|
||||
rthread = nullptr;
|
||||
}
|
||||
@@ -1128,7 +1134,7 @@ void PIConnection::DevicePool::run() {
|
||||
for (PIConnection * c: conns) {
|
||||
for (auto d = c->diags_.begin(); d != c->diags_.end(); d++) {
|
||||
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->open()) {
|
||||
auto timeout = dev->reopenTimeout();
|
||||
PITimeMeasurer tm;
|
||||
int timeout = dev->reopenTimeout();
|
||||
while (tm.elapsed_m() < timeout) {
|
||||
while (tm.elapsed() < timeout) {
|
||||
if (dd->rthread->isStopping()) return;
|
||||
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");
|
||||
needLockRun(true);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::Sender::tick(void *, int) {
|
||||
void PIConnection::Sender::tick(int) {
|
||||
if (!parent) return;
|
||||
PIByteArray data;
|
||||
if (!sdata.isEmpty())
|
||||
|
||||
@@ -387,12 +387,12 @@ private:
|
||||
|
||||
public:
|
||||
Sender(PIConnection * parent_ = 0);
|
||||
~Sender() { stop(); }
|
||||
~Sender() { stopAndWait(); }
|
||||
PIConnection * parent;
|
||||
PIVector<PIIODevice *> devices;
|
||||
PIByteArray sdata;
|
||||
float int_;
|
||||
void tick(void *, int) override;
|
||||
PISystemTime int_;
|
||||
void tick(int) override;
|
||||
};
|
||||
|
||||
PIMap<PIString, Extractor *> extractors;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pidiagnostics.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
|
||||
|
||||
/** \class PIDiagnostics
|
||||
* \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";
|
||||
setInterval(100);
|
||||
setInterval(10_Hz);
|
||||
reset();
|
||||
setDisconnectTimeout(3.);
|
||||
changeDisconnectTimeout(3.);
|
||||
if (start_) PITimer::start(100);
|
||||
setDisconnectTimeout(3_s);
|
||||
changeDisconnectTimeout(3_s);
|
||||
if (start_) PITimer::start(10_Hz);
|
||||
// piCout << "PIDiagnostics construct done";
|
||||
}
|
||||
|
||||
PIDiagnostics::~PIDiagnostics() {
|
||||
PITimer::stop();
|
||||
PITimer::stopAndWait();
|
||||
// piCout << "~PIDiagnostics start...";
|
||||
// piCout << "~PIDiagnostics done!";
|
||||
}
|
||||
@@ -92,14 +94,14 @@ PIString PIDiagnostics::sendSpeed() const {
|
||||
|
||||
|
||||
void PIDiagnostics::start() {
|
||||
PITimer::start(100.);
|
||||
PITimer::start(10_Hz);
|
||||
changeDisconnectTimeout(disconn_);
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::start(double msecs) {
|
||||
if (msecs > 0.) {
|
||||
PITimer::start(msecs);
|
||||
PITimer::start(PISystemTime::fromMilliseconds(msecs));
|
||||
changeDisconnectTimeout(disconn_);
|
||||
}
|
||||
}
|
||||
@@ -108,7 +110,7 @@ void PIDiagnostics::start(double msecs) {
|
||||
void PIDiagnostics::reset() {
|
||||
mutex_state.lock();
|
||||
cur_state = State();
|
||||
if (disconn_ != 0.) {
|
||||
if (disconn_.isNotNull()) {
|
||||
int hist_size = history_rec.size();
|
||||
history_rec.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();
|
||||
// piCoutObj << "lock";
|
||||
int tcnt_recv = 0;
|
||||
int tcnt_send = 0;
|
||||
Entry send = calcHistory(history_send, tcnt_send);
|
||||
Entry recv = calcHistory(history_rec, tcnt_recv);
|
||||
float itr = disconn_ * (float(tcnt_recv) / history_rec.size());
|
||||
float its = disconn_ * (float(tcnt_send) / history_send.size());
|
||||
float hz = interval() / 1000.f;
|
||||
float itr = disconn_.toSeconds() * (float(tcnt_recv) / history_rec.size());
|
||||
float its = disconn_.toSeconds() * (float(tcnt_send) / history_send.size());
|
||||
float hz = 1. / interval().toSeconds();
|
||||
if (tcnt_recv == 0) {
|
||||
cur_state.integral_freq = cur_state.immediate_freq = 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 *) {
|
||||
float disct = property("disconnectTimeout").toFloat();
|
||||
changeDisconnectTimeout(disct);
|
||||
changeDisconnectTimeout(property("disconnectTimeout").toSystemTime());
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::changeDisconnectTimeout(float disct) {
|
||||
void PIDiagnostics::changeDisconnectTimeout(PISystemTime disct) {
|
||||
mutex_state.lock();
|
||||
disconn_ = piMaxf(disct, interval() / 1000.f);
|
||||
if (interval() > 0) {
|
||||
int hist_size = piClampi(int(disconn_ * 1000.f / float(interval())), 1, 65536);
|
||||
disconn_ = piMax(disct, interval());
|
||||
if (!interval().isNull()) {
|
||||
int hist_size = piClampi(piRound(disconn_.toSeconds() / interval().toSeconds()), 1, 65536);
|
||||
// piCoutObj << hist_size << interval();
|
||||
history_rec.resize(hist_size);
|
||||
history_send.resize(hist_size);
|
||||
|
||||
@@ -75,13 +75,15 @@ public:
|
||||
PIDiagnostics::State state() const;
|
||||
|
||||
//! 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
|
||||
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
|
||||
void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm.toSeconds()); }
|
||||
void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm); }
|
||||
|
||||
//! Returns connection quality
|
||||
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);
|
||||
|
||||
void tick(void *, int) override;
|
||||
void tick(int) override;
|
||||
Entry calcHistory(PIQueue<Entry> & hist, int & cnt);
|
||||
void propertyChanged(const char *) override;
|
||||
void changeDisconnectTimeout(float disct);
|
||||
void changeDisconnectTimeout(PISystemTime disct);
|
||||
|
||||
PIQueue<Entry> history_rec, history_send;
|
||||
float disconn_ = 0.f;
|
||||
PISystemTime disconn_;
|
||||
State cur_state;
|
||||
mutable PIMutex mutex_state;
|
||||
};
|
||||
|
||||
@@ -97,7 +97,7 @@ void PIPacketExtractor::construct() {
|
||||
func_footer = nullptr;
|
||||
func_payload = nullptr;
|
||||
setPayloadSize(0);
|
||||
setTimeout(100);
|
||||
setTimeout(100_ms);
|
||||
#ifdef MICRO_PIP
|
||||
setThreadedReadBufferSize(512);
|
||||
#else
|
||||
@@ -115,7 +115,7 @@ void PIPacketExtractor::propertyChanged(const char *) {
|
||||
dataSize = property("payloadSize").toInt();
|
||||
src_header = property("header").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() */,
|
||||
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */,
|
||||
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"
|
||||
@@ -87,8 +87,8 @@ public:
|
||||
//! Set footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
void setFooter(const PIByteArray & data);
|
||||
|
||||
//! Set timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||
void setTimeout(double msecs) { setProperty("timeout", msecs); }
|
||||
//! Set timeout, used for PIPacketExtractor::Timeout algorithm
|
||||
void setTimeout(PISystemTime tm) { setProperty("timeout", tm); }
|
||||
|
||||
|
||||
//! Returns current extract algorithm
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
PIByteArray footer() const { return src_footer; }
|
||||
|
||||
//! 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
|
||||
ullong missedBytes() const { return missed; }
|
||||
@@ -165,7 +165,7 @@ private:
|
||||
PacketExtractorFooterFunc func_footer;
|
||||
SplitMode mode_;
|
||||
int dataSize, packetSize_pending, footerInd;
|
||||
double time_;
|
||||
PISystemTime time_;
|
||||
bool header_found;
|
||||
ullong missed;
|
||||
};
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
#include "pigeomodule.h"
|
||||
#include "piiodevicesmodule.h"
|
||||
#include "piioutilsmodule.h"
|
||||
#include "piliterals.h"
|
||||
#include "pimathmodule.h"
|
||||
#include "pistatemachinemodule.h"
|
||||
#include "pisystemmodule.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/>.
|
||||
*/
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#ifndef MICRO_PIP
|
||||
|
||||
# include "piprocess.h"
|
||||
|
||||
# include "piincludes_p.h"
|
||||
# include "piprocess.h"
|
||||
# ifndef WINDOWS
|
||||
# include <csignal>
|
||||
# include <sys/wait.h>
|
||||
@@ -88,6 +89,7 @@ PIProcess::PIProcess(): PIThread() {
|
||||
|
||||
|
||||
PIProcess::~PIProcess() {
|
||||
PIThread::stopAndWait();
|
||||
if (t_in) f_in.remove();
|
||||
if (t_out) f_out.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_) {
|
||||
PIProcess p;
|
||||
p.args << program << args_;
|
||||
|
||||
@@ -147,8 +147,8 @@ public:
|
||||
exec_();
|
||||
}
|
||||
EVENT_HANDLER(void, terminate);
|
||||
EVENT_HANDLER(bool, waitForFinish) { return waitForFinish(60000); }
|
||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) { return PIThread::waitForFinish(timeout_msecs); }
|
||||
EVENT_HANDLER(bool, waitForFinish);
|
||||
EVENT_HANDLER1(bool, waitForFinish, PISystemTime, timeout) { return PIThread::waitForFinish(timeout); }
|
||||
|
||||
EVENT1(execStarted, PIString, program);
|
||||
EVENT2(execFinished, PIString, program, int, exit_code);
|
||||
@@ -202,9 +202,9 @@ public:
|
||||
//! \~english Wait for attached execution finish maximum for 60 seconds
|
||||
//! \~russian
|
||||
|
||||
//! \fn bool waitForFinish(int timeout_msecs)
|
||||
//! \fn bool waitForFinish(PISystemTime timeout)
|
||||
//! \brief
|
||||
//! \~english Wait for attached execution finish maximum for "timeout_msecs" milliseconds
|
||||
//! \~english Wait for attached execution finish maximum for "timeout_"
|
||||
//! \~russian
|
||||
|
||||
//! \}
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
#include "pisingleapplication.h"
|
||||
|
||||
#include "piliterals.h"
|
||||
#include "piliterals_bytes.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pisharedmemory.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
//! \class PISingleApplication pisingleapplication.h
|
||||
@@ -70,7 +72,7 @@ PISingleApplication::PISingleApplication(const PIString & app_name): PIThread()
|
||||
started = false;
|
||||
sacnt = 0;
|
||||
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
|
||||
start(100);
|
||||
start(10_Hz);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ PISystemMonitor::~PISystemMonitor() {
|
||||
|
||||
|
||||
#ifndef MICRO_PIP
|
||||
bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
|
||||
bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
|
||||
stop();
|
||||
pID_ = pID;
|
||||
Pool::instance()->add(this);
|
||||
@@ -118,17 +118,17 @@ bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
|
||||
}
|
||||
PRIVATE->tm.reset();
|
||||
# endif
|
||||
return start(interval_ms);
|
||||
return start(interval);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool PISystemMonitor::startOnSelf(int interval_ms) {
|
||||
bool PISystemMonitor::startOnSelf(PISystemTime interval) {
|
||||
#ifndef MICRO_PIP
|
||||
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms);
|
||||
bool ret = startOnProcess(PIProcess::currentPID(), interval);
|
||||
cycle = -1;
|
||||
#else
|
||||
bool ret = start(interval_ms);
|
||||
bool ret = start(interval);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
@@ -190,7 +190,8 @@ void PISystemMonitor::run() {
|
||||
if (t->isPIObject()) gatherThread(t->tid());
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
tbid[pID_] = "main";
|
||||
double delay_ms = delay_.toMilliseconds();
|
||||
tbid[pID_] = "main";
|
||||
# ifdef MAC_OS
|
||||
rusage_info_current 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_u_cur = uint64toST(ru.ri_user_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_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_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_ms;
|
||||
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
|
||||
PRIVATE->file.seekToBegin();
|
||||
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_u_cur = sl[12].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_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_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_ms / 1000.);
|
||||
tstat.cpu_load_system /= cpu_count;
|
||||
tstat.cpu_load_user /= cpu_count;
|
||||
cycle = 0;
|
||||
@@ -394,8 +395,8 @@ void PISystemMonitor::gatherThread(llong id) {
|
||||
|
||||
|
||||
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
|
||||
if (delay_ <= 0) return -1.;
|
||||
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f);
|
||||
if (delay_.isNull()) return -1.;
|
||||
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
|
||||
//! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд
|
||||
bool startOnProcess(int pID, int interval_ms = 1000);
|
||||
bool startOnProcess(int pID, PISystemTime interval = PISystemTime::fromSeconds(1.));
|
||||
#endif
|
||||
|
||||
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
|
||||
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
|
||||
bool startOnSelf(int interval_ms = 1000);
|
||||
bool startOnSelf(PISystemTime interval = PISystemTime::fromSeconds(1.));
|
||||
|
||||
//! \~english Stop monitoring
|
||||
//! \~russian Останавливает мониторинг
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#define PIBLOCKINGQUEUE_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
|
||||
@@ -96,16 +96,16 @@ public:
|
||||
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
bool offer(const T & v, int timeoutMs = 0) {
|
||||
bool offer(const T & v, PISystemTime timeout = {}) {
|
||||
bool isOk;
|
||||
mutex.lock();
|
||||
if (timeoutMs == 0)
|
||||
if (timeout.isNull())
|
||||
isOk = PIDeque<T>::size() < max_size;
|
||||
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);
|
||||
mutex.unlock();
|
||||
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
|
||||
* 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 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 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;
|
||||
bool isNotEmpty;
|
||||
mutex.lock();
|
||||
if (timeoutMs == 0)
|
||||
if (timeout.isNull())
|
||||
isNotEmpty = !PIDeque<T>::isEmpty();
|
||||
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();
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
#ifdef WINDOWS
|
||||
# include <synchapi.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;
|
||||
#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)
|
||||
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
|
||||
isNotTimeout = (uxBits & 1) != 0;
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeout.toMilliseconds() / portTICK_PERIOD_MS);
|
||||
isNotTimeout = (uxBits & 1) != 0;
|
||||
#else
|
||||
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||
timespec expire_ts;
|
||||
PISystemTime st = PISystemTime::current(true);
|
||||
st.addMilliseconds(timeoutMs);
|
||||
st.toTimespec(&expire_ts);
|
||||
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0;
|
||||
#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;
|
||||
#if defined(WINDOWS) || defined(FREERTOS)
|
||||
PITimeMeasurer measurer;
|
||||
#else
|
||||
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||
timespec expire_ts;
|
||||
PISystemTime st = PISystemTime::current(true);
|
||||
st.addMilliseconds(timeoutMs);
|
||||
st.toTimespec(&expire_ts);
|
||||
#endif
|
||||
#ifdef FREERTOS
|
||||
@@ -143,12 +139,16 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::functi
|
||||
if (isCondition) break;
|
||||
bool isTimeout;
|
||||
#if defined(WINDOWS)
|
||||
isTimeout =
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0;
|
||||
isTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle,
|
||||
(PCRITICAL_SECTION)lk.handle(),
|
||||
timeout.toMilliseconds() - (int)measurer.elapsed_m()) == 0;
|
||||
#elif defined(FREERTOS)
|
||||
EventBits_t uxBits;
|
||||
uxBits =
|
||||
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle,
|
||||
1,
|
||||
pdTRUE,
|
||||
pdTRUE,
|
||||
(timeout.toMilliseconds() - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
||||
isTimeout = (uxBits & 1) == 0;
|
||||
#else
|
||||
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0;
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#ifndef 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()>&)
|
||||
*/
|
||||
virtual bool waitFor(PIMutex & lk, int timeoutMs);
|
||||
virtual bool waitFor(PIMutex & lk, PISystemTime timeout);
|
||||
|
||||
/**
|
||||
* \brief Wait for timeout or until notified
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
* @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_DECLARATION(PIP_EXPORT)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "pidiagnostics.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
template<typename T = PIByteArray>
|
||||
|
||||
@@ -535,33 +535,33 @@ PRIVATE_DEFINITION_START(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);
|
||||
data_ = data;
|
||||
ret_func = func;
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
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);
|
||||
ret_func = [func](void *) { func(); };
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
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);
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
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) << pthread_join(PRIVATE->thread, 0);
|
||||
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
|
||||
stop(true);
|
||||
stopAndWait();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
@@ -591,15 +591,47 @@ PIThread::~PIThread() {
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(ThreadFunc func, int loop_delay) {
|
||||
ret_func = func;
|
||||
return start(loop_delay);
|
||||
bool PIThread::start() {
|
||||
if (running_) return false;
|
||||
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(); };
|
||||
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();
|
||||
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() {
|
||||
piCoutObj << "Warning, terminate!";
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
|
||||
@@ -766,7 +791,7 @@ void PIThread::setPriority(PIThread::Priority prior) {
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
|
||||
policy_ = 0;
|
||||
int policy_ = 0;
|
||||
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
|
||||
pthread_getschedparam(PRIVATE->thread, &policy_, &(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
|
||||
bool isExists(HANDLE hThread) {
|
||||
// errorClear();
|
||||
@@ -808,11 +823,12 @@ bool isExists(HANDLE hThread) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
|
||||
bool PIThread::waitForFinish(PISystemTime timeout) {
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
|
||||
// timeout_msecs;
|
||||
if (!running_) return true;
|
||||
if (timeout_msecs < 0) {
|
||||
if (timeout.isNull()) {
|
||||
while (running_) {
|
||||
piMinSleep();
|
||||
#ifdef WINDOWS
|
||||
@@ -825,7 +841,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
return true;
|
||||
}
|
||||
tmf_.reset();
|
||||
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
|
||||
while (running_ && tmf_.elapsed() < timeout) {
|
||||
piMinSleep();
|
||||
#ifdef WINDOWS
|
||||
if (!isExists(PRIVATE->thread)) {
|
||||
@@ -834,21 +850,21 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
}
|
||||
#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 (timeout_msecs < 0) {
|
||||
if (timeout.isNull()) {
|
||||
while (!running_)
|
||||
piMinSleep();
|
||||
return true;
|
||||
}
|
||||
tms_.reset();
|
||||
while (!running_ && tms_.elapsed_m() < timeout_msecs)
|
||||
while (!running_ && tms_.elapsed() < timeout)
|
||||
piMinSleep();
|
||||
return tms_.elapsed_m() < timeout_msecs;
|
||||
return tms_.elapsed() < timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -940,11 +956,11 @@ void PIThread::__thread_func__() {
|
||||
_runThread();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
|
||||
PIINTROSPECTION_THREAD_WAIT(this);
|
||||
if (delay_ > 0) {
|
||||
if (delay_.isNotNull()) {
|
||||
tmr_.reset();
|
||||
double sl(0.);
|
||||
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 (sl <= 0.) break;
|
||||
piMSleep(sl);
|
||||
|
||||
@@ -79,15 +79,15 @@ public:
|
||||
|
||||
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "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"
|
||||
//! \~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"
|
||||
//! \~russian Создает поток с задержкой цикла "loop_delay"
|
||||
PIThread(bool startNow = false, int loop_delay = -1);
|
||||
PIThread(bool startNow = false, PISystemTime loop_delay = {});
|
||||
|
||||
virtual ~PIThread();
|
||||
|
||||
@@ -103,27 +103,55 @@ public:
|
||||
piHighest /** \~english Highest \~russian Высший */
|
||||
};
|
||||
|
||||
EVENT_HANDLER0(bool, start) { return start(-1); }
|
||||
EVENT_HANDLER1(bool, start, int, loop_delay);
|
||||
bool start(PISystemTime loop_delay) { return start(loop_delay.toMilliseconds()); }
|
||||
bool start(ThreadFunc func) { return start(func, -1); }
|
||||
bool start(ThreadFunc func, int loop_delay);
|
||||
bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
||||
bool start(std::function<void()> func) { return start(func, -1); }
|
||||
bool start(std::function<void()> func, int loop_delay);
|
||||
bool start(std::function<void()> func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
||||
EVENT_HANDLER0(bool, startOnce);
|
||||
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start();
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(PISystemTime loop_delay);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~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, terminate);
|
||||
|
||||
//! \~english Stop thread and wait for finish.
|
||||
//! \~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.
|
||||
//! \~russian Останавливает поток и ожидает завершения.
|
||||
void stopAndWait(PISystemTime timeout) { stopAndWait(timeout.toMilliseconds()); }
|
||||
void stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Set common data passed to external function
|
||||
//! \~russian Устанавливает данные, передаваемые в функцию потока
|
||||
@@ -159,12 +187,19 @@ public:
|
||||
//! \~russian Возвращает останавливается ли поток
|
||||
bool isStopping() const { return running_ && terminating; }
|
||||
|
||||
EVENT_HANDLER0(bool, waitForStart) { return waitForStart(-1); }
|
||||
EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs);
|
||||
bool waitForStart(PISystemTime timeout);
|
||||
EVENT_HANDLER0(bool, waitForFinish) { return waitForFinish(-1); }
|
||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
|
||||
bool waitForFinish(PISystemTime timeout);
|
||||
//! \~english Wait for thread start
|
||||
//! \~russian Ожидает старта потока
|
||||
bool waitForStart(PISystemTime timeout = {});
|
||||
bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") {
|
||||
return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs));
|
||||
}
|
||||
|
||||
//! \~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
|
||||
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
|
||||
@@ -198,21 +233,6 @@ public:
|
||||
//! \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()
|
||||
//! \brief
|
||||
//! \~english Stop thread
|
||||
@@ -223,16 +243,6 @@ public:
|
||||
//! \~english Strongly stop thread
|
||||
//! \~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()
|
||||
//! \brief
|
||||
//! \~english Lock internal mutex
|
||||
@@ -275,7 +285,7 @@ protected:
|
||||
virtual void end() { ; }
|
||||
|
||||
std::atomic_bool terminating, running_, lockRun;
|
||||
int delay_, policy_;
|
||||
PISystemTime delay_;
|
||||
llong tid_ = -1;
|
||||
void * data_ = nullptr;
|
||||
mutable PIMutex thread_mutex;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pithreadpoolexecutor.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
|
||||
/*! \class PIThreadPoolExecutor
|
||||
* \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
|
||||
@@ -29,7 +31,7 @@
|
||||
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) {
|
||||
for (int i = 0; i < corePoolSize; ++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) {
|
||||
runnable();
|
||||
}
|
||||
@@ -41,11 +43,11 @@ PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false)
|
||||
}
|
||||
|
||||
|
||||
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
|
||||
bool PIThreadPoolExecutor::awaitTermination(PISystemTime timeout) {
|
||||
PITimeMeasurer measurer;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) {
|
||||
int dif = timeoutMs - (int)measurer.elapsed_m();
|
||||
if (dif < 0) return false;
|
||||
auto dif = timeout - measurer.elapsed();
|
||||
if (dif.isNegative()) return false;
|
||||
if (!threadPool[i]->waitForFinish(dif)) return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define PITHREADPOOLEXECUTOR_H
|
||||
|
||||
#include "piblockingqueue.h"
|
||||
#include "pithread.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -47,7 +48,7 @@ public:
|
||||
|
||||
bool isShutdown() const;
|
||||
|
||||
bool awaitTermination(int timeoutMs);
|
||||
bool awaitTermination(PISystemTime timeout);
|
||||
|
||||
private:
|
||||
std::atomic_bool isShutdown_;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "pithreadpoolloop.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pithread.h"
|
||||
|
||||
@@ -115,7 +116,7 @@ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
|
||||
PIThreadPoolLoop::~PIThreadPoolLoop() {
|
||||
for (auto * t: threads) {
|
||||
t->stop();
|
||||
if (!t->waitForFinish(100)) t->terminate();
|
||||
if (!t->waitForFinish(100_ms)) t->terminate();
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
#include "pitimer.h"
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals.h"
|
||||
#ifdef PIP_TIMER_RT
|
||||
# include <csignal>
|
||||
#endif
|
||||
#include "piliterals_time.h"
|
||||
#include "pithread.h"
|
||||
|
||||
|
||||
//! \addtogroup Thread
|
||||
@@ -52,22 +49,22 @@
|
||||
//! \~russian \section PITimer_sec1 Варианты уведомления
|
||||
//! \~english
|
||||
//! 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);
|
||||
//! * event - \a tickEvent();
|
||||
//! * virtual function - \a tick().
|
||||
//!
|
||||
//! Lambda should be [ ]( ){ } or [ ](void*){ } format.
|
||||
//! Lambda should be [ ]( ){ } or [ ](int){ } format.
|
||||
//!
|
||||
//! All these variants are equivalent, use most applicable.
|
||||
//! \~russian
|
||||
//! Варианты уведомления:
|
||||
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или
|
||||
//! * "slot" - статический метод в формате void func(int delimiter) или
|
||||
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
|
||||
//! * event - \a tickEvent();
|
||||
//! * виртуальный метод - \a tick().
|
||||
//!
|
||||
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](void*){ }.
|
||||
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](int){ }.
|
||||
//!
|
||||
//! Все варианты аналогичны друг другу, используйте самый удобный.
|
||||
//!
|
||||
@@ -89,10 +86,10 @@
|
||||
//! Пример:
|
||||
//!
|
||||
//! \~\code
|
||||
//! void tfunc(void * , int delim) {
|
||||
//! void tfunc(int delim) {
|
||||
//! piCout << "tick with delimiter" << delim;
|
||||
//! };
|
||||
//! void tfunc4(void * , int delim) {
|
||||
//! void tfunc4(int delim) {
|
||||
//! piCout << "tick4 with delimiter" << delim;
|
||||
//! };
|
||||
//! int main() {
|
||||
@@ -101,8 +98,7 @@
|
||||
//! timer.addDelimiter(4, tfunc4);
|
||||
//! timer.start(50);
|
||||
//! piMSleep(200);
|
||||
//! timer.stop();
|
||||
//! timer.waitForFinish();
|
||||
//! timer.stopAndWait();
|
||||
//! return 0;
|
||||
//! };
|
||||
//! /* Result:
|
||||
@@ -119,596 +115,163 @@
|
||||
//! \}
|
||||
|
||||
|
||||
_PITimerBase::_PITimerBase() {
|
||||
running_ = false;
|
||||
PITimer::PITimer(): PIObject() {
|
||||
initFirst();
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::setInterval(double i) {
|
||||
interval_ = i;
|
||||
PITimer::PITimer(std::function<void(int)> func) {
|
||||
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()) {
|
||||
// piCout << "change interval runtime";
|
||||
stop();
|
||||
stopAndWait();
|
||||
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 {
|
||||
init();
|
||||
return imp->running_;
|
||||
return thread->isRunning();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::isStopped() const {
|
||||
init();
|
||||
return !imp->running_;
|
||||
bool PITimer::isStopping() const {
|
||||
return thread->isStopping();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::waitForFinish(PISystemTime timeout) {
|
||||
return thread->waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
void PITimer::initFirst() {
|
||||
lockRun = false;
|
||||
callEvents = true;
|
||||
setProperty("interval", 0.);
|
||||
thread = new PIThread([this] { threadFunc(); });
|
||||
thread->setName("__S__.PITimer.thread");
|
||||
setProperty("interval", PISystemTime());
|
||||
}
|
||||
|
||||
|
||||
void PITimer::init() const {
|
||||
if (imp) return;
|
||||
switch (imp_mode) {
|
||||
case PITimer::Pool: imp = new _PITimerImp_Pool(); break;
|
||||
case PITimer::ThreadRT:
|
||||
#ifdef PIP_TIMER_RT
|
||||
imp = new _PITimerImp_RT();
|
||||
break;
|
||||
#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);
|
||||
void PITimer::threadFunc() {
|
||||
PISystemTime st_wait = m_time_next - PISystemTime::current(true);
|
||||
// piCout << "wait" << this << st_wait;
|
||||
if (st_wait.abs() > m_interval_x5 || st_wait.seconds <= -5) {
|
||||
// piCout << &thread_ << "adjust" << "...";
|
||||
adjustTimes();
|
||||
// piCout << &thread_ << "adjust" << "ok";
|
||||
return;
|
||||
}
|
||||
if (!imp) return;
|
||||
// piCout << this << "init" << imp;
|
||||
imp->tfunc = tickImpS;
|
||||
imp->parent = const_cast<PITimer *>(this);
|
||||
if (thread->isStopping()) return;
|
||||
if (st_wait.isPositive()) {
|
||||
thread->mutex().lock();
|
||||
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() {
|
||||
if (!imp) return;
|
||||
// piCout << this << "destroy" << imp;
|
||||
imp->stop();
|
||||
delete imp;
|
||||
imp = 0;
|
||||
void PITimer::adjustTimes() {
|
||||
PISystemTime cst = PISystemTime::current(true);
|
||||
if (m_time_next < cst) {
|
||||
int rs = (cst - m_time_next).toSeconds() / m_interval.toSeconds();
|
||||
if (rs >= 100)
|
||||
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 (lockRun) lock();
|
||||
if (ret_func) ret_func(data_t, 1);
|
||||
tick(data_t, 1);
|
||||
tickEvent(data_t, 1);
|
||||
if (ret_func) ret_func(1);
|
||||
tick(1);
|
||||
tickEvent(1);
|
||||
if (callEvents) maybeCallQueuedEvents();
|
||||
piForeach(Delimiter & i, delims) {
|
||||
for (Delimiter & i: delims) {
|
||||
if (i.delim > ++(i.tick)) continue;
|
||||
i.tick = 0;
|
||||
if (i.slot)
|
||||
i.slot(data_t, i.delim);
|
||||
if (i.func)
|
||||
i.func(i.delim);
|
||||
else if (ret_func)
|
||||
ret_func(data_t, i.delim);
|
||||
tick(data_t, i.delim);
|
||||
tickEvent(data_t, i.delim);
|
||||
ret_func(i.delim);
|
||||
tick(i.delim);
|
||||
tickEvent(i.delim);
|
||||
}
|
||||
if (lockRun) unlock();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::start() {
|
||||
init();
|
||||
// piCout << this << "start" << imp;
|
||||
return imp->start();
|
||||
if (isRunning()) return true;
|
||||
m_interval_x5 = m_interval * 5;
|
||||
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) {
|
||||
init();
|
||||
// piCout << this << "start" << imp << interval_ms_d;
|
||||
setProperty("interval", interval_ms_d);
|
||||
return imp->start(interval_ms_d);
|
||||
bool PITimer::start(PISystemTime interval) {
|
||||
if (isRunning()) stopAndWait();
|
||||
setInterval(interval);
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::start(int interval_ms_i) {
|
||||
return start((double)interval_ms_i);
|
||||
void PITimer::stopAndWait(PISystemTime timeout) {
|
||||
stop();
|
||||
thread->waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! 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);
|
||||
void PITimer::addDelimiter(int delim, std::function<void(int)> func) {
|
||||
delims << Delimiter(func, delim);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! 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);
|
||||
void PITimer::addDelimiter(int delim, std::function<void()> func) {
|
||||
delims << Delimiter([func](int) { func(); }, delim);
|
||||
}
|
||||
|
||||
|
||||
@@ -722,14 +285,12 @@ void PITimer::removeDelimiter(int delim) {
|
||||
|
||||
|
||||
bool PITimer::restart() {
|
||||
init();
|
||||
imp->stop();
|
||||
return imp->start();
|
||||
stopAndWait();
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::stop() {
|
||||
init();
|
||||
// piCout << this << "stop" << imp << wait;
|
||||
return imp->stop();
|
||||
void PITimer::stop() {
|
||||
thread->stop();
|
||||
event.notifyAll();
|
||||
}
|
||||
|
||||
@@ -26,50 +26,12 @@
|
||||
#ifndef PITIMER_H
|
||||
#define PITIMER_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
#include "piconditionvar.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 {
|
||||
PIOBJECT_SUBCLASS(PITimer, PIObject);
|
||||
@@ -77,118 +39,70 @@ class PIP_EXPORT PITimer: public PIObject {
|
||||
public:
|
||||
NO_COPY_CLASS(PITimer);
|
||||
|
||||
//! \~english Constructs timer with PITimer::Thread implementation
|
||||
//! \~russian Создает таймер с реализацией PITimer::Thread
|
||||
//! \~english Constructs timer
|
||||
//! \~russian Создает таймер
|
||||
explicit PITimer();
|
||||
|
||||
//! \~english Timer implementations
|
||||
//! \~russian Реализация таймера
|
||||
enum TimerImplementation {
|
||||
Thread /*!
|
||||
\~english Timer works in his own thread. Intervals are measured by the system time
|
||||
\~russian Таймер работает в собственном потоке. Интервалы измеряются с помощью системного времени
|
||||
*/
|
||||
= 0x01,
|
||||
ThreadRT /*!
|
||||
\~english Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS!
|
||||
\~russian Использовать таймер POSIX с SIGEV_THREAD уведомлением. \attention Не поддерживается на Windows и Mac OS!
|
||||
*/
|
||||
= 0x02,
|
||||
Pool /*!
|
||||
\~english Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and
|
||||
sequentially executes all timers. \attention Use this implementation with care!
|
||||
\~russian Использовать единый TimerPool для всех таймеров с этой реализацией. TimerPool реализован через Thread и
|
||||
последовательно исполняет все таймеры. \attention Осторожнее с этой реализацией!
|
||||
*/
|
||||
= 0x04
|
||||
};
|
||||
//! \~english Constructs timer with method void(int)
|
||||
//! \~russian Создает таймер с функцией void(int)
|
||||
explicit PITimer(std::function<void(int)> func);
|
||||
|
||||
//! \~english Constructs timer with "ti" implementation
|
||||
//! \~russian Создает таймер с реализацией "ti"
|
||||
explicit PITimer(TimerImplementation ti);
|
||||
|
||||
//! \~english Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation
|
||||
//! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti"
|
||||
explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread);
|
||||
|
||||
//! \~english Constructs timer with "slot" slot void(), and "ti" implementation
|
||||
//! \~russian Создает таймер со слотом "slot" и реализацией "ti"
|
||||
explicit PITimer(std::function<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);
|
||||
//! \~english Constructs timer with method void()
|
||||
//! \~russian Создает таймер с функцией void()
|
||||
explicit PITimer(std::function<void()> func);
|
||||
|
||||
virtual ~PITimer();
|
||||
|
||||
//! \~english Returns timer loop delay
|
||||
//! \~russian Возвращает задержку цикла таймера
|
||||
PISystemTime interval() const;
|
||||
|
||||
//! \~english Returns timer implementation
|
||||
//! \~russian Возвращает реализацию таймера
|
||||
PITimer::TimerImplementation implementation() const { return imp_mode; }
|
||||
|
||||
//! \~english Returns timer loop delay in milliseconds
|
||||
//! \~russian Возвращает задержку цикла таймера в миллисекундах
|
||||
double interval() const;
|
||||
|
||||
EVENT_HANDLER1(void, setInterval, double, ms);
|
||||
void setInterval(PISystemTime interval) { setInterval(interval.toMilliseconds()); }
|
||||
//! \~english Set timer loop delay
|
||||
//! \~russian Установить интервал таймера
|
||||
void setInterval(PISystemTime interval);
|
||||
|
||||
//! \~english Returns if timer is started
|
||||
//! \~russian Возвращает работает ли таймер
|
||||
bool isRunning() const;
|
||||
|
||||
//! \~english Returns if timer is not started
|
||||
//! \~russian Возвращает остановлен ли таймер
|
||||
bool isStopped() const;
|
||||
//! \~english Return if timer is stopping
|
||||
//! \~russian Возвращает останавливается ли таймер
|
||||
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_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(void, stop);
|
||||
|
||||
//! \~english Start timer with \a interval() loop delay after "delay_msecs" delay
|
||||
//! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs"
|
||||
void startDeferred(double delay_ms);
|
||||
//! \~english Stop timer and wait for finish.
|
||||
//! \~russian Останавливает таймер и ожидает завершения.
|
||||
void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); }
|
||||
|
||||
//! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay
|
||||
//! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs"
|
||||
void startDeferred(double interval_ms, double delay_ms);
|
||||
|
||||
//! \~english Start timer with \a interval() loop delay after "start_datetime" date and time
|
||||
//! \~russian Запускает таймер с интервалом \a interval() после наступления "start_datetime"
|
||||
void startDeferred(PIDateTime start_datetime);
|
||||
|
||||
//! \~english Start timer with "interval_msecs" loop delay after "start_datetime" date and time
|
||||
//! \~russian Запускает таймер с интервалом "interval_msecs" после наступления "start_datetime"
|
||||
void startDeferred(double interval_ms, PIDateTime start_datetime);
|
||||
|
||||
EVENT_HANDLER0(bool, stop);
|
||||
|
||||
//! \~english Set custom data
|
||||
//! \~russian Установить данные, передаваемые в метод таймера
|
||||
void setData(void * data_) { data_t = data_; }
|
||||
|
||||
//! \~english Returns common data passed to tick functions
|
||||
//! \~russian Возвращает данные, передаваемые в метод таймера
|
||||
void * data() const { return data_t; }
|
||||
//! \~english Stop timer and wait for finish.
|
||||
//! \~russian Останавливает таймер и ожидает завершения.
|
||||
void stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(TimerEvent slot) { ret_func = slot; }
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(std::function<void()> slot) {
|
||||
ret_func = [slot](void *, int) { slot(); };
|
||||
void setSlot(std::function<void()> func) {
|
||||
ret_func = [func](int) { func(); };
|
||||
}
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(std::function<void(void *)> slot) {
|
||||
ret_func = [slot](void * d, int) { slot(d); };
|
||||
}
|
||||
void setSlot(std::function<void(int)> func) { ret_func = func; }
|
||||
|
||||
void needLockRun(bool need) { lockRun = need; }
|
||||
EVENT_HANDLER0(void, lock) { mutex_.lock(); }
|
||||
@@ -204,13 +118,11 @@ public:
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "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"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
void addDelimiter(int delim, std::function<void()> slot) {
|
||||
delims << Delimiter([slot](void *, int) { slot(); }, delim);
|
||||
}
|
||||
void addDelimiter(int delim, std::function<void()> func);
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
@@ -222,39 +134,15 @@ public:
|
||||
|
||||
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
|
||||
|
||||
EVENT2(tickEvent, void *, data_, int, delimiter);
|
||||
EVENT1(tickEvent, int, delimiter);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void setInterval(double ms)
|
||||
//! \brief
|
||||
//! \~english Set timer loop delay in milliseconds
|
||||
//! \~russian Установить интервал таймера "ms" миллисекунд
|
||||
|
||||
//! \fn bool start()
|
||||
//! \brief
|
||||
//! \~english Start timer with \a interval() loop delay
|
||||
//! \~russian Запустить таймер с интервалом \a interval()
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Start execution of timer functions with frequency = 1 / msecs Hz
|
||||
//! \~russian
|
||||
//! Запускает таймер с частотой = 1 / msecs Гц
|
||||
|
||||
//! \fn bool start(double msecs)
|
||||
//! \brief
|
||||
//! \~english Start timer with "msecs" loop delay
|
||||
//! \~russian Запустить таймер с интервалом "msecs"
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Start execution of timer functions with frequency = 1. / msecs Hz.
|
||||
//! Instead of \a start(int msecs) this function allow start timer
|
||||
//! with frequencies more than 1 kHz
|
||||
//! \~russian
|
||||
//! Запускает таймер с частотой = 1 / msecs Гц. В отличии от
|
||||
//! \a start(int msecs) этот метод позволяет запустить таймер с частотой
|
||||
//! более 1 кГц
|
||||
|
||||
//! \fn bool restart()
|
||||
//! \brief
|
||||
@@ -263,8 +151,8 @@ public:
|
||||
|
||||
//! \fn bool stop()
|
||||
//! \brief
|
||||
//! \~english Stop timer and wait for it finish
|
||||
//! \~russian Остановить таймер и дождаться остановки
|
||||
//! \~english Stop timer (don`t wait for finish)
|
||||
//! \~russian Остановить таймер (не дожидается остановки)
|
||||
|
||||
//! \fn void clearDelimiters()
|
||||
//! \brief
|
||||
@@ -275,16 +163,14 @@ public:
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void tickEvent(void * data, int delimiter)
|
||||
//! \fn void tickEvent(int delimiter)
|
||||
//! \brief
|
||||
//! \~english Raise on timer tick
|
||||
//! \~russian Вызывается каждый тик таймера
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! "data" can be set with function \a setData() or from constructor.
|
||||
//! "delimiter" is frequency delimiter, 1 for main loop.
|
||||
//! \~russian
|
||||
//! "data" устанавливается методом \a setData() или в конструкторе.
|
||||
//! "delimiter" - делитель частоты, 1 для основного цикла
|
||||
|
||||
|
||||
@@ -292,33 +178,33 @@ public:
|
||||
|
||||
protected:
|
||||
struct PIP_EXPORT Delimiter {
|
||||
Delimiter(TimerEvent slot_ = 0, int delim_ = 1) {
|
||||
slot = slot_;
|
||||
Delimiter(std::function<void(int)> func_ = nullptr, int delim_ = 1) {
|
||||
func = func_;
|
||||
delim = delim_;
|
||||
}
|
||||
TimerEvent slot;
|
||||
std::function<void(int)> func;
|
||||
int delim = 0;
|
||||
int tick = 0;
|
||||
};
|
||||
|
||||
void initFirst();
|
||||
void init() const;
|
||||
void destroy();
|
||||
|
||||
static void tickImpS(PITimer * t) { t->tickImp(); }
|
||||
void tickImp();
|
||||
void threadFunc();
|
||||
void adjustTimes();
|
||||
void execTick();
|
||||
|
||||
//! 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;
|
||||
std::atomic_bool lockRun, callEvents;
|
||||
PIThread * thread = nullptr;
|
||||
std::atomic_bool lockRun = {false}, callEvents = {true};
|
||||
PIMutex mutex_;
|
||||
TimerEvent ret_func = nullptr;
|
||||
TimerImplementation imp_mode = Thread;
|
||||
PISystemTime m_interval, m_interval_x5;
|
||||
PISystemTime m_time_next;
|
||||
std::function<void(int)> ret_func = nullptr;
|
||||
PIVector<Delimiter> delims;
|
||||
|
||||
mutable _PITimerBase * imp = nullptr;
|
||||
PIConditionVariable event;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -194,6 +194,18 @@ public:
|
||||
//! \~russian Возвращает нулевое ли время
|
||||
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
|
||||
//! \~russian Возвращает значение времени в секундах
|
||||
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); }
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Recursive call "func" for every child. "full_name" is a name with path, joined with ".".
|
||||
//! \~russian Рекурсивно выполняет "func" для каждого узла. "full_name" - это имя с путём, соединены ".".
|
||||
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & full_name)> func);
|
||||
//! \~english Recursive call "func" for every child. "path" is a name with path, joined with ".".
|
||||
//! \~russian Рекурсивно выполняет "func" для каждого узла. "path" - это имя с путём, соединены ".".
|
||||
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & path)> func);
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Returns a list of standard attribute names.
|
||||
|
||||
87
main.cpp
87
main.cpp
@@ -9,7 +9,85 @@
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
|
||||
|
||||
enum MyEvent {
|
||||
meVoid,
|
||||
meInt,
|
||||
meString,
|
||||
meIntString,
|
||||
};
|
||||
|
||||
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;
|
||||
ser.setSpeed(PISerial::S115200);
|
||||
piCout << ser.open("COM15", PIIODevice::ReadWrite);
|
||||
@@ -62,9 +140,14 @@ int main(int argc, char * argv[]) {
|
||||
test_str("1hz 1hz");*/
|
||||
|
||||
// PIPair<int, PIString> p = createPIPair(0, "");
|
||||
PIVector<PIPair<int, PIString>> pv;
|
||||
pv << createPIPair(0, PIString());
|
||||
/*PIConfig conf("model.conf");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "piliterals_time.h"
|
||||
#include "pip.h"
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
PIByteArray rnd;
|
||||
rnd.resize(1024 * 1024, 'x');
|
||||
@@ -12,7 +12,7 @@ int main(int argc, char * argv[]) {
|
||||
// c.setReopenEnabled(true);
|
||||
PICloudServer s("127.0.0.1:10101");
|
||||
auto clients = new PIVector<PICloudServer::Client *>();
|
||||
CONNECTL(&tm, tickEvent, ([&](void *, int) {
|
||||
CONNECTL(&tm, tickEvent, ([&](int) {
|
||||
if (c.isConnected()) {
|
||||
PIString str = "ping";
|
||||
piCout << "[Client] send:" << str;
|
||||
@@ -67,7 +67,7 @@ int main(int argc, char * argv[]) {
|
||||
} else {
|
||||
s.startThreadedRead();
|
||||
}
|
||||
tm.start(1000);
|
||||
tm.start(1_Hz);
|
||||
PIKbdListener ls;
|
||||
ls.enableExitCapture(PIKbdListener::F10);
|
||||
ls.start();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "dispatcherserver.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "piscreentiles.h"
|
||||
|
||||
|
||||
@@ -22,7 +23,7 @@ DispatcherServer::~DispatcherServer() {
|
||||
|
||||
void DispatcherServer::start() {
|
||||
eth.listen(true);
|
||||
timeout_timer.start(2000);
|
||||
timeout_timer.start(0.5_Hz);
|
||||
piCoutObj << "server started" << eth.readAddress();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define DISPATCHERSERVER_H
|
||||
|
||||
#include "cloudserver.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
class TileList;
|
||||
|
||||
|
||||
@@ -18,9 +18,14 @@
|
||||
*/
|
||||
|
||||
#include "dispatcherserver.h"
|
||||
#include "picrypt.h"
|
||||
#include "picli.h"
|
||||
#include "piconfig.h"
|
||||
#include "pidir.h"
|
||||
#include "piiostream.h"
|
||||
#include "pip.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "piscreen.h"
|
||||
#include "piscreentiles.h"
|
||||
#include "piscreentypes.h"
|
||||
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
@@ -127,7 +132,7 @@ int main(int argc, char * argv[]) {
|
||||
a.children()[0]->size_policy = PIScreenTypes::Fixed;
|
||||
maintile.addTile(&a);
|
||||
}
|
||||
CONNECTL(&status_timer, tickEvent, [&](void *, int) {
|
||||
CONNECTL(&status_timer, tickEvent, [&](int) {
|
||||
screen.lock();
|
||||
server.updateConnectionsTile(&conn_tl);
|
||||
server.updateServersTile(&server_tl, sel_servers);
|
||||
@@ -142,7 +147,7 @@ int main(int argc, char * argv[]) {
|
||||
screen.rootTile()->addTile(new TilePICout());
|
||||
screen.start();
|
||||
server.start();
|
||||
status_timer.start(100);
|
||||
status_timer.start(10_Hz);
|
||||
screen.waitForFinish();
|
||||
} else {
|
||||
PIKbdListener ls;
|
||||
@@ -151,7 +156,7 @@ int main(int argc, char * argv[]) {
|
||||
server.start();
|
||||
if (cli.hasArgument("verbose")) {
|
||||
CONNECTU(&status_timer, tickEvent, &server, picoutStatus);
|
||||
status_timer.start(1000);
|
||||
status_timer.start(1_Hz);
|
||||
}
|
||||
WAIT_FOR_EXIT
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ int main(int argc, char * argv[]) {
|
||||
# define PIP_CONSOLE_STATIC_DEFINE
|
||||
# include "../../libs/console/piterminal.cpp"
|
||||
# include "pifile.h"
|
||||
# include "piliterals_time.h"
|
||||
# include "pip_console_export.h"
|
||||
# include "piscreentypes.h"
|
||||
# include "pisharedmemory.h"
|
||||
@@ -164,9 +165,12 @@ public:
|
||||
PipeReader(): PIThread() {
|
||||
wrote = readed = 0;
|
||||
msg_size = 0;
|
||||
start(1);
|
||||
start(1_ms);
|
||||
}
|
||||
~PipeReader() {
|
||||
stop();
|
||||
if (!waitForFinish(100_ms)) terminate();
|
||||
}
|
||||
~PipeReader() { stop(); }
|
||||
void run() {
|
||||
in.resize(PIPE_BUFFER_SIZE);
|
||||
ReadFile(pipe, in.data(), in.size_s(), &readed, 0);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "daemon.h"
|
||||
|
||||
#include "picrypt.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "shared.h"
|
||||
|
||||
@@ -23,6 +24,7 @@ Daemon::Remote::Remote(const PIString & n): PIThread() {
|
||||
|
||||
|
||||
Daemon::Remote::~Remote() {
|
||||
term_timer.stopAndWait();
|
||||
shellClose();
|
||||
ft.stop();
|
||||
stopAndWait();
|
||||
@@ -34,14 +36,14 @@ void Daemon::Remote::shellOpen() {
|
||||
piCoutObj << "shell open";
|
||||
term = new PITerminal();
|
||||
term->initialize();
|
||||
term_timer.start(50);
|
||||
term_timer.start(20_Hz);
|
||||
}
|
||||
|
||||
|
||||
void Daemon::Remote::shellClose() {
|
||||
if (!term) return;
|
||||
piCoutObj << "shell close";
|
||||
term_timer.stop();
|
||||
term_timer.stopAndWait();
|
||||
term->destroy();
|
||||
delete term;
|
||||
term = 0;
|
||||
@@ -272,7 +274,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_"
|
||||
localft.setCRCEnabled(false);
|
||||
CONNECTU(&localft, sendRequest, _self, received)
|
||||
dtimer.addDelimiter(5);
|
||||
dtimer.start(200);
|
||||
dtimer.start(5_Hz);
|
||||
|
||||
tile_root = new PIScreenTile();
|
||||
tile_root->direction = Vertical;
|
||||
@@ -320,6 +322,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_"
|
||||
|
||||
|
||||
Daemon::~Daemon() {
|
||||
dtimer.stopAndWait();
|
||||
requestCloseShell();
|
||||
PIVector<Remote *> rl = remotes.values();
|
||||
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();
|
||||
list_daemons->content.clear();
|
||||
availableDaemons();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define DAEMON_H
|
||||
|
||||
#include "file_manager.h"
|
||||
#include "pidatatransfer.h"
|
||||
#include "pifiletransfer.h"
|
||||
#include "pipeer.h"
|
||||
#include "piscreentiles.h"
|
||||
@@ -165,7 +164,7 @@ private:
|
||||
EVENT_HANDLER3(void, fmActionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data);
|
||||
EVENT_HANDLER(void, shResizeRequest);
|
||||
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, filesSended, const PIString &, p_name, bool, ok);
|
||||
EVENT_HANDLER2(void, dirChanged, const PIString &, p_name, const PIString &, dir);
|
||||
|
||||
@@ -21,20 +21,19 @@
|
||||
#include "file_manager.h"
|
||||
#include "picli.h"
|
||||
#include "piintrospection_server.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "piprocess.h"
|
||||
#include "pisingleapplication.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#include "shared.h"
|
||||
|
||||
class _Init {
|
||||
public:
|
||||
_Init() { randomize(); }
|
||||
};
|
||||
_Init _pisd_init;
|
||||
STATIC_INITIALIZER_BEGIN
|
||||
randomize();
|
||||
STATIC_INITIALIZER_END
|
||||
|
||||
PISystemMonitor sys_mon;
|
||||
PIScreen * screen = 0;
|
||||
PIScreen * screen = nullptr;
|
||||
|
||||
|
||||
class MainMenu: public PITimer {
|
||||
@@ -93,7 +92,7 @@ public:
|
||||
CONNECTU(screen, tileEvent, this, tileEvent)
|
||||
CONNECTU(screen, keyPressed, this, keyEvent)
|
||||
CONNECTU(&daemon_, menuRequest, this, menuRequest)
|
||||
start(25);
|
||||
start(40_Hz);
|
||||
}
|
||||
PIScreenTile * menuTile() {
|
||||
TileList * ret = new TileList();
|
||||
@@ -185,13 +184,19 @@ public:
|
||||
addrs_tl->content.clear();
|
||||
peerinfo_tl->content.clear();
|
||||
peermap_tl->content.clear();
|
||||
peers_tl->content << TileList::Row("this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s())
|
||||
// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ",
|
||||
//" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " "sm = " +
|
||||
//PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " +
|
||||
//PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm) + "]"
|
||||
,
|
||||
CellFormat());
|
||||
peers_tl->content << TileList::Row(
|
||||
"this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s())
|
||||
// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ",
|
||||
//" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", "
|
||||
//"sm
|
||||
//=
|
||||
//"
|
||||
//+ PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " +
|
||||
// PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm)
|
||||
// +
|
||||
// "]"
|
||||
,
|
||||
CellFormat());
|
||||
piForeachC(PIPeer::PeerInfo & p, daemon_.allPeers())
|
||||
peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " +
|
||||
PIString::fromNumber(p.ping()) + " | n = " + PIString::fromBool(p.isNeighbour()),
|
||||
@@ -246,7 +251,7 @@ public:
|
||||
}
|
||||
screen->unlock();
|
||||
}
|
||||
void tick(void * data_, int delimiter) override {
|
||||
void tick(int delimiter) override {
|
||||
if (tpeerdiag->visible || tpeer->visible) updatePeerInfo();
|
||||
if (tinfo->visible) updateSysMon();
|
||||
}
|
||||
@@ -420,7 +425,7 @@ int main(int argc, char * argv[]) {
|
||||
ls.enableExitCapture(PIKbdListener::F10);
|
||||
ls.start();
|
||||
WAIT_FOR_EXIT
|
||||
ls.stop();
|
||||
ls.stopAndWait();
|
||||
} else {
|
||||
screen->start();
|
||||
screen->waitForFinish();
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picli.h"
|
||||
#include "pidatatransfer.h"
|
||||
#include "piethernet.h"
|
||||
#include "pifiletransfer.h"
|
||||
#include "pip.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "piscreen.h"
|
||||
#include "piscreentiles.h"
|
||||
|
||||
@@ -52,7 +54,7 @@ public:
|
||||
CONNECTU(&ft, receiveFilesFinished, this, ftevent);
|
||||
}
|
||||
CONNECT2(void, const uchar *, ssize_t, ð, threadedReadEvent, this, received);
|
||||
start(50);
|
||||
start(20_Hz);
|
||||
eth.setParameter(PIEthernet::SeparateSockets);
|
||||
eth.startThreadedRead();
|
||||
}
|
||||
@@ -74,7 +76,7 @@ private:
|
||||
PIEthernet eth;
|
||||
bool quet_;
|
||||
|
||||
void tick(void *, int) override {
|
||||
void tick(int) override {
|
||||
if (ft.isStarted()) {
|
||||
ftevent();
|
||||
updatePMT();
|
||||
|
||||
Reference in New Issue
Block a user