state machine, parallel seems to work, final state and info about active atomic states

This commit is contained in:
2024-07-17 21:11:01 +03:00
parent 3db26a762c
commit abdba6d68b
6 changed files with 168 additions and 61 deletions

View File

@@ -27,5 +27,11 @@ PIStateMachine::PIStateMachine(const PIString & n): PIStateBase(n) {
bool PIStateMachine::start() { bool PIStateMachine::start() {
setActiveRecursive(false); setActiveRecursive(false);
return PIStateBase::start(); is_running = PIStateBase::start();
return is_running;
}
void PIStateMachine::onFinish() {
need_finish = true;
} }

View File

@@ -39,11 +39,22 @@ public:
PIStateMachine(const PIString & n = {}); PIStateMachine(const PIString & n = {});
bool start(); bool start();
bool isRunning() const { return is_running; }
void addOnFinish(std::function<void()> f) { on_finish = f; }
template<typename... Args> template<typename... Args>
bool postEvent(int event_id, Args... 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; PIVector<PIStateBase *> active_states;
gatherActiveStates(active_states); gatherActiveStates(active_states);
// piCout << "active" << active_states;
for (auto * s: active_states) { for (auto * s: active_states) {
for (auto * t: s->transitions) { for (auto * t: s->transitions) {
if (t->eventID != event_id) continue; if (t->eventID != event_id) continue;
@@ -55,6 +66,12 @@ public:
} }
return false; return false;
} }
private:
void onFinish() override;
bool is_running = false, need_finish = false;
std::function<void()> on_finish;
}; };

View File

