/*! \file pistatemachinemodule.h * \ingroup StateMachine * \~\brief * \~english Declares module entry includes for the state machine API * \~russian Объявляет основной include модуля API машины состояний * * \~\details * \~english Includes the public state machine, state, and transition headers. * \~russian Подключает публичные заголовки машины состояний, состояний и переходов. */ /* 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 . */ //! \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 //! The module provides hierarchical states, event-driven transitions, timeout //! transitions and helper state classes for callback-based logic. //! \~russian //! Модуль предоставляет иерархические состояния, переходы по событиям, //! переходы по таймауту и вспомогательные классы состояний для логики на callback-функциях. //! \~\authors //! \~english //! Ivan Pelipenko peri4ko@yandex.ru; //! Andrey Bychkov work.a.b@yandex.ru; //! \~russian //! Иван Пелипенко peri4ko@yandex.ru; //! Андрей Бычков work.a.b@yandex.ru; //! //! //! \~english \section state_machine_overview General Description //! \~russian \section state_machine_overview Общее описание //! //! \~english State machine is a behavioral design pattern that allows an object to change its behavior when its internal state changes. //! Implementation in PIP is based on the **SCXML** (State Chart XML) standard. //! \~russian Машина состояний — это поведенческий паттерн проектирования, который позволяет объекту изменять свое поведение при изменении //! внутреннего состояния. Реализация в PIP основана на стандарте **SCXML** (State Chart XML). //! //! \~english \subsection scxml_concepts SCXML Concepts //! \~russian \subsection scxml_concepts Основные концепции SCXML //! //! \~english - **State** — a node in the state tree, can be atomic or compound //! \~russian - **State (Состояние)** — узел в дереве состояний, может быть атомарным или составным //! \~english - **Transition** — a connection between states that triggers on an event //! \~russian - **Transition (Переход)** — связь между состояниями, срабатывает при событии //! \~english - **Event** — a trigger that causes a transition //! \~russian - **Event (Событие)** — триггер, вызывающий переход //! \~english - **Guard** — a condition that must be true for a transition to execute //! \~russian - **Guard (Сторожевая функция)** — условие, которое должно быть истинным для выполнения перехода //! \~english - **Action** — an operation executed during a transition //! \~russian - **Action (Действие)** — операция, выполняемая при переходе //! \~english - **Parallel** — a state where all substates are activated simultaneously //! \~russian - **Parallel (Параллельное состояние)** — состояние, в котором все подсостояния активируются одновременно //! //! \~english \subsection pim_state_machine_features PIP State Machine Features //! \~russian \subsection pim_state_machine_features Особенности реализации PIP //! //! \~english - **Cannot create state, event, transition on stack** — all objects are created via `new` and managed via pointers //! \~russian - **Нельзя создавать state, event, transition в стеке** — все объекты создаются через `new` и управляются через указатели //! \~english - **State machine is the root state** — `PIStateMachine` inherits from `PIStateBase` //! \~russian - **Машина состояний — это корневой state** — `PIStateMachine` наследуется от `PIStateBase` //! \~english - **All transitions and states are automatically deleted** — when the parent object is destroyed //! \~russian - **Все переходы и состояния удаляются автоматически** — при уничтожении родительского объекта //! //! \~english \subsection state_types State Types //! \~russian \subsection state_types Основные типы состояний //! //! \~english - **Atomic state** — a state without nested substates //! \~russian - **Атомарное состояние** — состояние без вложенных подсостояний //! \~english - **Compound state** — a state containing nested substates //! \~russian - **Составное состояние** — состояние, содержащее вложенные подсостояния //! \~english - **Final state** — a terminating state indicating the end of machine execution //! \~russian - **Финальное состояние** — завершающее состояние, указывающее на окончание работы машины //! \~english - **Parallel state** — a state where all substates are activated simultaneously //! \~russian - **Параллельное состояние** — состояние, в котором все подсостояния активируются одновременно //! //! \~english \subsection transition_types Transition Types //! \~russian \subsection transition_types Виды переходов //! //! \~english - **Normal transition** — triggers on receiving a specific event //! \~russian - **Обычный переход** — срабатывает при получении определенного события //! \~english - **Timeout transition** — triggers automatically after a specified time interval //! \~russian - **Переход по таймауту** — срабатывает автоматически через заданный промежуток времени //! \~english - **Guarded transition** — triggers only when a specific condition is met //! \~russian - **Переход с guard** — срабатывает только при выполнении определенного условия //! //! \~english \section state_machine_api State Machine API //! \~russian \section state_machine_api PIP State Machine API //! //! \~english \subsection main_classes Main Classes //! \~russian \subsection main_classes Основные классы //! //! \~english ### PIStateMachine //! //! \~english Main state machine class. //! \~russian Основной класс машины состояний. //! //! \~english **Key methods:** //! \~russian **Ключевые методы:** //! //! \~english - `bool start()` — starts state machine execution //! \~russian - `bool start()` — запускает выполнение машины состояний //! \~english - `bool isRunning()` — checks if state machine is running //! \~russian - `bool isRunning()` — проверяет, запущена ли машина //! \~english - `void setOnFinish(std::function f)` — sets finish callback //! \~russian - `void setOnFinish(std::function f)` — устанавливает коллбэк завершения //! \~english - `bool postEvent(int event_id, Args... args)` — posts event to state machine //! \~russian - `bool postEvent(int event_id, Args... args)` — отправляет событие в машину состояний //! //! \~english ### PIStateBase //! //! \~english Base class for all states. //! \~russian Базовый класс для всех состояний. //! //! \~english **Key methods:** //! \~russian **Ключевые методы:** //! //! \~english - `virtual void onEnter()` — called when state is entered //! \~russian - `virtual void onEnter()` — вызывается при входе в состояние //! \~english - `virtual void onExit()` — called when state is exited //! \~russian - `virtual void onExit()` — вызывается при выходе из состояния //! \~english - `void addState(PIStateBase *s)` — adds child state //! \~russian - `void addState(PIStateBase *s)` — добавляет дочернее состояние //! \~english - `PITransitionBase *addTransition(PIStateBase *target, int event_id)` — adds transition //! \~russian - `PITransitionBase *addTransition(PIStateBase *target, int event_id)` — добавляет переход //! \~english - `PITransitionTimeout *addTimeoutTransition(PIStateBase *target, PISystemTime timeout)` — adds timeout transition //! \~russian - `PITransitionTimeout *addTimeoutTransition(PIStateBase *target, PISystemTime timeout)` — добавляет переход по таймауту //! \~english - `void setParallel(bool yes)` — sets parallel mode //! \~russian - `void setParallel(bool yes)` — устанавливает параллельный режим //! //! \~english ### PIStateLambda //! //! \~english State with lambda callbacks. //! \~russian Состояние с lambda-коллбэками. //! //! \~english ```cpp //! \~english PIStateLambda(std::function on_enter, std::function on_exit = nullptr, const PIString &n = {}) //! \~english ``` //! \~russian ```cpp //! \~russian PIStateLambda(std::function on_enter, std::function on_exit = nullptr, const PIString &n = {}) //! \~russian ``` //! //! \~english ### PIStateFinal //! //! \~english Final state of state machine. //! \~russian Финальное состояние машины состояний. //! //! \~english ```cpp //! \~english PIStateFinal(std::function on_finish = nullptr, const PIString &n = {}) //! \~english ``` //! \~russian ```cpp //! \~russian PIStateFinal(std::function on_finish = nullptr, const PIString &n = {}) //! \~russian ``` //! //! \~english ### PITransitionBase //! //! \~english Base class for transitions. //! \~russian Базовый класс для переходов. //! //! \~english **Key methods:** //! \~russian **Ключевые методы:** //! //! \~english - `PITransitionBase *addGuard(std::function f)` — adds guard function //! \~russian - `PITransitionBase *addGuard(std::function f)` — добавляет сторожевую функцию //! \~english - `PITransitionBase *addAction(std::function a)` — adds action //! \~russian - `PITransitionBase *addAction(std::function a)` — добавляет действие //! \~english - `void trigger()` — triggers transition //! \~russian - `void trigger()` — запускает переход //! //! \~english ### PITransitionTimeout //! //! \~english Transition that triggers after a specified timeout. //! \~russian Переход, срабатывающий через заданный промежуток времени. //! //! \~english \section usage_examples Usage Examples //! \~russian \section usage_examples Примеры использования //! //! \~english \subsection simple_state_machine Simple State Machine //! \~russian \subsection simple_state_machine Простая машина состояний //! //! \~english ```cpp //! \~english #include "pistatemachine.h" //! \~english #include "pisystemtime.h" //! \~english //! \~english // Create state machine //! \~english PIStateMachine *machine = new PIStateMachine("Main"); //! \~english //! \~english // Create states //! \~english PIStateLambda *idle = new PIStateLambda( //! \~english []() { piCout << "Entering Idle state\n"; }, //! \~english []() { piCout << "Exiting Idle state\n"; }, //! \~english "Idle" //! \~english ); //! \~english PIStateLambda *running = new PIStateLambda( //! \~english []() { piCout << "Entering Running state\n"; }, //! \~english []() { piCout << "Exiting Running state\n"; }, //! \~english "Running" //! \~english ); //! \~english PIStateFinal *finish = new PIStateFinal( //! \~english []() { piCout << "Machine finished\n"; }, //! \~english "Finish" //! \~english ); //! \~english //! \~english // Add states //! \~english machine->addState(idle); //! \~english machine->addState(running); //! \~english machine->addState(finish); //! \~english //! \~english // Set initial state //! \~english idle->setInitialState(idle); //! \~english running->setInitialState(running); //! \~english machine->setInitialState(idle); //! \~english //! \~english // Add transitions //! \~english idle->addTransition(running, 1); //! \~english running->addTransition(finish, 2); //! \~english //! \~english // Set finish callback //! \~english machine->setOnFinish([]() { piCout << "Machine execution completed\n"; }); //! \~english //! \~english // Start machine //! \~english machine->start(); //! \~english //! \~english // Post events //! \~english machine->postEvent(1); // Transition to Running //! \~english machine->postEvent(2); // Transition to Finish //! \~english ``` //! \~russian ```cpp //! \~russian #include "pistatemachine.h" //! \~russian #include "pisystemtime.h" //! \~russian //! \~russian // Создаем машину состояний //! \~russian PIStateMachine *machine = new PIStateMachine("Main"); //! \~russian //! \~russian // Создаем состояния //! \~russian PIStateLambda *idle = new PIStateLambda( //! \~russian []() { piCout << "Entering Idle state\n"; }, //! \~russian []() { piCout << "Exiting Idle state\n"; }, //! \~russian "Idle" //! \~russian ); //! \~russian PIStateLambda *running = new PIStateLambda( //! \~russian []() { piCout << "Entering Running state\n"; }, //! \~russian []() { piCout << "Exiting Running state\n"; }, //! \~russian "Running" //! \~russian ); //! \~russian PIStateFinal *finish = new PIStateFinal( //! \~russian []() { piCout << "Machine finished\n"; }, //! \~russian "Finish" //! \~russian ); //! \~russian //! \~russian // Добавляем состояния //! \~russian machine->addState(idle); //! \~russian machine->addState(running); //! \~russian machine->addState(finish); //! \~russian //! \~russian // Устанавливаем начальное состояние //! \~russian idle->setInitialState(idle); //! \~russian running->setInitialState(running); //! \~russian machine->setInitialState(idle); //! \~russian //! \~russian // Добавляем переходы //! \~russian idle->addTransition(running, 1); //! \~russian running->addTransition(finish, 2); //! \~russian //! \~russian // Устанавливаем коллбэк завершения //! \~russian machine->setOnFinish([]() { piCout << "Machine execution completed\n"; }); //! \~russian //! \~russian // Запускаем машину //! \~russian machine->start(); //! \~russian //! \~russian // Отправляем события //! \~russian machine->postEvent(1); // Перейти в Running //! \~russian machine->postEvent(2); // Перейти в Finish //! \~russian ``` //! //! \~english \subsection guarded_transitions Guarded Transitions //! \~russian \subsection guarded_transitions Машина состояний с guard-функциями //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("With Guards"); //! \~english //! \~english PIStateLambda *stateA = new PIStateLambda([]() { piCout << "State A\n"; }, nullptr, "A"); //! \~english PIStateLambda *stateB = new PIStateLambda([]() { piCout << "State B\n"; }, nullptr, "B"); //! \~english PIStateLambda *stateC = new PIStateLambda([]() { piCout << "State C\n"; }, nullptr, "C"); //! \~english //! \~english machine->addState(stateA); //! \~english machine->addState(stateB); //! \~english machine->addState(stateC); //! \~english //! \~english stateA->setInitialState(stateA); //! \~english machine->setInitialState(stateA); //! \~english //! \~english // Transition with guard function //! \~english auto *t1 = stateA->addTransition(stateB, 1); //! \~english t1->addGuard([](int value) -> bool { //! \~english return value > 10; //! \~english }); //! \~english //! \~english // Transition with another guard function //! \~english auto *t2 = stateB->addTransition(stateC, 2); //! \~english t2->addGuard([](const PIString &msg) -> bool { //! \~english return msg == "allowed"; //! \~english }); //! \~english //! \~english machine->start(); //! \~english //! \~english // First call will not execute (value <= 10) //! \~english machine->postEvent(1, 5); //! \~english //! \~english // Second call will execute (value > 10) //! \~english machine->postEvent(1, 15); //! \~english //! \~english // First call will not execute (msg != "allowed") //! \~english machine->postEvent(2, "test"); //! \~english //! \~english // Second call will execute (msg == "allowed") //! \~english machine->postEvent(2, "allowed"); //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("With Guards"); //! \~russian //! \~russian PIStateLambda *stateA = new PIStateLambda([]() { piCout << "State A\n"; }, nullptr, "A"); //! \~russian PIStateLambda *stateB = new PIStateLambda([]() { piCout << "State B\n"; }, nullptr, "B"); //! \~russian PIStateLambda *stateC = new PIStateLambda([]() { piCout << "State C\n"; }, nullptr, "C"); //! \~russian //! \~russian machine->addState(stateA); //! \~russian machine->addState(stateB); //! \~russian machine->addState(stateC); //! \~russian //! \~russian stateA->setInitialState(stateA); //! \~russian machine->setInitialState(stateA); //! \~russian //! \~russian // Переход с guard-функцией //! \~russian auto *t1 = stateA->addTransition(stateB, 1); //! \~russian t1->addGuard([](int value) -> bool { //! \~russian return value > 10; //! \~russian }); //! \~russian //! \~russian // Переход с другой guard-функцией //! \~russian auto *t2 = stateB->addTransition(stateC, 2); //! \~russian t2->addGuard([](const PIString &msg) -> bool { //! \~russian return msg == "allowed"; //! \~russian }); //! \~russian //! \~russian machine->start(); //! \~russian //! \~russian // Первый вызов не выполнится (value <= 10) //! \~russian machine->postEvent(1, 5); //! \~russian //! \~russian // Второй вызов выполнится (value > 10) //! \~russian machine->postEvent(1, 15); //! \~russian //! \~russian // Первый вызов не выполнится (msg != "allowed") //! \~russian machine->postEvent(2, "test"); //! \~russian //! \~russian // Второй вызов выполнится (msg == "allowed") //! \~russian machine->postEvent(2, "allowed"); //! \~russian ``` //! //! \~english \subsection timeout_transitions Timeout Transitions //! \~russian \subsection timeout_transitions Машина состояний с таймаутами //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("With Timeout"); //! \~english //! \~english PIStateLambda *working = new PIStateLambda( //! \~english []() { piCout << "Working...\n"; }, //! \~english []() { piCout << "Stop working\n"; }, //! \~english "Working" //! \~english ); //! \~english PIStateLambda *timeoutState = new PIStateLambda([]() { piCout << "Timeout occurred\n"; }, nullptr, "Timeout"); //! \~english PIStateFinal *finish = new PIStateFinal([]() { piCout << "Done\n"; }, "Finish"); //! \~english //! \~english machine->addState(working); //! \~english machine->addState(timeoutState); //! \~english machine->addState(finish); //! \~english //! \~english working->setInitialState(working); //! \~english machine->setInitialState(working); //! \~english //! \~english // Add timeout transition (after 5 seconds) //! \~english working->addTimeoutTransition(timeoutState, PISystemTime::fromSeconds(5)); //! \~english //! \~english // Add transition from timeoutState to finish //! \~english timeoutState->addTransition(finish, 1); //! \~english //! \~english machine->start(); //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("With Timeout"); //! \~russian //! \~russian PIStateLambda *working = new PIStateLambda( //! \~russian []() { piCout << "Working...\n"; }, //! \~russian []() { piCout << "Stop working\n"; }, //! \~russian "Working" //! \~russian ); //! \~russian PIStateLambda *timeoutState = new PIStateLambda([]() { piCout << "Timeout occurred\n"; }, nullptr, "Timeout"); //! \~russian PIStateFinal *finish = new PIStateFinal([]() { piCout << "Done\n"; }, "Finish"); //! \~russian //! \~russian machine->addState(working); //! \~russian machine->addState(timeoutState); //! \~russian machine->addState(finish); //! \~russian //! \~russian working->setInitialState(working); //! \~russian machine->setInitialState(working); //! \~russian //! \~russian // Добавляем переход по таймауту (через 5 секунд) //! \~russian working->addTimeoutTransition(timeoutState, PISystemTime::fromSeconds(5)); //! \~russian //! \~russian // Добавляем переход из timeoutState в finish //! \~russian timeoutState->addTransition(finish, 1); //! \~russian //! \~russian machine->start(); //! \~russian ``` //! //! \~english \subsection compound_states Compound States //! \~russian \subsection compound_states Составные состояния //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("Compound States"); //! \~english //! \~english // Root state (machine) //! \~english PIStateLambda *root = new PIStateLambda([]() { piCout << "Root state\n"; }, nullptr, "Root"); //! \~english //! \~english // Compound state with substates //! \~english PIStateLambda *parent = new PIStateLambda([]() { piCout << "Parent state\n"; }, nullptr, "Parent"); //! \~english PIStateLambda *child1 = new PIStateLambda([]() { piCout << "Child 1\n"; }, nullptr, "Child1"); //! \~english PIStateLambda *child2 = new PIStateLambda([]() { piCout << "Child 2\n"; }, nullptr, "Child2"); //! \~english //! \~english parent->setInitialState(child1); //! \~english parent->addState(child1); //! \~english parent->addState(child2); //! \~english root->addState(parent); //! \~english //! \~english machine->addState(root); //! \~english machine->setInitialState(root); //! \~english //! \~english // Add transitions //! \~english root->addTransition(parent, 1); //! \~english parent->addTransition(root, 2); //! \~english //! \~english machine->start(); //! \~english //! \~english // Transition to parent //! \~english machine->postEvent(1); //! \~english //! \~english // Transition back //! \~english machine->postEvent(2); //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("Compound States"); //! \~russian //! \~russian // Корневое состояние (машина) //! \~russian PIStateLambda *root = new PIStateLambda([]() { piCout << "Root state\n"; }, nullptr, "Root"); //! \~russian //! \~russian // Составное состояние с подсостояниями //! \~russian PIStateLambda *parent = new PIStateLambda([]() { piCout << "Parent state\n"; }, nullptr, "Parent"); //! \~russian PIStateLambda *child1 = new PIStateLambda([]() { piCout << "Child 1\n"; }, nullptr, "Child1"); //! \~russian PIStateLambda *child2 = new PIStateLambda([]() { piCout << "Child 2\n"; }, nullptr, "Child2"); //! \~russian //! \~russian parent->setInitialState(child1); //! \~russian parent->addState(child1); //! \~russian parent->addState(child2); //! \~russian root->addState(parent); //! \~russian //! \~russian machine->addState(root); //! \~russian machine->setInitialState(root); //! \~russian //! \~russian // Добавляем переходы //! \~russian root->addTransition(parent, 1); //! \~russian parent->addTransition(root, 2); //! \~russian //! \~russian machine->start(); //! \~russian //! \~russian // Переход в parent //! \~russian machine->postEvent(1); //! \~russian //! \~russian // Переход обратно //! \~russian machine->postEvent(2); //! \~russian ``` //! //! \~english \subsection parallel_states Parallel States //! \~russian \subsection parallel_states Параллельные состояния //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("Parallel States"); //! \~english //! \~english PIStateLambda *root = new PIStateLambda([]() { piCout << "Root\n"; }, nullptr, "Root"); //! \~english PIStateLambda *parallel = new PIStateLambda([]() { piCout << "Parallel\n"; }, nullptr, "Parallel"); //! \~english PIStateLambda *sub1 = new PIStateLambda([]() { piCout << "Substate 1\n"; }, nullptr, "Sub1"); //! \~english PIStateLambda *sub2 = new PIStateLambda([]() { piCout << "Substate 2\n"; }, nullptr, "Sub2"); //! \~english //! \~english // Enable parallel mode //! \~english parallel->setParallel(true); //! \~english parallel->addState(sub1); //! \~english parallel->addState(sub2); //! \~english parallel->setInitialState(sub1); //! \~english root->addState(parallel); //! \~english //! \~english machine->addState(root); //! \~english machine->setInitialState(root); //! \~english //! \~english machine->start(); //! \~english //! \~english // When entering parallel, both substates are activated simultaneously //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("Parallel States"); //! \~russian //! \~russian PIStateLambda *root = new PIStateLambda([]() { piCout << "Root\n"; }, nullptr, "Root"); //! \~russian PIStateLambda *parallel = new PIStateLambda([]() { piCout << "Parallel\n"; }, nullptr, "Parallel"); //! \~russian PIStateLambda *sub1 = new PIStateLambda([]() { piCout << "Substate 1\n"; }, nullptr, "Sub1"); //! \~russian PIStateLambda *sub2 = new PIStateLambda([]() { piCout << "Substate 2\n"; }, nullptr, "Sub2"); //! \~russian //! \~russian // Включаем параллельный режим //! \~russian parallel->setParallel(true); //! \~russian parallel->addState(sub1); //! \~russian parallel->addState(sub2); //! \~russian parallel->setInitialState(sub1); //! \~russian root->addState(parallel); //! \~russian //! \~russian machine->addState(root); //! \~russian machine->setInitialState(root); //! \~russian //! \~russian machine->start(); //! \~russian //! \~russian // При входе в parallel оба подсостояния активируются одновременно //! \~russian ``` //! //! \~english \subsection transitions_with_actions Transitions with Actions //! \~russian \subsection transitions_with_actions Машина состояний с действиями //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("With Actions"); //! \~english //! \~english PIStateLambda *stateA = new PIStateLambda([]() { piCout << "State A\n"; }, nullptr, "A"); //! \~english PIStateLambda *stateB = new PIStateLambda([]() { piCout << "State B\n"; }, nullptr, "B"); //! \~english //! \~english machine->addState(stateA); //! \~english machine->addState(stateB); //! \~english //! \~english machine->setInitialState(stateA); //! \~english //! \~english // Add transition with action //! \~english auto *t = stateA->addTransition(stateB, 1); //! \~english t->addAction([]() { piCout << "Action during transition\n"; }); //! \~english //! \~english machine->start(); //! \~english machine->postEvent(1); //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("With Actions"); //! \~russian //! \~russian PIStateLambda *stateA = new PIStateLambda([]() { piCout << "State A\n"; }, nullptr, "A"); //! \~russian PIStateLambda *stateB = new PIStateLambda([]() { piCout << "State B\n"; }, nullptr, "B"); //! \~russian //! \~russian machine->addState(stateA); //! \~russian machine->addState(stateB); //! \~russian //! \~russian machine->setInitialState(stateA); //! \~russian //! \~russian // Добавляем переход с действием //! \~russian auto *t = stateA->addTransition(stateB, 1); //! \~russian t->addAction([]() { piCout << "Action during transition\n"; }); //! \~russian //! \~russian machine->start(); //! \~russian machine->postEvent(1); //! \~russian ``` //! //! \~english \section threading Thread Safety //! \~russian \section threading Потокобезопасность //! //! \~english State machine is thread-safe. The `postEvent` method uses a queue to handle nested calls, allowing safe event posting from //! different threads. //! \~russian Машина состояний PIP потокобезопасна. Метод `postEvent` использует очередь для обработки вложенных вызовов, что позволяет //! безопасно отправлять события из разных потоков. //! //! \~english \section usage_rules Usage Rules //! \~russian \section usage_rules Правила использования //! //! \~english \subsection cannot_stack Cannot Create on Stack //! \~russian \subsection cannot_stack Нельзя создавать в стеке //! //! \~english ```cpp //! \~english // ❌ WRONG //! \~english PIStateLambda state([]() {}, nullptr, "State"); //! \~english //! \~english // ✅ CORRECT //! \~english PIStateLambda *state = new PIStateLambda([]() {}, nullptr, "State"); //! \~english ``` //! \~russian ```cpp //! \~russian // ❌ НЕЛЬЗЯ //! \~russian PIStateLambda state([]() {}, nullptr, "State"); //! \~russian //! \~russian // ✅ ПРАВИЛЬНО //! \~russian PIStateLambda *state = new PIStateLambda([]() {}, nullptr, "State"); //! \~russian ``` //! //! \~english \subsection proper_hierarchy Proper Object Hierarchy //! \~russian \subsection proper_hierarchy Правильная иерархия объектов //! //! \~english ```cpp //! \~english PIStateMachine *machine = new PIStateMachine("Main"); //! \~english //! \~english // States are created via new and added to machine or another state //! \~english PIStateLambda *state1 = new PIStateLambda([]() {}, nullptr, "State1"); //! \~english PIStateLambda *state2 = new PIStateLambda([]() {}, nullptr, "State2"); //! \~english //! \~english machine->addState(state1); //! \~english machine->addState(state2); //! \~english //! \~english // Transitions are added to states via addTransition //! \~english state1->addTransition(state2, 1); //! \~english //! \~english // Machine is started //! \~english machine->start(); //! \~english ``` //! \~russian ```cpp //! \~russian PIStateMachine *machine = new PIStateMachine("Main"); //! \~russian //! \~russian // Состояния создаются через new и добавляются в машину или другое состояние //! \~russian PIStateLambda *state1 = new PIStateLambda([]() {}, nullptr, "State1"); //! \~russian PIStateLambda *state2 = new PIStateLambda([]() {}, nullptr, "State2"); //! \~russian //! \~russian machine->addState(state1); //! \~russian machine->addState(state2); //! \~russian //! \~russian // Переходы добавляются к состояниям через addTransition //! \~russian state1->addTransition(state2, 1); //! \~russian //! \~russian // Машина запускается //! \~russian machine->start(); //! \~russian ``` //! //! \~english \subsection memory_cleanup Memory Cleanup //! \~russian \subsection memory_cleanup Очистка памяти //! //! \~english All objects (states, transitions) are automatically deleted when the parent object is destroyed: //! \~russian Все объекты (состояния, переходы) автоматически удаляются при уничтожении родительского объекта: //! //! \~english - When `PIStateMachine` is destroyed, all states and transitions are deleted //! \~russian - При уничтожении `PIStateMachine` удаляются все состояния и переходы //! \~english - When `PIStateBase` is destroyed, all child states and transitions are deleted //! \~russian - При уничтожении `PIStateBase` удаляются все дочерние состояния и переходы //! //! \~english \section debugging Debugging //! \~russian \section debugging Отладка //! //! \~english For debugging, you can use the `print()` method to output the state tree: //! \~russian Для отладки можно использовать метод `print()` для вывода дерева состояний: //! //! \~english ```cpp //! \~english machine->print(); //! \~english ``` //! \~russian ```cpp //! \~russian machine->print(); //! \~russian ``` //! //! \~english Also, you can use `activeAtomics()` to get a list of active states. //! \~russian Также можно использовать `activeAtomics()` для получения списка активных состояний. //! //! \~english \section related_modules Related Modules //! \~russian \section related_modules Связанные модули //! //! \~english - \ref DateTime module for `PISystemTime` used in timeout transitions //! \~russian - \ref DateTime модуль для `PISystemTime`, используемого в переходах по таймауту //! //! \~\} #ifndef PISTATEMACHINEMODULE_H #define PISTATEMACHINEMODULE_H #include "pistatemachine.h" #include "pistatemachine_state.h" #include "pistatemachine_transition.h" #endif