diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f39e533dcb..13fe62190f 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -298,6 +298,23 @@ jobs: target: esp32s3 - path: 'components/state_machine/example' target: esp32 + # this example GENERATES its state machine from Complex.json + # at configure time, and the esp-idf image has no node + command: >- + node_major=$(node -v 2>/dev/null | sed -E "s/^v([0-9]+).*/\1/"); + if [ "${node_major:-0}" -lt 18 ]; then + apt-get update && + apt-get install -y ca-certificates curl gnupg && + install -d -m 0755 /etc/apt/keyrings && + curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | + gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg && + chmod a+r /etc/apt/keyrings/nodesource.gpg && + printf "%s\n" "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | + tee /etc/apt/sources.list.d/nodesource.list >/dev/null && + apt-get update && + apt-get install -y nodejs; + fi && + IDF_COMPONENT_MANAGER=0 idf.py build - path: 'components/stream_frame/example' target: esp32 - path: 'components/sx126x/example' diff --git a/components/state_machine/README.md b/components/state_machine/README.md index d21afa86bd..4e37745387 100644 --- a/components/state_machine/README.md +++ b/components/state_machine/README.md @@ -11,6 +11,58 @@ Note: This is a generic HFSM implementation - it should be used with generated code or a manually written state machine, as it provides no functionality on its own. +## Generating a state machine + +`state_machine` is the runtime; the machines themselves are generated +from a model by [webgme-hfsm][repo]. You can model and generate one +entirely in the browser — no install, no server — with the +[**HFSM Playground**][playground], or from the command line: + +```sh +npx -y -p webgme-hfsm@^1.8.0 hfsm-gen my_machine.json -o generated +``` + +(`-y` skips npx's install prompt for non-interactive/CI use; the `@^1.8.0` +pin matches the example's CMake so generation is reproducible.) + +### Generating from your own CMake + +This component provides `espp_generate_hfsm()`, so any component can turn a +model into C++ at configure time: + +```cmake +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + espp_generate_hfsm( + MODEL "${CMAKE_CURRENT_LIST_DIR}/my_machine.json" + OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/hfsm" + SOURCES_VAR hfsm_srcs + INCLUDE_DIR_VAR hfsm_inc) +endif() + +idf_component_register(SRCS "main.cpp" ${hfsm_srcs} + INCLUDE_DIRS "." ${hfsm_inc}) +``` + +The guard is needed because ESP-IDF does not load a component's +`project_include.cmake` during its early requirements pass — and that pass +does not read `SRCS` either, so the empty variables are what it expects. + +It regenerates whenever the model changes, finds the generated file names +rather than making you name them, and leaves out the shared runtime this +component already provides (pass `WITH_SUPPORT` if you want the generator's +copies instead). `NAMESPACE` overrides the model's own. + +Requires **node >= 18**; `npx` fetches the generator. Set +`-DESPP_HFSM_GEN_COMMAND="node;/path/to/webgme-hfsm/bin/hfsm-gen.js"` to use a +local checkout, which is also how to build offline. + +The example uses exactly this, so its C++ is generated at build time from +[`Complex.json`](example/main/Complex.json) rather than checked in — see +[the example README](example/README.md). + +[repo]: https://github.com/finger563/webgme-hfsm +[playground]: https://finger563.github.io/webgme-hfsm/ + ## Example This example shows an example of running the below HFSM on an ESP32 in a diff --git a/components/state_machine/example/README.md b/components/state_machine/example/README.md index a4b9243e20..2c4258cedb 100644 --- a/components/state_machine/example/README.md +++ b/components/state_machine/example/README.md @@ -8,6 +8,51 @@ CLI to manually spawn events and trace the execution). For more information, see ![hfsm](https://user-images.githubusercontent.com/213467/230950083-d4d8a483-31a7-43ac-8822-b1e28d552984.png) +## The state machine is generated, not checked in + +The HFSM's C++ is generated from [`main/Complex.json`](main/Complex.json) +every time the example is configured. The model is the source; the C++ is +a build product, like an object file. + +The generation is one call to `espp_generate_hfsm()`, provided by the +`state_machine` component — see its README to use it from your own +component. + +This needs **node (>= 18)** on your PATH — nothing else, and nothing to +install by hand. `npx` fetches the generator on demand: + +``` +idf.py build # generates main/Complex.json -> build/.../hfsm/, then builds +``` + +Editing the model regenerates on the next build; you do not need to clean. + +Only the machine itself is generated. The shared runtime it builds on +— `state_base.hpp`, the history states, `magic_enum.hpp` — comes from +this component, via the generator's `--no-support` flag; espp's copies +are the ones the rest of the codebase is built against. + +To edit the machine, open it in the **[HFSM Playground][playground]** — a +browser-based editor and code generator, no install and no server. Load +`main/Complex.json` with **Open file…**, or jump straight to this +example's machine: + +[**Open this example's HFSM in the playground**][this-model] + +Save the edited model back over `main/Complex.json` and rebuild. + +If you are working on the generator itself, point the build at your +checkout instead of npx: + +``` +idf.py -DESPP_HFSM_GEN_COMMAND="node;/path/to/webgme-hfsm/bin/hfsm-gen.js" build +``` + +The same flag is the way to build without network access. + +[playground]: https://finger563.github.io/webgme-hfsm/ +[this-model]: https://finger563.github.io/webgme-hfsm/?example=Complex&view=diagram + ## How to use example ### Build and Flash diff --git a/components/state_machine/example/main/CMakeLists.txt b/components/state_machine/example/main/CMakeLists.txt index a941e22ba7..db2a334ba1 100644 --- a/components/state_machine/example/main/CMakeLists.txt +++ b/components/state_machine/example/main/CMakeLists.txt @@ -1,2 +1,19 @@ -idf_component_register(SRC_DIRS "." - INCLUDE_DIRS ".") +# The HFSM's C++ is GENERATED from Complex.json, not checked in: the +# model is the source, the C++ is a build product. +# +# espp_generate_hfsm comes from the state_machine component's +# project_include.cmake. ESP-IDF does not load those during its early +# requirements pass, so the call is guarded -- SRCS and INCLUDE_DIRS +# are not read in that pass either, and the empty variables below are +# what it expects to see. +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + espp_generate_hfsm( + MODEL "${CMAKE_CURRENT_LIST_DIR}/Complex.json" + OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/hfsm" + SOURCES_VAR hfsm_srcs + INCLUDE_DIR_VAR hfsm_inc) +endif() + +idf_component_register( + SRCS "hfsm_example.cpp" ${hfsm_srcs} + INCLUDE_DIRS "." ${hfsm_inc}) diff --git a/components/state_machine/example/main/Complex.json b/components/state_machine/example/main/Complex.json new file mode 100644 index 0000000000..8bcd1f68fc --- /dev/null +++ b/components/state_machine/example/main/Complex.json @@ -0,0 +1,707 @@ +{ + "root": "/c", + "namespace": "espp::state_machine", + "objects": { + "/c": { + "name": "Complex", + "type": "State Machine", + "position": { + "x": 450, + "y": 238 + }, + "Declarations": "bool goToEnd = false;\nbool goToChoice = true;\nbool goToHistory = false;\nbool nextState = false;\nbool killedState = false;\nbool someGuard = true;\nbool someTest = true;\n\nint someNumber = 40;\nint someValue = 50;", + "Includes": "#include " + }, + "/c/3": { + "name": "EVENT1", + "type": "Event", + "position": { + "x": 100, + "y": 100 + } + }, + "/c/3/a": { + "name": "last_time", + "type": "Field", + "position": { + "x": 100, + "y": 100 + }, + "Default": "0" + }, + "/c/A": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "pointers": { + "dst": "/c/G", + "src": "/c/T" + } + }, + "/c/C": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT3", + "pointers": { + "dst": "/c/v/G", + "src": "/c/T" + } + }, + "/c/E": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT2", + "pointers": { + "dst": "/c/T", + "src": "/c/v" + } + }, + "/c/F": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "pointers": { + "dst": "/c/G", + "src": "/c/v" + } + }, + "/c/G": { + "name": "End State", + "type": "End State", + "position": { + "x": 457, + "y": 665 + } + }, + "/c/I": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 343, + "y": 189 + }, + "Event": "EVENT4", + "Guard": "someTest", + "pointers": { + "dst": "/c/X", + "src": "/c/Y" + } + }, + "/c/L": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "ENDEVENT", + "pointers": { + "dst": "/c/Y", + "src": "/c/T" + } + }, + "/c/Q": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT4", + "pointers": { + "dst": "/c/T/o", + "src": "/c/v" + } + }, + "/c/T": { + "name": "State3", + "type": "State", + "position": { + "x": 596, + "y": 481 + } + }, + "/c/T/0": { + "name": "ChildState2", + "type": "State", + "position": { + "x": 617, + "y": 504 + }, + "Timer Period": 0.1 + }, + "/c/T/A": { + "name": "Shallow History Pseudostate", + "type": "Shallow History Pseudostate", + "position": { + "x": 495, + "y": 404 + } + }, + "/c/T/I": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "pointers": { + "dst": "/c/T/W", + "src": "/c/T/v" + } + }, + "/c/T/L": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT1", + "pointers": { + "dst": "/c/T/0", + "src": "/c/T/W" + } + }, + "/c/T/W": { + "name": "ChildState", + "type": "State", + "position": { + "x": 564, + "y": 433 + }, + "Timer Period": 0.1 + }, + "/c/T/h": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "ENDEVENT", + "pointers": { + "dst": "/c/T/z", + "src": "/c/T/0" + } + }, + "/c/T/j": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT2", + "pointers": { + "dst": "/c/T/w", + "src": "/c/T/0" + } + }, + "/c/T/o": { + "name": "Deep History Pseudostate", + "type": "Deep History Pseudostate", + "position": { + "x": 510, + "y": 422 + } + }, + "/c/T/p": { + "name": "External Transition", + "type": "External Transition", + "position": { + "x": 100, + "y": 100 + }, + "Event": "EVENT3", + "pointers": { + "dst": "/c/T/W", + "src": "/c/T/w" + } + }, + "/c/T/v": { + "name": "Initial", + "type": "Initial", + "position": { + "x": 527, + "y": 431 + } + }, + "/c/T/w": { + "name": "ChildState3", + "type": "State", + "position": { + "x": 677, + "y": 429 + }, + "Timer Period": 0.1 + }, + "/c/T/z": { + "name": "End State", + "type": "End State", + "position": { + "x": 618, + "y": 557 + } + }, + "/c/X": { + "name": "Choice Pseudostate", + "type": "Choice Pseudostate", + "position": { + "x": 495, + "y": 298 + } + }, + "/c/Y": { + "name": "State 1", + "type": "State", + "position": { + "x": 583, + "y": 221 + }, + "Entry": "printf(\"SerialTask :: initializing State 1\\n\");", + "Exit": "printf(\"Exiting State 1\\n\");", + "Tick": "printf(\"SerialTask::State 1::tick()\\n\");", + "Timer Period": 0.1 + }, + "/c/Y/X": { + "name": "Internal Transition", + "type": "Internal Transition", + "position": { + "x": 511, + "y": 229 + }, + "Event": "EVENT2", + "Guard": "someNumber > someValue" + }, + "/c/Y/t": { + "name": "Internal Transition", + "type": "Internal Transition", + "position": { + "x": 511, + "y": 214 + }, + "Action": "int testVal = 32;\nfor (int i=0; ilog("\033[36mTRANSITION::ACTION for /c/m\033[0m"); - - //::::/c/m::::Action:::: - - // State : entry for: /c/Y - _root->COMPLEX_OBJ__STATE_1_OBJ.entry(); - - // initialize our new active state - _root->COMPLEX_OBJ__STATE_1_OBJ.initialize(); -}; - -void Root::handle_all_events(void) { - GeneratedEventBase *e; - // get the next event and check if it's nullptr - while ((e = event_factory.get_next_event())) { - [[maybe_unused]] bool did_handle = handleEvent(e); - log("\033[0mHANDLED " + e->to_string() + (did_handle ? ": \033[32mtrue" : ": \033[31mfalse") + - "\033[0m"); - // free the memory that was allocated when it was spawned - consume_event(e); - } -} - -void Root::terminate(void) { - // will call exit() and exitChildren() on _activeState if it - // exists - exitChildren(); -}; - -void Root::restart(void) { - terminate(); - initialize(); -}; - -bool Root::has_stopped(void) { - bool reachedEnd = false; - // Get the currently active leaf state - const StateBase *activeLeaf = getActiveLeaf(); - if (activeLeaf != nullptr && activeLeaf != this && - activeLeaf == static_cast(&_root->COMPLEX_OBJ__END_STATE_OBJ)) { - reachedEnd = true; - } - return reachedEnd; -}; - -bool Root::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // Get the currently active leaf state - StateBase *activeLeaf = getActiveLeaf(); - - if (activeLeaf != nullptr && activeLeaf != this) { - // have the active leaf handle the event, this will bubble up until - // the event is handled or it reaches the root. - handled = activeLeaf->handleEvent(event); - } - - return handled; -} - -/* * * Definitions for State_1 : /c/Y * * */ - -// User Definitions for the HFSM -//::::/c/Y::::Definitions:::: - -void Root::State_1::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State_1::entry(void) { - _root->log("\033[36mENTRY::State_1::/c/Y\033[0m"); - // Entry action for this state - //::::/c/Y::::Entry:::: - [[maybe_unused]] int a = 2; - printf("SerialTask :: initializing State 1\n"); -} - -void Root::State_1::exit(void) { - _root->log("\033[36mEXIT::State_1::/c/Y\033[0m"); - // Call the Exit Action for this state - //::::/c/Y::::Exit:::: - printf("Exiting State 1\n"); -} - -void Root::State_1::tick(void) { - _root->log("\033[36mTICK::State_1::/c/Y\033[0m"); - // Call the Tick Action for this state - //::::/c/Y::::Tick:::: - printf("SerialTask::State 1::tick()\n"); - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_1::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State_1::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - case EventType::EVENT3: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - case EventType::EVENT1: - if (false) { // makes generation easier :) - } - //::::/c/Y/t::::Guard:::: - else if (_root->someNumber < _root->someValue) { - _root->log("\033[37mGUARD [ _root->someNumber < _root->someValue ] for INTERNAL " - "TRANSITION:/c/Y/t evaluated to TRUE\033[0m"); - // run transition action - //::::/c/Y/t::::Action:::: - int testVal = 32; - for (int i = 0; i < testVal; i++) { - printf("Action iterating: %d\n", i); - } - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT2: - if (false) { // makes generation easier :) - } - //::::/c/Y/X::::Guard:::: - else if (_root->someNumber > _root->someValue) { - _root->log("\033[37mGUARD [ _root->someNumber > _root->someValue ] for INTERNAL " - "TRANSITION:/c/Y/X evaluated to TRUE\033[0m"); - // run transition action - //::::/c/Y/X::::Action:::: - - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT4: - if (false) { - } // makes generation easier :) - //::::/c/I::::Guard:::: - else if (_root->someTest) { - _root->log("\033[37mGUARD [ _root->someTest ] for EXTERNAL TRANSITION:/c/I evaluated to " - "TRUE\033[0m"); - // Going into a choice pseudo-state, let it handle its - // guards and perform the state transition - if (false) { - } // makes geneeration easier :) - //::::/c/h::::Guard:::: - else if (_root->goToHistory) { - _root->log("\033[37mGUARD [ _root->goToHistory ] for EXTERNAL TRANSITION:/c/h evaluated " - "to TRUE\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_1_OBJ.exitChildren(); - // State : exit for: /c/Y - _root->COMPLEX_OBJ__STATE_1_OBJ.exit(); - // External Transition : Action for: /c/I - _root->log("\033[36mTRANSITION::ACTION for /c/I\033[0m"); - - //::::/c/I::::Action:::: - - // External Transition : Action for: /c/h - _root->log("\033[36mTRANSITION::ACTION for /c/h\033[0m"); - - //::::/c/h::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log( - "\033[31mSTATE TRANSITION: State_1->State3::Shallow_History_Pseudostate\033[0m"); - - // going into shallow history pseudo-state - _root->COMPLEX_OBJ__STATE3_OBJ.setShallowHistory(); - // make sure nothing else handles this event - handled = true; - } - //::::/c/k::::Guard:::: - else if (_root->nextState) { - _root->log("\033[37mGUARD [ _root->nextState ] for EXTERNAL TRANSITION:/c/k evaluated to " - "TRUE\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_1_OBJ.exitChildren(); - // State : exit for: /c/Y - _root->COMPLEX_OBJ__STATE_1_OBJ.exit(); - // External Transition : Action for: /c/I - _root->log("\033[36mTRANSITION::ACTION for /c/I\033[0m"); - - //::::/c/I::::Action:::: - - // External Transition : Action for: /c/k - _root->log("\033[36mTRANSITION::ACTION for /c/k\033[0m"); - - //::::/c/k::::Action:::: - - // State : entry for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_1->State_2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/r\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_1_OBJ.exitChildren(); - // State : exit for: /c/Y - _root->COMPLEX_OBJ__STATE_1_OBJ.exit(); - // External Transition : Action for: /c/I - _root->log("\033[36mTRANSITION::ACTION for /c/I\033[0m"); - - //::::/c/I::::Action:::: - - // External Transition : Action for: /c/r - _root->log("\033[36mTRANSITION::ACTION for /c/r\033[0m"); - - //::::/c/r::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_1->State3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - } - break; - default: - handled = false; - break; - } - } - // can't buble up, we are a root state. - return handled; -} -/* * * Definitions for State_2 : /c/v * * */ - -// User Definitions for the HFSM -//::::/c/v::::Definitions:::: - -void Root::State_2::initialize(void) { - // External Transition : Action for: /c/v/u - _root->log("\033[36mTRANSITION::ACTION for /c/v/u\033[0m"); - - //::::/c/v/u::::Action:::: - - // State : entry for: /c/v/K - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.entry(); - - // initialize our new active state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.initialize(); -} - -void Root::State_2::entry(void) { - _root->log("\033[36mENTRY::State_2::/c/v\033[0m"); - // Entry action for this state - //::::/c/v::::Entry:::: -} - -void Root::State_2::exit(void) { - _root->log("\033[36mEXIT::State_2::/c/v\033[0m"); - // Call the Exit Action for this state - //::::/c/v::::Exit:::: -} - -void Root::State_2::tick(void) { - _root->log("\033[36mTICK::State_2::/c/v\033[0m"); - // Call the Tick Action for this state - //::::/c/v::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::getTimerPeriod(void) { return (double)(0); } - -bool Root::State_2::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT4: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/Q\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ.exitChildren(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/Q - _root->log("\033[36mTRANSITION::ACTION for /c/Q\033[0m"); - - //::::/c/Q::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2->State3::Deep_History_Pseudostate\033[0m"); - - // going into deep history pseudo-state - _root->COMPLEX_OBJ__STATE3_OBJ.setDeepHistory(); - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT2: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/E\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ.exitChildren(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/E - _root->log("\033[36mTRANSITION::ACTION for /c/E\033[0m"); - - //::::/c/E::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2->State3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT3: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/t\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ.exitChildren(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/t - _root->log("\033[36mTRANSITION::ACTION for /c/t\033[0m"); - - //::::/c/t::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2->State3::Shallow_History_Pseudostate\033[0m"); - - // going into shallow history pseudo-state - _root->COMPLEX_OBJ__STATE3_OBJ.setShallowHistory(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - // can't buble up, we are a root state. - return handled; -} -/* * * Definitions for State_2::ChildState : /c/v/K * * */ - -// User Definitions for the HFSM -//::::/c/v/K::::Definitions:::: - -void Root::State_2::ChildState::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State_2::ChildState::entry(void) { - _root->log("\033[36mENTRY::State_2::ChildState::/c/v/K\033[0m"); - // Entry action for this state - //::::/c/v/K::::Entry:::: -} - -void Root::State_2::ChildState::exit(void) { - _root->log("\033[36mEXIT::State_2::ChildState::/c/v/K\033[0m"); - // Call the Exit Action for this state - //::::/c/v/K::::Exit:::: -} - -void Root::State_2::ChildState::tick(void) { - _root->log("\033[36mTICK::State_2::ChildState::/c/v/K\033[0m"); - // Call the Tick Action for this state - //::::/c/v/K::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::ChildState::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State_2::ChildState::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT1: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/S\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.exitChildren(); - // State : exit for: /c/v/K - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.exit(); - // External Transition : Action for: /c/v/S - _root->log("\033[36mTRANSITION::ACTION for /c/v/S\033[0m"); - - //::::/c/v/S::::Action:::: - - // State : entry for: /c/v/e - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2::ChildState->State_2::ChildState2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State_2::ChildState2 : /c/v/e * * */ - -// User Definitions for the HFSM -//::::/c/v/e::::Definitions:::: - -void Root::State_2::ChildState2::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State_2::ChildState2::entry(void) { - _root->log("\033[36mENTRY::State_2::ChildState2::/c/v/e\033[0m"); - // Entry action for this state - //::::/c/v/e::::Entry:::: -} - -void Root::State_2::ChildState2::exit(void) { - _root->log("\033[36mEXIT::State_2::ChildState2::/c/v/e\033[0m"); - // Call the Exit Action for this state - //::::/c/v/e::::Exit:::: -} - -void Root::State_2::ChildState2::tick(void) { - _root->log("\033[36mTICK::State_2::ChildState2::/c/v/e\033[0m"); - // Call the Tick Action for this state - //::::/c/v/e::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::ChildState2::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State_2::ChildState2::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT2: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/W\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ.exitChildren(); - // State : exit for: /c/v/e - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ.exit(); - // External Transition : Action for: /c/v/W - _root->log("\033[36mTRANSITION::ACTION for /c/v/W\033[0m"); - - //::::/c/v/W::::Action:::: - - // State : entry for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2::ChildState2->State_2::ChildState3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State_2::ChildState3 : /c/v/z * * */ - -// User Definitions for the HFSM -//::::/c/v/z::::Definitions:::: - -void Root::State_2::ChildState3::initialize(void) { - // External Transition : Action for: /c/v/z/8 - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/8\033[0m"); - - //::::/c/v/z/8::::Action:::: - - // State : entry for: /c/v/z/6 - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.entry(); - - // initialize our new active state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.initialize(); -} - -void Root::State_2::ChildState3::entry(void) { - _root->log("\033[36mENTRY::State_2::ChildState3::/c/v/z\033[0m"); - // Entry action for this state - //::::/c/v/z::::Entry:::: -} - -void Root::State_2::ChildState3::exit(void) { - _root->log("\033[36mEXIT::State_2::ChildState3::/c/v/z\033[0m"); - // Call the Exit Action for this state - //::::/c/v/z::::Exit:::: -} - -void Root::State_2::ChildState3::tick(void) { - _root->log("\033[36mTICK::State_2::ChildState3::/c/v/z\033[0m"); - // Call the Tick Action for this state - //::::/c/v/z::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::ChildState3::getTimerPeriod(void) { return (double)(0); } - -bool Root::State_2::ChildState3::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT3: - if (false) { - } // makes generation easier :) - //::::/c/v/P::::Guard:::: - else if (_root->someGuard) { - _root->log("\033[37mGUARD [ _root->someGuard ] for EXTERNAL TRANSITION:/c/v/P evaluated to " - "TRUE\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exitChildren(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // External Transition : Action for: /c/v/P - _root->log("\033[36mTRANSITION::ACTION for /c/v/P\033[0m"); - - //::::/c/v/P::::Action:::: - - // State : entry for: /c/v/K - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2::ChildState3->State_2::ChildState\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State_2::ChildState3::Grand : /c/v/z/6 * * */ - -// User Definitions for the HFSM -//::::/c/v/z/6::::Definitions:::: - -void Root::State_2::ChildState3::Grand::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State_2::ChildState3::Grand::entry(void) { - _root->log("\033[36mENTRY::State_2::ChildState3::Grand::/c/v/z/6\033[0m"); - // Entry action for this state - //::::/c/v/z/6::::Entry:::: -} - -void Root::State_2::ChildState3::Grand::exit(void) { - _root->log("\033[36mEXIT::State_2::ChildState3::Grand::/c/v/z/6\033[0m"); - // Call the Exit Action for this state - //::::/c/v/z/6::::Exit:::: -} - -void Root::State_2::ChildState3::Grand::tick(void) { - _root->log("\033[36mTICK::State_2::ChildState3::Grand::/c/v/z/6\033[0m"); - // Call the Tick Action for this state - //::::/c/v/z/6::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::ChildState3::Grand::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State_2::ChildState3::Grand::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::ENDEVENT: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT1: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/z/z\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.exitChildren(); - // State : exit for: /c/v/z/6 - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.exit(); - // External Transition : Action for: /c/v/z/z - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/z\033[0m"); - - //::::/c/v/z/z::::Action:::: - - // State : entry for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand->State_2::ChildState3::Grand2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State_2::ChildState3::Grand2 : /c/v/z/c * * */ - -// User Definitions for the HFSM -//::::/c/v/z/c::::Definitions:::: - -void Root::State_2::ChildState3::Grand2::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State_2::ChildState3::Grand2::entry(void) { - _root->log("\033[36mENTRY::State_2::ChildState3::Grand2::/c/v/z/c\033[0m"); - // Entry action for this state - //::::/c/v/z/c::::Entry:::: -} - -void Root::State_2::ChildState3::Grand2::exit(void) { - _root->log("\033[36mEXIT::State_2::ChildState3::Grand2::/c/v/z/c\033[0m"); - // Call the Exit Action for this state - //::::/c/v/z/c::::Exit:::: -} - -void Root::State_2::ChildState3::Grand2::tick(void) { - _root->log("\033[36mTICK::State_2::ChildState3::Grand2::/c/v/z/c\033[0m"); - // Call the Tick Action for this state - //::::/c/v/z/c::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State_2::ChildState3::Grand2::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State_2::ChildState3::Grand2::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::ENDEVENT: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/z/9\033[0m"); - // Going into an end pseudo-state that is not the root end state, - // follow its parent end transition - if (false) { - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/F\033[0m"); - // Going into a choice pseudo-state, let it handle its - // guards and perform the state transition - if (false) { - } // makes geneeration easier :) - //::::/c/v/g::::Guard:::: - else if (_root->killedState) { - _root->log("\033[37mGUARD [ _root->killedState ] for EXTERNAL TRANSITION:/c/v/g " - "evaluated to TRUE\033[0m"); - // Going into an end pseudo-state that is not the root end state, - // follow its parent end transition - if (false) { - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/F\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/v/z/9 - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/9\033[0m"); - - //::::/c/v/z/9::::Action:::: - - // External Transition : Action for: /c/v/F - _root->log("\033[36mTRANSITION::ACTION for /c/v/F\033[0m"); - - //::::/c/v/F::::Action:::: - - // External Transition : Action for: /c/v/g - _root->log("\033[36mTRANSITION::ACTION for /c/v/g\033[0m"); - - //::::/c/v/g::::Action:::: - - // External Transition : Action for: /c/F - _root->log("\033[36mTRANSITION::ACTION for /c/F\033[0m"); - - //::::/c/F::::Action:::: - - _root->log( - "\033[31mSTATE TRANSITION: State_2::ChildState3::Grand2->End_State\033[0m"); - - // going into end pseudo-state THIS SHOULD BE TOP LEVEL END STATE - _root->COMPLEX_OBJ__END_STATE_OBJ.makeActive(); - // make sure nothing else handles this event - handled = true; - } - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/2\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // External Transition : Action for: /c/v/z/9 - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/9\033[0m"); - - //::::/c/v/z/9::::Action:::: - - // External Transition : Action for: /c/v/F - _root->log("\033[36mTRANSITION::ACTION for /c/v/F\033[0m"); - - //::::/c/v/F::::Action:::: - - // External Transition : Action for: /c/v/2 - _root->log("\033[36mTRANSITION::ACTION for /c/v/2\033[0m"); - - //::::/c/v/2::::Action:::: - - // State : entry for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand2->State_2::ChildState3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - } - } - break; - case EventType::EVENT2: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/z/R\033[0m"); - // Going into a choice pseudo-state, let it handle its - // guards and perform the state transition - if (false) { - } // makes geneeration easier :) - //::::/c/v/z/j::::Guard:::: - else if (_root->goToEnd) { - _root->log("\033[37mGUARD [ _root->goToEnd ] for EXTERNAL TRANSITION:/c/v/z/j evaluated " - "to TRUE\033[0m"); - // Going into an end pseudo-state that is not the root end state, - // follow its parent end transition - if (false) { - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/F\033[0m"); - // Going into a choice pseudo-state, let it handle its - // guards and perform the state transition - if (false) { - } // makes geneeration easier :) - //::::/c/v/g::::Guard:::: - else if (_root->killedState) { - _root->log("\033[37mGUARD [ _root->killedState ] for EXTERNAL TRANSITION:/c/v/g " - "evaluated to TRUE\033[0m"); - // Going into an end pseudo-state that is not the root end state, - // follow its parent end transition - if (false) { - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/F\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/j - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/j\033[0m"); - - //::::/c/v/z/j::::Action:::: - - // External Transition : Action for: /c/v/F - _root->log("\033[36mTRANSITION::ACTION for /c/v/F\033[0m"); - - //::::/c/v/F::::Action:::: - - // External Transition : Action for: /c/v/g - _root->log("\033[36mTRANSITION::ACTION for /c/v/g\033[0m"); - - //::::/c/v/g::::Action:::: - - // External Transition : Action for: /c/F - _root->log("\033[36mTRANSITION::ACTION for /c/F\033[0m"); - - //::::/c/F::::Action:::: - - _root->log( - "\033[31mSTATE TRANSITION: State_2::ChildState3::Grand2->End_State\033[0m"); - - // going into end pseudo-state THIS SHOULD BE TOP LEVEL END STATE - _root->COMPLEX_OBJ__END_STATE_OBJ.makeActive(); - // make sure nothing else handles this event - handled = true; - } - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/2\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/j - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/j\033[0m"); - - //::::/c/v/z/j::::Action:::: - - // External Transition : Action for: /c/v/F - _root->log("\033[36mTRANSITION::ACTION for /c/v/F\033[0m"); - - //::::/c/v/F::::Action:::: - - // External Transition : Action for: /c/v/2 - _root->log("\033[36mTRANSITION::ACTION for /c/v/2\033[0m"); - - //::::/c/v/2::::Action:::: - - // State : entry for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand2->State_2::ChildState3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - } - } - //::::/c/v/z/g::::Guard:::: - else if (_root->goToChoice) { - _root->log("\033[37mGUARD [ _root->goToChoice ] for EXTERNAL TRANSITION:/c/v/z/g " - "evaluated to TRUE\033[0m"); - // Going into a choice pseudo-state, let it handle its - // guards and perform the state transition - if (false) { - } // makes geneeration easier :) - //::::/c/h::::Guard:::: - else if (_root->goToHistory) { - _root->log("\033[37mGUARD [ _root->goToHistory ] for EXTERNAL TRANSITION:/c/h " - "evaluated to TRUE\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/g - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/g\033[0m"); - - //::::/c/v/z/g::::Action:::: - - // External Transition : Action for: /c/h - _root->log("\033[36mTRANSITION::ACTION for /c/h\033[0m"); - - //::::/c/h::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand2->State3::Shallow_History_Pseudostate\033[0m"); - - // going into shallow history pseudo-state - _root->COMPLEX_OBJ__STATE3_OBJ.setShallowHistory(); - // make sure nothing else handles this event - handled = true; - } - //::::/c/k::::Guard:::: - else if (_root->nextState) { - _root->log("\033[37mGUARD [ _root->nextState ] for EXTERNAL TRANSITION:/c/k evaluated " - "to TRUE\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/g - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/g\033[0m"); - - //::::/c/v/z/g::::Action:::: - - // External Transition : Action for: /c/k - _root->log("\033[36mTRANSITION::ACTION for /c/k\033[0m"); - - //::::/c/k::::Action:::: - - // State : entry for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2::ChildState3::Grand2->State_2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/r\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // State : exit for: /c/v/z - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ.exit(); - // State : exit for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/g - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/g\033[0m"); - - //::::/c/v/z/g::::Action:::: - - // External Transition : Action for: /c/r - _root->log("\033[36mTRANSITION::ACTION for /c/r\033[0m"); - - //::::/c/r::::Action:::: - - // State : entry for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State_2::ChildState3::Grand2->State3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/z/O\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // External Transition : Action for: /c/v/z/R - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/R\033[0m"); - - //::::/c/v/z/R::::Action:::: - - // External Transition : Action for: /c/v/z/O - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/O\033[0m"); - - //::::/c/v/z/O::::Action:::: - - // State : entry for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand2->State_2::ChildState3::Grand2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - } - break; - case EventType::EVENT1: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/v/z/a\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exitChildren(); - // State : exit for: /c/v/z/c - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ.exit(); - // External Transition : Action for: /c/v/z/a - _root->log("\033[36mTRANSITION::ACTION for /c/v/z/a\033[0m"); - - //::::/c/v/z/a::::Action:::: - - // State : entry for: /c/v/z/6 - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: " - "State_2::ChildState3::Grand2->State_2::ChildState3::Grand\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State3 : /c/T * * */ - -// User Definitions for the HFSM -//::::/c/T::::Definitions:::: - -void Root::State3::initialize(void) { - // External Transition : Action for: /c/T/I - _root->log("\033[36mTRANSITION::ACTION for /c/T/I\033[0m"); - - //::::/c/T/I::::Action:::: - - // State : entry for: /c/T/W - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.entry(); - - // initialize our new active state - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.initialize(); -} - -void Root::State3::entry(void) { - _root->log("\033[36mENTRY::State3::/c/T\033[0m"); - // Entry action for this state - //::::/c/T::::Entry:::: -} - -void Root::State3::exit(void) { - _root->log("\033[36mEXIT::State3::/c/T\033[0m"); - // Call the Exit Action for this state - //::::/c/T::::Exit:::: -} - -void Root::State3::tick(void) { - _root->log("\033[36mTICK::State3::/c/T\033[0m"); - // Call the Tick Action for this state - //::::/c/T::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State3::getTimerPeriod(void) { return (double)(0); } - -bool Root::State3::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::ENDEVENT: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/L\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ.exitChildren(); - // State : exit for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.exit(); - // External Transition : Action for: /c/L - _root->log("\033[36mTRANSITION::ACTION for /c/L\033[0m"); - - //::::/c/L::::Action:::: - - // State : entry for: /c/Y - _root->COMPLEX_OBJ__STATE_1_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3->State_1\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_1_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT2: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/z\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ.exitChildren(); - // State : exit for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.exit(); - // External Transition : Action for: /c/z - _root->log("\033[36mTRANSITION::ACTION for /c/z\033[0m"); - - //::::/c/z::::Action:::: - - // State : entry for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3->State_2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE_2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT4: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/w\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ.exitChildren(); - // State : exit for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.exit(); - // External Transition : Action for: /c/w - _root->log("\033[36mTRANSITION::ACTION for /c/w\033[0m"); - - //::::/c/w::::Action:::: - - // State : entry for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3->State_2::Deep_History_Pseudostate\033[0m"); - - // going into deep history pseudo-state - _root->COMPLEX_OBJ__STATE_2_OBJ.setDeepHistory(); - // make sure nothing else handles this event - handled = true; - } - break; - case EventType::EVENT3: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/C\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ.exitChildren(); - // State : exit for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.exit(); - // External Transition : Action for: /c/C - _root->log("\033[36mTRANSITION::ACTION for /c/C\033[0m"); - - //::::/c/C::::Action:::: - - // State : entry for: /c/v - _root->COMPLEX_OBJ__STATE_2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3->State_2::Shallow_History_Pseudostate\033[0m"); - - // going into shallow history pseudo-state - _root->COMPLEX_OBJ__STATE_2_OBJ.setShallowHistory(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - // can't buble up, we are a root state. - return handled; -} -/* * * Definitions for State3::ChildState2 : /c/T/0 * * */ - -// User Definitions for the HFSM -//::::/c/T/0::::Definitions:::: - -void Root::State3::ChildState2::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State3::ChildState2::entry(void) { - _root->log("\033[36mENTRY::State3::ChildState2::/c/T/0\033[0m"); - // Entry action for this state - //::::/c/T/0::::Entry:::: -} - -void Root::State3::ChildState2::exit(void) { - _root->log("\033[36mEXIT::State3::ChildState2::/c/T/0\033[0m"); - // Call the Exit Action for this state - //::::/c/T/0::::Exit:::: -} - -void Root::State3::ChildState2::tick(void) { - _root->log("\033[36mTICK::State3::ChildState2::/c/T/0\033[0m"); - // Call the Tick Action for this state - //::::/c/T/0::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State3::ChildState2::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State3::ChildState2::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::ENDEVENT: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/T/h\033[0m"); - // Going into an end pseudo-state that is not the root end state, - // follow its parent end transition - if (false) { - } else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/A\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.exitChildren(); - // State : exit for: /c/T/0 - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.exit(); - // State : exit for: /c/T - _root->COMPLEX_OBJ__STATE3_OBJ.exit(); - // External Transition : Action for: /c/T/h - _root->log("\033[36mTRANSITION::ACTION for /c/T/h\033[0m"); - - //::::/c/T/h::::Action:::: - - // External Transition : Action for: /c/A - _root->log("\033[36mTRANSITION::ACTION for /c/A\033[0m"); - - //::::/c/A::::Action:::: - - _root->log("\033[31mSTATE TRANSITION: State3::ChildState2->End_State\033[0m"); - - // going into end pseudo-state THIS SHOULD BE TOP LEVEL END STATE - _root->COMPLEX_OBJ__END_STATE_OBJ.makeActive(); - // make sure nothing else handles this event - handled = true; - } - } - break; - case EventType::EVENT2: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/T/j\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.exitChildren(); - // State : exit for: /c/T/0 - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.exit(); - // External Transition : Action for: /c/T/j - _root->log("\033[36mTRANSITION::ACTION for /c/T/j\033[0m"); - - //::::/c/T/j::::Action:::: - - // State : entry for: /c/T/w - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3::ChildState2->State3::ChildState3\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State3::ChildState : /c/T/W * * */ - -// User Definitions for the HFSM -//::::/c/T/W::::Definitions:::: - -void Root::State3::ChildState::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State3::ChildState::entry(void) { - _root->log("\033[36mENTRY::State3::ChildState::/c/T/W\033[0m"); - // Entry action for this state - //::::/c/T/W::::Entry:::: -} - -void Root::State3::ChildState::exit(void) { - _root->log("\033[36mEXIT::State3::ChildState::/c/T/W\033[0m"); - // Call the Exit Action for this state - //::::/c/T/W::::Exit:::: -} - -void Root::State3::ChildState::tick(void) { - _root->log("\033[36mTICK::State3::ChildState::/c/T/W\033[0m"); - // Call the Tick Action for this state - //::::/c/T/W::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State3::ChildState::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State3::ChildState::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT1: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/T/L\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.exitChildren(); - // State : exit for: /c/T/W - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.exit(); - // External Transition : Action for: /c/T/L - _root->log("\033[36mTRANSITION::ACTION for /c/T/L\033[0m"); - - //::::/c/T/L::::Action:::: - - // State : entry for: /c/T/0 - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3::ChildState->State3::ChildState2\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} -/* * * Definitions for State3::ChildState3 : /c/T/w * * */ - -// User Definitions for the HFSM -//::::/c/T/w::::Definitions:::: - -void Root::State3::ChildState3::initialize(void) { - // if we're a leaf state, make sure we're active - makeActive(); -} - -void Root::State3::ChildState3::entry(void) { - _root->log("\033[36mENTRY::State3::ChildState3::/c/T/w\033[0m"); - // Entry action for this state - //::::/c/T/w::::Entry:::: -} - -void Root::State3::ChildState3::exit(void) { - _root->log("\033[36mEXIT::State3::ChildState3::/c/T/w\033[0m"); - // Call the Exit Action for this state - //::::/c/T/w::::Exit:::: -} - -void Root::State3::ChildState3::tick(void) { - _root->log("\033[36mTICK::State3::ChildState3::/c/T/w\033[0m"); - // Call the Tick Action for this state - //::::/c/T/w::::Tick:::: - - if (_activeState != nullptr && _activeState != this) - _activeState->tick(); -} - -double Root::State3::ChildState3::getTimerPeriod(void) { return (double)(0.1); } - -bool Root::State3::ChildState3::handleEvent(GeneratedEventBase *event) { - bool handled = false; - - // take care of all event types that this branch will not handle - - // for more consistent run-time performnace - switch (event->get_type()) { - case EventType::EVENT1: - handled = true; - break; - default: - handled = false; - break; - } - - if (handled) { - // we didn't actually handle the event, but return anyway - return false; - } - - // handle internal transitions first - switch (event->get_type()) { - default: - handled = false; - break; - } - if (!handled) { - // handle external transitions here - switch (event->get_type()) { - case EventType::EVENT3: - if (false) { - } // makes generation easier :) - else if (true) { - _root->log("\033[37mNO GUARD on EXTERNAL TRANSITION:/c/T/p\033[0m"); - // Transitioning states! - // Call all from prev state down exits - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ.exitChildren(); - // State : exit for: /c/T/w - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ.exit(); - // External Transition : Action for: /c/T/p - _root->log("\033[36mTRANSITION::ACTION for /c/T/p\033[0m"); - - //::::/c/T/p::::Action:::: - - // State : entry for: /c/T/W - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.entry(); - _root->log("\033[31mSTATE TRANSITION: State3::ChildState3->State3::ChildState\033[0m"); - - // going into regular state - _root->COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ.initialize(); - // make sure nothing else handles this event - handled = true; - } - break; - default: - handled = false; - break; - } - } - if (!handled) { - // now check parent states - handled = _parentState->handleEvent(event); - } - return handled; -} diff --git a/components/state_machine/example/main/Complex_generated_states.hpp b/components/state_machine/example/main/Complex_generated_states.hpp deleted file mode 100644 index f0ce378c7b..0000000000 --- a/components/state_machine/example/main/Complex_generated_states.hpp +++ /dev/null @@ -1,676 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "deep_history_state.hpp" -#include "magic_enum.hpp" -#include "shallow_history_state.hpp" -#include "state_base.hpp" - -#include "Complex_event_data.hpp" - -// User Includes for the HFSM -//::::/c::::Includes:::: -#include - -namespace espp::state_machine::Complex { - -typedef std::function LogCallback; - -enum class EventType { - ENDEVENT, - EVENT1, - EVENT2, - EVENT3, - EVENT4, -}; // ENUMS GENERATED FROM MODEL - -/** - * @brief Class representing all events that this HFSM can respond - * to / handle. Used as abstract interface for handleEvent(). - */ -class GeneratedEventBase : public EventBase { -protected: - EventType type; - -public: - explicit GeneratedEventBase(const EventType &t) - : type(t) {} - virtual ~GeneratedEventBase() {} - EventType get_type() const { return type; } - virtual std::string to_string() const { return std::string(magic_enum::enum_name(type)); } -}; // Class GeneratedEventBase - -/** - * @brief Class representing all events that this HFSM can respond - * to / handle. Intended to be created / managed by the - * EventFactory (below). - */ -template class Event : public GeneratedEventBase { - T data; - -public: - explicit Event(const EventType &t, const T &d) - : GeneratedEventBase(t) - , data(d) {} - virtual ~Event() {} - T get_data() const { return data; } -}; // Class Event - -// free the memory associated with the event -static void consume_event(GeneratedEventBase *e) { delete e; } - -typedef Event ENDEVENTEvent; -typedef Event EVENT1Event; -typedef Event EVENT2Event; -typedef Event EVENT3Event; -typedef Event EVENT4Event; - -/** - * @brief Class handling all Event creation, memory management, and - * ordering. - */ -class EventFactory { -public: - ~EventFactory(void) { clear_events(); } - - void set_log_callback(LogCallback cb) { log_callback_ = cb; } - - void spawn_ENDEVENT_event(const ENDEVENTEventData &data) { - log("\033[32mSPAWN: ENDEVENT\033[0m"); - GeneratedEventBase *new_event = new ENDEVENTEvent{EventType::ENDEVENT, data}; - std::lock_guard lock(queue_mutex_); - events_.push_back(new_event); - queue_cv_.notify_one(); - } - void spawn_EVENT1_event(const EVENT1EventData &data) { - log("\033[32mSPAWN: EVENT1\033[0m"); - GeneratedEventBase *new_event = new EVENT1Event{EventType::EVENT1, data}; - std::lock_guard lock(queue_mutex_); - events_.push_back(new_event); - queue_cv_.notify_one(); - } - void spawn_EVENT2_event(const EVENT2EventData &data) { - log("\033[32mSPAWN: EVENT2\033[0m"); - GeneratedEventBase *new_event = new EVENT2Event{EventType::EVENT2, data}; - std::lock_guard lock(queue_mutex_); - events_.push_back(new_event); - queue_cv_.notify_one(); - } - void spawn_EVENT3_event(const EVENT3EventData &data) { - log("\033[32mSPAWN: EVENT3\033[0m"); - GeneratedEventBase *new_event = new EVENT3Event{EventType::EVENT3, data}; - std::lock_guard lock(queue_mutex_); - events_.push_back(new_event); - queue_cv_.notify_one(); - } - void spawn_EVENT4_event(const EVENT4EventData &data) { - log("\033[32mSPAWN: EVENT4\033[0m"); - GeneratedEventBase *new_event = new EVENT4Event{EventType::EVENT4, data}; - std::lock_guard lock(queue_mutex_); - events_.push_back(new_event); - queue_cv_.notify_one(); - } - - // Returns the number of events in the queue - size_t get_num_events(void) { - std::lock_guard lock(queue_mutex_); - return events_.size(); - } - - // Blocks until an event is available - void wait_for_events(void) { - std::unique_lock lock(queue_mutex_); - queue_cv_.wait(lock); - } - - // Blocks until an event is available or the timeout is reached - void sleep_until_event(float seconds) { - std::unique_lock lock(queue_mutex_); - queue_cv_.wait_for(lock, std::chrono::duration(seconds)); - } - - // Blocks until an event is available - GeneratedEventBase *get_next_event_blocking(void) { - std::unique_lock lock(queue_mutex_); - queue_cv_.wait(lock, [this] { return events_.size() > 0; }); - GeneratedEventBase *ptr = events_.front(); - events_.pop_front(); // remove the event from the Q - return ptr; - } - - // Retrieves the pointer to the next event in the queue, or - // nullptr if it doesn't exist - GeneratedEventBase *get_next_event(void) { - std::lock_guard lock(queue_mutex_); - GeneratedEventBase *ptr = nullptr; - if (events_.size()) { - ptr = events_.front(); - events_.pop_front(); // remove the event from the Q - } - return ptr; - } - - // Clears the event queue and frees all event memory - void clear_events(void) { - GeneratedEventBase *ptr = get_next_event(); - while (ptr != nullptr) { - consume_event(ptr); - ptr = get_next_event(); - } - } - - std::string to_string(void) { - std::lock_guard lock(queue_mutex_); - std::string qStr = "[ "; - for (int i = 0; i < events_.size(); i++) { - qStr += events_[i]->to_string(); - } - qStr += " ]"; - return qStr; - } - -protected: - void log(std::string_view msg) { - if (log_callback_) { - log_callback_(msg); - } - } - - std::deque events_; - std::mutex queue_mutex_; - std::condition_variable queue_cv_; - LogCallback log_callback_{nullptr}; -}; // class EventFactory - -/** - * @brief The ROOT of the HFSM - contains the declarations from - * the user as well as the entire substate tree. - */ -class Root : public StateBase { -public: - // User Declarations for the HFSM - //::::/c::::Declarations:::: - bool goToEnd = false; - bool goToChoice = true; - bool goToHistory = false; - bool nextState = false; - bool killedState = false; - bool someGuard = true; - bool someTest = true; - - int someNumber = 40; - int someValue = 50; - -protected: - void log(const std::string &msg) { - if (log_callback_) { - log_callback_(msg); - } - } - - LogCallback log_callback_{nullptr}; - -public: - // event factory for spawning / ordering events - EventFactory event_factory; - - void set_log_callback(LogCallback cb) { - log_callback_ = cb; - event_factory.set_log_callback(cb); - } - - // helper functions for spawning events into the HFSM - void spawn_ENDEVENT_event(const ENDEVENTEventData &data) { - event_factory.spawn_ENDEVENT_event(data); - } - void spawn_EVENT1_event(const EVENT1EventData &data) { event_factory.spawn_EVENT1_event(data); } - void spawn_EVENT2_event(const EVENT2EventData &data) { event_factory.spawn_EVENT2_event(data); } - void spawn_EVENT3_event(const EVENT3EventData &data) { event_factory.spawn_EVENT3_event(data); } - void spawn_EVENT4_event(const EVENT4EventData &data) { event_factory.spawn_EVENT4_event(data); } - - // Constructors - Root() - : StateBase() - , COMPLEX_OBJ__STATE_1_OBJ(this, this) - , COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ(this, &COMPLEX_OBJ__STATE_2_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__DEEP_HISTORY_PSEUDOSTATE_OBJ(&COMPLEX_OBJ__STATE_2_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ(this, &COMPLEX_OBJ__STATE_2_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ( - this, &COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ( - this, &COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ(this, &COMPLEX_OBJ__STATE_2_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ__SHALLOW_HISTORY_PSEUDOSTATE_OBJ(&COMPLEX_OBJ__STATE_2_OBJ) - , COMPLEX_OBJ__STATE_2_OBJ(this, this) - , COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ(this, &COMPLEX_OBJ__STATE3_OBJ) - , COMPLEX_OBJ__STATE3_OBJ__SHALLOW_HISTORY_PSEUDOSTATE_OBJ(&COMPLEX_OBJ__STATE3_OBJ) - , COMPLEX_OBJ__STATE3_OBJ__DEEP_HISTORY_PSEUDOSTATE_OBJ(&COMPLEX_OBJ__STATE3_OBJ) - , COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ(this, &COMPLEX_OBJ__STATE3_OBJ) - , COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ(this, &COMPLEX_OBJ__STATE3_OBJ) - , COMPLEX_OBJ__STATE3_OBJ(this, this) - , COMPLEX_OBJ__END_STATE_OBJ(this) - , _root(this) {} - ~Root(void) {} - - /** - * @brief Fully initializes the HFSM. Runs the HFSM Initialization - * code from the model, then sets the inital state and runs the - * initial transition and entry actions accordingly. - */ - void initialize(void); - - /** - * @brief Returns true if there are any events in the event queue. - */ - bool has_events(void) { return event_factory.get_num_events() > 0; } - - /** - * @brief Sleeps until an event is available or the current state's timer - * period expires, then returns. This will block until an event is - * available. The amount of time spent sleeping is determined by the - * current state's timer period. - */ - void sleep_until_event(void) { - event_factory.sleep_until_event(getActiveLeaf()->getTimerPeriod()); - } - - /** - * @brief Waits for an event to be available, then returns. - * This will block until an event is available. - */ - void wait_for_events(void) { event_factory.wait_for_events(); } - - /** - * @brief Handles all events in the event queue, ensuring to free the - * memory. This will ensure that any events spawned from other event - * transitions / actions are handled. Returns once there are no more - * events in the queue to process. - */ - void handle_all_events(void); - - /** - * @brief Terminates the HFSM, calling exit functions for the - * active leaf state upwards through its parents all the way to - * the root. - */ - void terminate(void); - - /** - * @brief Restarts the HFSM by calling terminate and then - * initialize. - */ - void restart(void); - - /** - * @brief Returns true if the HFSM has reached its END State - */ - bool has_stopped(void); - - /** - * @brief Calls handleEvent on the activeLeaf. - * - * @param[in] EventBase* Event needing to be handled - * - * @return true if event is consumed, false otherwise - */ - bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - - /** - * @brief Calls handleEvent on the activeLeaf. - * - * @param[in] EventBase* Event needing to be handled - * - * @return true if event is consumed, false otherwise - */ - bool handleEvent(GeneratedEventBase *event); - - // Child Substates - // Declaration for State_1 : /c/Y - class State_1 : public StateBase { - public: - // User Declarations for the State - //::::/c/Y::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - State_1(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~State_1(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State_2 : /c/v - class State_2 : public StateBase { - public: - // User Declarations for the State - //::::/c/v::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - State_2(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~State_2(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - - // Declaration for State_2::ChildState : /c/v/K - class ChildState : public StateBase { - public: - // User Declarations for the State - //::::/c/v/K::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State_2::ChildState2 : /c/v/e - class ChildState2 : public StateBase { - public: - // User Declarations for the State - //::::/c/v/e::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState2(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState2(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State_2::ChildState3 : /c/v/z - class ChildState3 : public StateBase { - public: - // User Declarations for the State - //::::/c/v/z::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState3(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState3(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - - // Declaration for State_2::ChildState3::Grand : /c/v/z/6 - class Grand : public StateBase { - public: - // User Declarations for the State - //::::/c/v/z/6::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - Grand(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~Grand(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State_2::ChildState3::Grand2 : /c/v/z/c - class Grand2 : public StateBase { - public: - // User Declarations for the State - //::::/c/v/z/c::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - Grand2(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~Grand2(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - }; - }; - // Declaration for State3 : /c/T - class State3 : public StateBase { - public: - // User Declarations for the State - //::::/c/T::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - State3(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~State3(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - - // Declaration for State3::ChildState2 : /c/T/0 - class ChildState2 : public StateBase { - public: - // User Declarations for the State - //::::/c/T/0::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState2(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState2(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State3::ChildState : /c/T/W - class ChildState : public StateBase { - public: - // User Declarations for the State - //::::/c/T/W::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - // Declaration for State3::ChildState3 : /c/T/w - class ChildState3 : public StateBase { - public: - // User Declarations for the State - //::::/c/T/w::::Declarations:::: - - public: - // Pointer to the root of the HFSM. - Root *_root; - - // Constructors - ChildState3(Root *root, StateBase *parent) - : StateBase(parent) - , _root(root) {} - ~ChildState3(void) {} - - // StateBase Interface - void initialize(void); - void entry(void); - void exit(void); - void tick(void); - double getTimerPeriod(void); - virtual bool handleEvent(EventBase *event) { - return handleEvent(static_cast(event)); - } - virtual bool handleEvent(GeneratedEventBase *event); - }; - }; - - // END STATE - /** - * @brief This is the terminal END STATE for the HFSM, after which no - * events or other actions will be processed. - */ - class End_State : public StateBase { - public: - explicit End_State(StateBase *parent) - : StateBase(parent) {} - void entry(void) {} - void exit(void) {} - void tick(void) {} - // Simply returns true since the END STATE trivially handles all - // events. - bool handleEvent(EventBase *event) { return true; } - bool handleEvent(GeneratedEventBase *event) { return true; } - }; - - // State Objects - State_1 COMPLEX_OBJ__STATE_1_OBJ; - State_2::ChildState COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE_OBJ; - DeepHistoryState COMPLEX_OBJ__STATE_2_OBJ__DEEP_HISTORY_PSEUDOSTATE_OBJ; - State_2::ChildState2 COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE2_OBJ; - State_2::ChildState3::Grand COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND_OBJ; - State_2::ChildState3::Grand2 COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ__GRAND2_OBJ; - State_2::ChildState3 COMPLEX_OBJ__STATE_2_OBJ__CHILDSTATE3_OBJ; - ShallowHistoryState COMPLEX_OBJ__STATE_2_OBJ__SHALLOW_HISTORY_PSEUDOSTATE_OBJ; - State_2 COMPLEX_OBJ__STATE_2_OBJ; - State3::ChildState2 COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE2_OBJ; - ShallowHistoryState COMPLEX_OBJ__STATE3_OBJ__SHALLOW_HISTORY_PSEUDOSTATE_OBJ; - DeepHistoryState COMPLEX_OBJ__STATE3_OBJ__DEEP_HISTORY_PSEUDOSTATE_OBJ; - State3::ChildState COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE_OBJ; - State3::ChildState3 COMPLEX_OBJ__STATE3_OBJ__CHILDSTATE3_OBJ; - State3 COMPLEX_OBJ__STATE3_OBJ; - // END state object - End_State COMPLEX_OBJ__END_STATE_OBJ; - // Keep a _root for easier templating, it will point to us - Root *_root; -}; // class Root - -}; // namespace espp::state_machine::Complex diff --git a/components/state_machine/example/main/Complex_metadata.json b/components/state_machine/example/main/Complex_metadata.json deleted file mode 100644 index 4d677bea02..0000000000 --- a/components/state_machine/example/main/Complex_metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "projectID": "guest+Examples", - "timeStamp": "2023-08-08T19:38:25.130Z", - "pluginVersion": "0.1.0" -} \ No newline at end of file diff --git a/components/state_machine/project_include.cmake b/components/state_machine/project_include.cmake new file mode 100644 index 0000000000..939d59574a --- /dev/null +++ b/components/state_machine/project_include.cmake @@ -0,0 +1,149 @@ +# espp_generate_hfsm() -- turn an HFSM model into C++ at configure time. +# +# Included by the ESP-IDF build system before any component's +# CMakeLists is processed, so every component can call it. +# +# The model is the source and the C++ is a build product, like an +# object file. Checking generated code in lets the two disagree, and +# they do: this component's example carried a copy generated in 2023 +# that had drifted from the generator by roughly two thousand lines. +# +# Requires node (>= 18). The generator itself comes from npx on demand. +# +# espp_generate_hfsm( +# MODEL # required +# OUTPUT_DIR # required, wiped each configure +# [SOURCES_VAR ] # -> generated .cpp files +# [INCLUDE_DIR_VAR ] # -> dir for INCLUDE_DIRS +# [NAMESPACE ] # -n, else the model's own +# [WITH_SUPPORT] # also emit the shared runtime +# ) +# +# Typical use, from a component's CMakeLists.txt: +# +# espp_generate_hfsm( +# MODEL "${CMAKE_CURRENT_LIST_DIR}/Complex.json" +# OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/hfsm" +# SOURCES_VAR hfsm_srcs +# INCLUDE_DIR_VAR hfsm_inc) +# +# idf_component_register(SRCS "main.cpp" ${hfsm_srcs} +# INCLUDE_DIRS "." ${hfsm_inc}) + +# Pinned to a minor range: reproducible enough for a build that +# regenerates from a checked-in model, and picks up generator fixes +# without a commit here. 1.8.0 is the first release the CLI can be +# installed from at all, and the first with --no-support. +set(ESPP_HFSM_GEN_SPEC "webgme-hfsm@^1.8.0" + CACHE STRING "npm/npx spec for the webgme-hfsm code generator") + +# Skip npx entirely -- a local checkout while working on the +# generator, and the way to build with no network: +# idf.py -DESPP_HFSM_GEN_COMMAND="node;/path/to/webgme-hfsm/bin/hfsm-gen.js" build +set(ESPP_HFSM_GEN_COMMAND "" CACHE STRING + "Override the generator invocation (a ;-separated command)") + +function(espp_generate_hfsm) + cmake_parse_arguments(HFSM + "WITH_SUPPORT" + "MODEL;OUTPUT_DIR;SOURCES_VAR;INCLUDE_DIR_VAR;NAMESPACE" + "" + ${ARGN}) + + if(HFSM_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "espp_generate_hfsm: unknown argument(s): ${HFSM_UNPARSED_ARGUMENTS}") + endif() + if(NOT HFSM_MODEL) + message(FATAL_ERROR "espp_generate_hfsm: MODEL is required") + endif() + if(NOT HFSM_OUTPUT_DIR) + message(FATAL_ERROR "espp_generate_hfsm: OUTPUT_DIR is required") + endif() + if(NOT EXISTS "${HFSM_MODEL}") + message(FATAL_ERROR "espp_generate_hfsm: no such model: ${HFSM_MODEL}") + endif() + + get_filename_component(_output_dir "${HFSM_OUTPUT_DIR}" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + get_filename_component(_binary_dir "${CMAKE_BINARY_DIR}" ABSOLUTE) + file(RELATIVE_PATH _output_relative "${_binary_dir}" "${_output_dir}") + if(_output_relative STREQUAL "" OR + _output_relative MATCHES "^\\.\\.(/|$)" OR + IS_ABSOLUTE "${_output_relative}") + message(FATAL_ERROR + "espp_generate_hfsm: OUTPUT_DIR must be inside CMAKE_BINARY_DIR: " + "${HFSM_OUTPUT_DIR}") + endif() + + # Re-run cmake when the model changes, so editing it regenerates on + # the next build rather than the next clean. A function does not open + # a directory scope, so this lands on the caller's directory. + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${HFSM_MODEL}") + + if(ESPP_HFSM_GEN_COMMAND) + set(_cmd ${ESPP_HFSM_GEN_COMMAND}) + else() + find_program(ESPP_NPX_EXECUTABLE npx) + if(NOT ESPP_NPX_EXECUTABLE) + message(FATAL_ERROR + "espp_generate_hfsm needs node (>= 18) with npx on PATH to generate " + "${HFSM_MODEL}.\n" + " Install node: https://nodejs.org\n" + " Or point at a local generator checkout:\n" + " idf.py -DESPP_HFSM_GEN_COMMAND=\"node;/path/to/webgme-hfsm/bin/hfsm-gen.js\" build") + endif() + # --yes so npx never stops to ask whether to install the package, + # which in CI would hang rather than fail + set(_cmd "${ESPP_NPX_EXECUTABLE}" --yes -p "${ESPP_HFSM_GEN_SPEC}" hfsm-gen) + endif() + + set(_args "${HFSM_MODEL}" -o "${_output_dir}") + if(NOT HFSM_WITH_SUPPORT) + # Generate THIS machine and not the shared runtime: state_base.hpp, + # the history states and magic_enum.hpp are the same for every + # machine, and this component already provides them. espp's are the + # ones the rest of the codebase is built against -- and its + # magic_enum is newer than the generator's -- so a second copy + # beside the generated machine would shadow them on the include + # path. + list(APPEND _args --no-support) + endif() + if(HFSM_NAMESPACE) + list(APPEND _args -n "${HFSM_NAMESPACE}") + endif() + + # Clear stale artifacts first. The generator only overwrites what it + # emits, so a machine renamed or removed in the model would leave an + # obsolete .cpp behind in the (persistent) binary dir for CMake to go + # on compiling. + file(REMOVE_RECURSE "${_output_dir}") + file(MAKE_DIRECTORY "${_output_dir}") + + message(STATUS "hfsm: generating C++ from ${HFSM_MODEL}") + execute_process( + COMMAND ${_cmd} ${_args} + RESULT_VARIABLE _result + OUTPUT_VARIABLE _out + ERROR_VARIABLE _err) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "hfsm generation failed for ${HFSM_MODEL}:\n${_out}${_err}") + endif() + + # Found rather than assumed: the file names come from the machine's + # name in the model, so a caller would otherwise have to know what + # its own model is called and keep that in step by hand. + file(GLOB _sources "${_output_dir}/*.cpp") + list(SORT _sources) + if(NOT _sources) + message(FATAL_ERROR + "hfsm: ${HFSM_MODEL} generated no .cpp -- does it contain a State Machine?") + endif() + + if(HFSM_SOURCES_VAR) + set(${HFSM_SOURCES_VAR} "${_sources}" PARENT_SCOPE) + endif() + if(HFSM_INCLUDE_DIR_VAR) + set(${HFSM_INCLUDE_DIR_VAR} "${_output_dir}" PARENT_SCOPE) + endif() +endfunction()