From abdba6d68b628e212e91363cd5025f6bd4770761 Mon Sep 17 00:00:00 2001 From: peri4 Date: Wed, 17 Jul 2024 21:11:01 +0300 Subject: [PATCH] state machine, parallel seems to work, final state and info about active atomic states --- libs/main/state_machine/pistatemachine.cpp | 8 +- libs/main/state_machine/pistatemachine.h | 17 ++++ .../state_machine/pistatemachine_state.cpp | 96 ++++++++++++++----- .../main/state_machine/pistatemachine_state.h | 34 +++++-- .../pistatemachine_transition.cpp | 19 +++- main.cpp | 55 ++++++----- 6 files changed, 168 insertions(+), 61 deletions(-) diff --git a/libs/main/state_machine/pistatemachine.cpp b/libs/main/state_machine/pistatemachine.cpp index eae8a494..21a9bf55 100644 --- a/libs/main/state_machine/pistatemachine.cpp +++ b/libs/main/state_machine/pistatemachine.cpp @@ -27,5 +27,11 @@ PIStateMachine::PIStateMachine(const PIString & n): PIStateBase(n) { bool PIStateMachine::start() { setActiveRecursive(false); - return PIStateBase::start(); + is_running = PIStateBase::start(); + return is_running; +} + + +void PIStateMachine::onFinish() { + need_finish = true; } diff --git a/libs/main/state_machine/pistatemachine.h b/libs/main/state_machine/pistatemachine.h index 03f9be76..31bb5d8e 100644 --- a/libs/main/state_machine/pistatemachine.h +++ b/libs/main/state_machine/pistatemachine.h @@ -39,11 +39,22 @@ public: PIStateMachine(const PIString & n = {}); bool start(); + bool isRunning() const { return is_running; } + void addOnFinish(std::function f) { on_finish = f; } template 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 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; @@ -55,6 +66,12 @@ public: } return false; } + +private: + void onFinish() override; + + bool is_running = false, need_finish = false; + std::function on_finish; }; diff --git a/libs/main/state_machine/pistatemachine_state.cpp b/libs/main/state_machine/pistatemachine_state.cpp index 2d80745d..28075ebb 100644 --- a/libs/main/state_machine/pistatemachine_state.cpp +++ b/libs/main/state_machine/pistatemachine_state.cpp @@ -28,6 +28,23 @@ PIStateBase::~PIStateBase() { } +PIVector PIStateBase::activeChildren() const { + if (!isParallel()) { + if (active_state) return {active_state}; + return {}; + } + if (isActive()) return children; + return {}; +} + + +PIVector PIStateBase::activeAtomics() const { + PIVector ret; + gatherActiveAtomicStates(ret); + return ret; +} + + void PIStateBase::addState(PIStateBase * s) { children << s; s->parent_state = this; @@ -60,7 +77,8 @@ PITransitionBase * PIStateBase::addTransition(PIStateBase * target, int event_id void PIStateBase::print(PIString prefix) { - PICout(PICoutManipulators::AddNewLine) << prefix << "[" << (isActive() ? "*" : " ") << "] " << getName(); + PICout(PICoutManipulators::AddNewLine) << prefix << "[" << (isActive() ? "*" : " ") << "] " << getName() << " active " + << activeChildren(); prefix += " "; for (auto * c: children) c->print(prefix); @@ -72,11 +90,19 @@ bool PIStateBase::start() { setActive(true); return true; } else { - if (initial_state) { + if (!isParallel()) { + if (initial_state) { + setActive(true); + return initial_state->start(); + } else + piCout << "error:" << getName() << "no initial state!"; + } else { setActive(true); - return initial_state->start(); - } else - piCout << "error:" << getName() << "no initial state!"; + for (auto * s: children) { + if (!s->start()) return false; + } + return true; + } } return false; } @@ -85,8 +111,16 @@ bool PIStateBase::start() { void PIStateBase::setActive(bool yes) { bool prev_active = is_active; is_active = yes; - if (!prev_active && is_active) onEnter(); - if (prev_active && !is_active) onExit(); + if (parent_state && yes) parent_state->childActived(this); + if (!prev_active && is_active) { + onEnter(); + // if (isParallel()) setChildrenActive(true); + } + if (prev_active && !is_active) { + active_state = nullptr; + if (isParallel()) setChildrenActiveRecursive(false); + onExit(); + } } @@ -98,26 +132,37 @@ void PIStateBase::setActiveRecursive(bool yes) { } -void PIStateBase::setChildActiveRecursive(bool yes) { +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::setChildActive(PIStateBase * s) { - if (isAtomic()) return; - if (!s) s = initial_state; - if (!s) { - piCout << "error:" << getName() << "no initial state!"; - return; +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); } - for (auto * c: children) - c->setActive(false); - if (active_state) { - if (active_state != s) active_state->setActive(false); - } - active_state = s; - if (active_state) active_state->setActive(true); +} + + +void PIStateBase::childActived(PIStateBase * s) { + if (!isParallel()) { + active_state = s; + if (active_state->isFinal()) onFinish(); + } else + active_state = nullptr; } @@ -136,7 +181,14 @@ void PIStateBase::propagateRoot(PIStateMachine * r) { void PIStateBase::gatherActiveStates(PIVector & output) { for (auto * c: children) c->gatherActiveStates(output); - if (is_active) output << this; + if (isActive()) output << this; +} + + +void PIStateBase::gatherActiveAtomicStates(PIVector & output) const { + for (auto * c: children) + c->gatherActiveAtomicStates(output); + if (isActive() && isAtomic()) output << const_cast(this); } diff --git a/libs/main/state_machine/pistatemachine_state.h b/libs/main/state_machine/pistatemachine_state.h index 6906f464..e9749bdb 100644 --- a/libs/main/state_machine/pistatemachine_state.h +++ b/libs/main/state_machine/pistatemachine_state.h @@ -44,9 +44,13 @@ public: 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 activeChildren() const; + PIVector activeAtomics() const; void addState(PIStateBase * s); void addStates(PIVector s); @@ -60,6 +64,7 @@ public: 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 & getChildren() const { return children; } @@ -71,14 +76,17 @@ protected: bool start(); void setActive(bool yes); void setActiveRecursive(bool yes); - void setChildActiveRecursive(bool yes); - void setChildActive(PIStateBase * s); + void setChildrenActive(bool yes); + void setChildrenActiveRecursive(bool yes); + void activeChild(PIStateBase * c); + void childActived(PIStateBase * s); void propagateRoot(PIStateMachine * r); void gatherActiveStates(PIVector & output); + void gatherActiveAtomicStates(PIVector & output) const; void gatherPathToMachine(PIVector & output); PIVector pathToMachine(); - bool is_active = false, is_root = false, is_parallel = false; + bool is_active = false, is_root = false, is_parallel = false, is_final = false; PIVector children; PIVector transitions; PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr; @@ -107,20 +115,26 @@ private: class PIP_EXPORT PIStateFinal: public PIStateBase { public: - PIStateFinal(std::function on_enter, std::function on_exit = nullptr, const PIString & n = {}): PIStateBase(n) { - enter = on_enter; - exit = on_exit; + PIStateFinal(std::function on_finish = nullptr, const PIString & n = {}): PIStateBase(n) { + is_final = true; + enter = on_finish; } void onEnter() override { if (enter) enter(); } - void onExit() override { - if (exit) exit(); - } private: - std::function enter, exit; + std::function enter; }; +inline PICout operator<<(PICout c, PIStateBase * s) { + if (!s) + c << "state(nullptr)"; + else + c << ("state(" + s->getName() + ")"); + return c; +} + + #endif diff --git a/libs/main/state_machine/pistatemachine_transition.cpp b/libs/main/state_machine/pistatemachine_transition.cpp index 5f3445fb..0b328524 100644 --- a/libs/main/state_machine/pistatemachine_transition.cpp +++ b/libs/main/state_machine/pistatemachine_transition.cpp @@ -71,11 +71,24 @@ void PITransitionBase::trigger() { target_path.remove(target_path.size_s() - common_count, common_count); // piCout << "source_path" << source_path; // piCout << "target_path" << target_path; - source_state->setChildActiveRecursive(false); + // 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 (auto * s: source_target_path) - s->setActive(true); + 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(); } diff --git a/main.cpp b/main.cpp index c8349868..8c575fc2 100644 --- a/main.cpp +++ b/main.cpp @@ -20,51 +20,56 @@ enum MyEvent { 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"); + 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(s22); + s2->setInitialState(s21); s21->setInitialState(s213); - s1->addTransition(s213, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; }); - s21->addTransition(s22, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; }); + 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->setInitialState(s1); root->start(); - piCout << "initial\n"; - root->print(); - - // piCout << root->postEvent(meVoid); - // piCout << root->postEvent(meInt, 1); - - piCout << "\npost event"; - posted = root->postEvent(meVoid); - piCout << "posted" << posted << "\n"; + 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();