hsmcpp Documentation

Note

This project is under active development.

MIT License Changelog Documentation Status

Releases

Latest Release PlatformIO Registry arduino-library-badge

hsmcpp — Hierarchical State Machines for Embedded & Event-Driven C++

A C++ library for building scalable, maintainable hierarchical state machines for embedded and event-driven systems.

  • Embedded-ready (Linux, QNX, FreeRTOS, Arduino)

  • SCXML-based code generation + visual tooling

  • Thread-safe, async/sync execution

  • MISRA C++ checks enforced in CI

Eliminate fragile switch-case FSMs and replace them with scalable, testable state machines that work across embedded and multi-threaded systems.

Why hsmcpp for embedded systems?

  • Manage complex state logic without spaghetti code

  • Model behavior visually with SCXML and keep it in sync with implementation

  • Debug transitions and state flow with built-in tooling

  • Designed for high-performance and real-time workflows

  • Integrate easily with your runtime (RTOS, Qt, STD, etc.)

Is this library a good fit for your project?

Good fit for:

  • C++ engineers building event-driven and embedded systems

  • Teams needing maintainable state logic at scale and architecture-as-code

May be overkill for:

  • trivial FSMs

  • ultra-constrained environments with no dynamic memory

Quick Start

hsmcpp supports two workflows:

  • Model-driven (recommended): SCXML + code generation + visual tooling

  • Code-first: define state machines directly in C++

Visual Workflow (SCXML-based)

        flowchart LR
    subgraph Modeling
        REQ[Requirements]
        SCXML[SCXML Definition]
        IDE[Visual Editor]
    end

    subgraph Generation
        GEN[Code Generator]
        UML[PlantUML Diagram]
    end

    subgraph Runtime
        HSM[C++ HSM]
        DISP[Dispatcher]
        APP[Application]
    end

    subgraph Analysis
        DBG[hsmdebugger]
    end

    subgraph Artifacts
        DESIGN[Design Documentation]
        EXE[Binaries]
    end

    REQ --> IDE
    IDE --> SCXML
    SCXML --> GEN
    SCXML --> UML
    UML --> DESIGN
    GEN --> HSM

    HSM --> DISP
    DISP --> APP

    APP --> EXE
    EXE --> DBG
    DBG -. inspect / refine .-> SCXML
    

Minimal code-only example

#include <chrono>
#include <thread>
#include <memory>
#include <hsmcpp/hsm.hpp>
#include <hsmcpp/HsmEventDispatcherSTD.hpp>

enum class States { OFF, ON };
enum class Events { SWITCH };

int main(const int argc, const char**argv)
{
    std::shared_ptr<hsmcpp::HsmEventDispatcherSTD> dispatcher = hsmcpp::HsmEventDispatcherSTD::create();
    hsmcpp::HierarchicalStateMachine<States, Events> hsm(States::OFF);

    // Register states
    hsm.registerState(States::OFF, [&hsm](const VariantList_t& args) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        hsm.transition(Events::SWITCH);
    });
    hsm.registerState(States::ON, [&hsm](const VariantList_t& args) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        hsm.transition(Events::SWITCH);
    });

    // Register transitions
    hsm.registerTransition(States::OFF, States::ON, Events::SWITCH);
    hsm.registerTransition(States::ON, States::OFF, Events::SWITCH);

    // Initialize HSM
    hsm.initialize(dispatcher);

    // Start dispatcher and block
    dispatcher->join();

    return 0;
}

For complete code see examples/00_helloworld/00_helloworld_std.cpp.

Minimal SCXML-based example

blink.scxml:

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="OFF">
  <state id="OFF">
    <invoke srcexpr="onOff"/>
    <transition event="SWITCH" target="ON"/>
  </state>

  <state id="ON">
    <invoke srcexpr="onOn"/>
    <transition event="SWITCH" target="OFF"/>
  </state>
</scxml>

Minimal C++ code to use the generated BlinkHsmBase:

#include "gen/BlinkHsmBase.hpp"

class BlinkHsm : public BlinkHsmBase {
protected:
    void onOff(const hsmcpp::VariantVector_t&) override {
        transition(BlinkHsmEvents::SWITCH);
    }

    void onOn(const hsmcpp::VariantVector_t&) override {
        transition(BlinkHsmEvents::SWITCH);
    }
};

int main(const int argc, const char** argv) {
    std::shared_ptr<HsmEventDispatcherSTD> dispatcher = HsmEventDispatcherSTD::create();
    BlinkHsm hsm;

    if (true == hsm.initialize(dispatcher)) {
        dispatcher->join();