@@ -28,6 +28,23 @@ PIStateBase::~PIStateBase() {
} }
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) { void PIStateBase::addState(PIStateBase * s) {
children << s; children << s;
s->parent_state = this; s->parent_state = this;
@@ -60,7 +77,8 @@ PITransitionBase * PIStateBase::addTransition(PIStateBase * target, int event_id
void PIStateBase::print(PIString prefix) { void PIStateBase::print(PIString prefix) {
PICout(PICoutManipulators::AddNewLine) << prefix << "[" << (isActive() ? "*" : " ") << "] " << getName(); PICout(PICoutManipulators::AddNewLine) << prefix << "[" << (isActive() ? "*" : " ") << "] " << getName() << " active "
<< activeChildren();
prefix += " "; prefix += " ";
for (auto * c: children) for (auto * c: children)
c->print(prefix); c->print(prefix);
@@ -72,11 +90,19 @@ bool PIStateBase::start() {
setActive(true); setActive(true);
return true; return true;
} else { } else {
if (!isParallel()) {
if (initial_state) { if (initial_state) {
setActive(true); setActive(true);
return initial_state->start(); return initial_state->start();
} else } else
piCout << "error:" << getName() << "no initial state!"; piCout << "error:" << getName() << "no initial state!";
} else {
setActive(true);
for (auto * s: children) {
if (!s->start()) return false;
}
return true;
}
} }
return false; return false;
} }
@@ -85,8 +111,16 @@ bool PIStateBase::start() {
void PIStateBase::setActive(bool yes) { void PIStateBase::setActive(bool yes) {
bool prev_active = is_active; bool prev_active = is_active;
is_active = yes; is_active = yes;
if (!prev_active && is_active) onEnter(); if (parent_state && yes) parent_state->childActived(this);
if (prev_active && !is_active) onExit(); 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) for (auto * c: children)
c->setActiveRecursive(yes); c->setActiveRecursive(yes);
} }
void PIStateBase::setChildActive(PIStateBase * s) { void PIStateBase::activeChild(PIStateBase * c) {
if (isAtomic()) return; setActive(true);
if (!s) s = initial_state; if (isParallel())
if (!s) { for (auto * s: children) {
piCout << "error:" << getName() << "no initial state!"; if (c != s) s->start();
return;
} }
for (auto * c: children) else {
c->setActive(false); if (!c) c = initial_state;
if (active_state) { if (c) c->setActive(true);
if (active_state != s) active_state->setActive(false);
} }
}
void PIStateBase::childActived(PIStateBase * s) {
if (!isParallel()) {
active_state = s; active_state = s;
if (active_state) active_state->setActive(true); if (active_state->isFinal()) onFinish();
} else
active_state = nullptr;
} }
@@ -136,7 +181,14 @@ void PIStateBase::propagateRoot(PIStateMachine * r) {
void PIStateBase::gatherActiveStates(PIVector<PIStateBase *> & output) { void PIStateBase::gatherActiveStates(PIVector<PIStateBase *> & output) {
for (auto * c: children) for (auto * c: children)
c->gatherActiveStates(output); c->gatherActiveStates(output);
if (is_active) output << this; 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);
} }

View File

@@ -44,9 +44,13 @@ public:
virtual void onEnter() {} virtual void onEnter() {}
virtual void onExit() {} virtual void onExit() {}
virtual void onFinish() {}
PIStateMachine * machine() const { return root; } PIStateMachine * machine() const { return root; }
PIStateBase * parent() const { return parent_state; } 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 addState(PIStateBase * s);
void addStates(PIVector<PIStateBase *> s); void addStates(PIVector<PIStateBase *> s);
@@ -60,6 +64,7 @@ public:
bool isStateMachine() const { return is_root; } bool isStateMachine() const { return is_root; }
bool isActive() const { return is_active; } bool isActive() const { return is_active; }
bool isParallel() const { return is_parallel; } bool isParallel() const { return is_parallel; }
bool isFinal() const { return is_final; }
bool isAtomic() const { return children.isEmpty(); } bool isAtomic() const { return children.isEmpty(); }
bool isCompound() const { return children.isNotEmpty(); } bool isCompound() const { return children.isNotEmpty(); }
const PIVector<PIStateBase *> & getChildren() const { return children; } const PIVector<PIStateBase *> & getChildren() const { return children; }
@@ -71,14 +76,17 @@ protected:
bool start(); bool start();
void setActive(bool yes); void setActive(bool yes);
void setActiveRecursive(bool yes); void setActiveRecursive(bool yes);
void setChildActiveRecursive(bool yes); void setChildrenActive(bool yes);
void setChildActive(PIStateBase * s); void setChildrenActiveRecursive(bool yes);
void activeChild(PIStateBase * c);
void childActived(PIStateBase * s);
void propagateRoot(PIStateMachine * r); void propagateRoot(PIStateMachine * r);
void gatherActiveStates(PIVector<PIStateBase *> & output); void gatherActiveStates(PIVector<PIStateBase *> & output);
void gatherActiveAtomicStates(PIVector<PIStateBase *> & output) const;
void gatherPathToMachine(PIVector<PIStateBase *> & output); void gatherPathToMachine(PIVector<PIStateBase *> & output);
PIVector<PIStateBase *> pathToMachine(); PIVector<PIStateBase *> 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<PIStateBase *> children; PIVector<PIStateBase *> children;
PIVector<PITransitionBase *> transitions; PIVector<PITransitionBase *> transitions;
PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr; PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr;
@@ -107,20 +115,26 @@ private:
class PIP_EXPORT PIStateFinal: public PIStateBase { class PIP_EXPORT PIStateFinal: public PIStateBase {
public: public:
PIStateFinal(std::function<void()> on_enter, std::function<void()> on_exit = nullptr, const PIString & n = {}): PIStateBase(n) { PIStateFinal(std::function<void()> on_finish = nullptr, const PIString & n = {}): PIStateBase(n) {
enter = on_enter; is_final = true;
exit = on_exit; enter = on_finish;
} }
void onEnter() override { void onEnter() override {
if (enter) enter(); if (enter) enter();
} }
void onExit() override {
if (exit) exit();
}
private: private:
std::function<void()> enter, exit; std::function<void()> enter;
}; };
inline PICout operator<<(PICout c, PIStateBase * s) {
if (!s)
c << "state(nullptr)";
else
c << ("state(" + s->getName() + ")");
return c;
}
#endif #endif

View File

@@ -71,11 +71,24 @@ void PITransitionBase::trigger() {
target_path.remove(target_path.size_s() - common_count, common_count); target_path.remove(target_path.size_s() - common_count, common_count);
// piCout << "source_path" << source_path; // piCout << "source_path" << source_path;
// piCout << "target_path" << target_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) for (auto * s: source_path)
s->setActive(false); s->setActive(false);
makeAction(); makeAction();
for (auto * s: source_target_path) for (int i = 0; i < source_target_path.size_s(); ++i) {
s->setActive(true); 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(); if (target_state->isCompound()) target_state->start();
} }

View File

@@ -20,6 +20,7 @@ enum MyEvent {
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
bool posted; bool posted;
PIStateMachine * root = new PIStateMachine("Machine"); PIStateMachine * root = new PIStateMachine("Machine");
root->addOnFinish([] { piCout << "finish"; });
PIStateLambda * s1 = new PIStateLambda([] { piCout << "+ enter s1"; }, [] { piCout << "- exit s1"; }, "s1"); PIStateLambda * s1 = new PIStateLambda([] { piCout << "+ enter s1"; }, [] { piCout << "- exit s1"; }, "s1");
PIStateLambda * s2 = new PIStateLambda([] { piCout << "+ enter s2"; }, [] { piCout << "- exit s2"; }, "s2"); PIStateLambda * s2 = new PIStateLambda([] { piCout << "+ enter s2"; }, [] { piCout << "- exit s2"; }, "s2");
@@ -33,38 +34,42 @@ int main(int argc, char * argv[]) {
PIStateLambda * s211 = new PIStateLambda([] { piCout << " + enter s211"; }, [] { piCout << " - exit s211"; }, "s211"); PIStateLambda * s211 = new PIStateLambda([] { piCout << " + enter s211"; }, [] { piCout << " - exit s211"; }, "s211");
PIStateLambda * s212 = new PIStateLambda([] { piCout << " + enter s212"; }, [] { piCout << " - exit s212"; }, "s212"); PIStateLambda * s212 = new PIStateLambda([] { piCout << " + enter s212"; }, [] { piCout << " - exit s212"; }, "s212");
PIStateLambda * s213 = new PIStateLambda([] { piCout << " + enter s213"; }, [] { piCout << " - exit s213"; }, "s213"); 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}); root->addStates({s1, s2, s3});
s1->addStates({s11, s12, s13}); s1->addStates({s11, s12, s13});
s2->addStates({s21, s22, s23}); s2->addStates({s21, s22, s23});
s21->addStates({s211, s212, s213}); s21->addStates({s211, s212, s213});
// root->addState(s214);
s2->setParallel(true);
root->setInitialState(s2);
s1->setInitialState(s11); s1->setInitialState(s11);
s2->setInitialState(s22); s2->setInitialState(s21);
s21->setInitialState(s213); s21->setInitialState(s213);
s1->addTransition(s213, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; }); s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; });
s21->addTransition(s22, 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; }); // s2->addTransition(s3, meInt)->addGuard([](int i) { return i == 1; });
// s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; }); // s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; });
root->setInitialState(s1);
root->start(); root->start();
piCout << "initial\n"; piCout << "initial" << root->isRunning() << "\n";
root->print(); piCout << "active atomics" << root->activeAtomics();
// piCout << root->postEvent(meVoid);
// piCout << root->postEvent(meInt, 1);
piCout << "\npost event";
posted = root->postEvent(meVoid);
piCout << "posted" << posted << "\n";
root->print(); root->print();
piCout << "\npost event"; piCout << "\npost event";
posted = root->postEvent(meVoid); posted = root->postEvent(meVoid);
piCout << "posted" << posted << "\n"; piCout << "posted" << posted << "\n";
piCout << "active atomics" << root->activeAtomics();
root->print(); root->print();
// piCout << "\npost event";
// posted = root->postEvent(meVoid);
// piCout << "posted" << posted << "\n";
// root->print();
/*root->addStates({s1, s2, s3}); /*root->addStates({s1, s2, s3});
root->setInitialState(s1); root->setInitialState(s1);
root->start(); root->start();