Getting Started

Overview

There are 2 ways to add hsmcpp library to your project:

  • compile, install and use library through pkg-config;

  • add hsmcpp repository as a git submodule and compile it together with your project.

Building the library

Requirements

  • CMake 3.16+

  • Python 3.8+

Ubuntu

Simplest way to build hsmcpp is to run build.sh script:

git clone https://github.com/igor-krechetov/hsmcpp.git
cd ./hsmcpp
./build.sh

Windows

You can build hsmcpp with any tools that you have, but provided script build_vs.cmd requires Visual Studio 2015 or newer. Make sure to set correct path to your Visual Studio directory in build_vs.cmd:

call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86

By default only STD based dispatcher is enabled. To enable Qt based one uncomment following lines and change path to match your Qt directory:

set Qt5_DIR=C:\Qt\5.9\5.9.2\msvc2015\lib\cmake\Qt5
cmake -DHSMBUILD_DISPATCHER_GLIB=OFF -DHSMBUILD_DISPATCHER_GLIBMM=OFF ..

To build GLib and GLibmm based dispatchers you will need to provide pkg-config and corresponding libraries yourself.

Possible build options

Option

Description

HSMBUILD_VERBOSE

Enable/disable HSM verbosity (usually OFF since it’s only needed for hsmcpp development)

HSMBUILD_STRUCTURE_VALIDATION

Enable/disable HSM structure validation

HSMBUILD_THREAD_SAFETY

Enable/disable HSM thread safety

HSMBUILD_DEBUGGING

Enable/disable support for HSM debugging using hsmdebugger (recommended to turn off in production build)

HSMBUILD_DISPATCHER_GLIB

Enable GLib dispatcher

HSMBUILD_DISPATCHER_GLIBMM

Enable GLibmm dispatcher

HSMBUILD_DISPATCHER_STD

Enable std::thread based dispatcher

HSMBUILD_DISPATCHER_QT

Enable Qt based dispatcher

HSMBUILD_TESTS

Build unittests

HSMBUILD_EXAMPLES

Build examples

Options can be applied when running cmake:

cmake -DHSMBUILD_TESTS=OFF -DHSMBUILD_EXAMPLES=OFF ..

Hello World!

Let’s create the smallest state machine which would represent a switch button:

HelloWorld state machine

For more complex examples see /examples folder.

For simplicity we are going to use STD dispatcher to avoid additional dependencies. Source code is available in /examples/00_helloworld/00_helloworld_std.cpp .

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

namespace States {
    const hsmcpp::StateID_t OFF = 0;
    const hsmcpp::StateID_t ON = 1;
}

namespace Events {
    const hsmcpp::EventID_t SWITCH = 0;
}

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

    hsm.registerState(States::OFF, [&hsm](const hsmcpp::VariantVector_t& args) {
        (void)printf("Off\n");
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        hsm.transition(Events::SWITCH);
    });
    hsm.registerState(States::ON, [&hsm](const hsmcpp::VariantVector_t& args) {
        (void)printf("On\n");
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        hsm.transition(Events::SWITCH);
    });

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

    if (true == hsm.initialize(dispatcher)) {
        hsm.transition(Events::SWITCH);
        dispatcher->join();
    }

    return 0;
}

CMake script (pkg-config)

To use hsmcpp as a pkg-config module you can follow template: /examples/07_build/using_pkgconfig/CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(07_build_pkgconfig)
set(BINARY_NAME "07_build_pkgconfig")
set(CMAKE_CXX_STANDARD 11)

find_package(PkgConfig REQUIRED)

# Configure HSMCPP library. Settings must be set before calling find_package
set(HSMCPP_CONFIG_VERBOSE ON CACHE BOOL "Enable internal HSM traces")
# set(HSMCPP_CONFIG_STRUCTURE_VALIDATION ON CACHE BOOL "Enable HSM structure validation")
# set(HSMCPP_CONFIG_THREAD_SAFETY ON CACHE BOOL "Enable HSM thread safety")
# set(HSMCPP_CONFIG_DEBUGGING ON CACHE BOOL "Enable HSM debugging")

# Include HSMCPP module with STD dispatcher (multiple can be specified)
# Possible component values: std, glib, glibmm, qt
find_package(hsmcpp COMPONENTS std glibmm)

# create folder for generated files
set(GEN_DIR ${CMAKE_BINARY_DIR}/gen)
file(MAKE_DIRECTORY ${GEN_DIR})
set(GEN_DIR_DIAGRAM ${CMAKE_BINARY_DIR}/gen_diagram)
file(MAKE_DIRECTORY ${GEN_DIR_DIAGRAM})

# generate HSM
generateHsm(GEN_07_HSM ../07_build.scxml "SwitchHsm" ${GEN_DIR} "GEN_OUT_SRC")
# generate state machine diagram (optional)
generateHsmDiagram(GEN_07_HSM_DIAGRAM ../07_build.scxml ${GEN_DIR_DIAGRAM}/07_build.plantuml)

# Define binary and dependencies
add_executable(${BINARY_NAME} ../main.cpp ${GEN_OUT_SRC})
add_dependencies(${BINARY_NAME} GEN_07_HSM)
add_dependencies(${BINARY_NAME} GEN_07_HSM_DIAGRAM)

# Add HSMCPP and GEN include directories
target_include_directories(${BINARY_NAME} PUBLIC ${HSMCPP_INCLUDE_DIRS} ${CMAKE_BINARY_DIR})
# Link with HSMCPP library
target_link_libraries(${BINARY_NAME} PUBLIC ${HSMCPP_LDFLAGS})
# Set defines for HSMCPP library
target_compile_options(${BINARY_NAME} PRIVATE ${HSMCPP_CFLAGS_OTHER})

CMake script (as source code)

To compile hsmcpp together with your project you can follow template: /examples/07_build/using_code/CMakeLists.txt

# This is an example showing how to use hsmcpp library as a source code

cmake_minimum_required(VERSION 3.16)
project(example)
set(BINARY_NAME "07_build_code")
set(CMAKE_CXX_STANDARD 11)

# ----------------------------------------------------------------------
# Configure and install HSMCPP library
SET(HSMBUILD_VERBOSE OFF CACHE BOOL "Disable HSM verbosity")
SET(HSMBUILD_EXAMPLES OFF CACHE BOOL "Disable HSM examples")
SET(HSMBUILD_TESTS OFF CACHE BOOL "Disable HSM tests")
SET(HSMBUILD_DISPATCHER_GLIB OFF CACHE BOOL "Disable Glib dispatcher")
SET(HSMBUILD_DISPATCHER_GLIBMM ON CACHE BOOL "Enable Glibmm dispatcher")
SET(HSMBUILD_DISPATCHER_QT OFF CACHE BOOL "Disable Qt dispatcher")
SET(HSMBUILD_DISPATCHER_STD ON CACHE BOOL "Enable STD dispatcher")
# ./hsmcpp folder should contain all files from hsmcpp repository
add_subdirectory(hsmcpp)

# ----------------------------------------------------------------------
# Application specific code. This is just an example it there are no restrictions to use it specifically in this way

# create folder for generated files
set(GEN_DIR ${CMAKE_BINARY_DIR}/gen)
file(MAKE_DIRECTORY ${GEN_DIR})
set(GEN_DIR_DIAGRAM ${CMAKE_BINARY_DIR}/gen_diagram)
file(MAKE_DIRECTORY ${GEN_DIR_DIAGRAM})

# generate HSM
generateHsm(GEN_07_HSM ../07_build.scxml "SwitchHsm" ${GEN_DIR} "GEN_OUT_SRC")
# generate state machine diagram (optional)
generateHsmDiagram(GEN_07_HSM_DIAGRAM ../07_build.scxml ${GEN_DIR_DIAGRAM}/07_build.plantuml)

# Define binary and dependencies
add_executable(${BINARY_NAME} ../main.cpp ${GEN_OUT_SRC})
add_dependencies(${BINARY_NAME} GEN_07_HSM)
add_dependencies(${BINARY_NAME} GEN_07_HSM_DIAGRAM)

# Add HSMCPP and GEN include directories
target_include_directories(${BINARY_NAME} PUBLIC ${HSMCPP_STD_INCLUDE}
                                                 ${HSMCPP_GLIBMM_INCLUDE}
                                                 ${CMAKE_BINARY_DIR})
# Link with HSMCPP library
target_link_libraries(${BINARY_NAME} PUBLIC ${HSMCPP_STD_LIB} ${HSMCPP_GLIBMM_LIB})
# Set CXX flags for HSMCPP library
target_compile_options(${BINARY_NAME} PRIVATE ${HSMCPP_STD_CXX_FLAGS}
                                              ${HSMCPP_GLIBMM_CXX_FLAGS}
                                              ${HSM_DEFINITIONS_STD}
                                              ${HSM_DEFINITIONS_GLIBMM})

CMake script (download from GitHub)

Maybe the easiest option to use hsmcpp in your project is to download it directly from GitHub and compile it together with your application. The downsides of this approach are:

  • dependency on Internet connection availability and GitHub;

  • a bit longer clean build time due to the necessity to download hsmcpp library files (since files are stored in your temporary build folder).

You can use this CMake template: /examples/07_build/using_fetch/CMakeLists.txt

# This is an example showing how to use hsmcpp library directly from GitHub

cmake_minimum_required(VERSION 3.16)
project(example)
set(BINARY_NAME "07_build_fetch")
set(CMAKE_CXX_STANDARD 11)

# ----------------------------------------------------------------------
# wrapper function to download hsmcpp
function(installHsmcpp)
    include(FetchContent)
    message("Downloading hsmcpp...")
    FetchContent_Declare(hsmcpp
                         GIT_REPOSITORY https://github.com/igor-krechetov/hsmcpp.git
                         GIT_TAG main
    )
    FetchContent_MakeAvailable(hsmcpp)
endfunction()

# Configure and install HSMCPP library
SET(HSMBUILD_VERBOSE OFF CACHE BOOL "Disable HSM verbosity")
SET(HSMBUILD_EXAMPLES OFF CACHE BOOL "Disable HSM examples")
SET(HSMBUILD_TESTS OFF CACHE BOOL "Disable HSM tests")
SET(HSMBUILD_DISPATCHER_GLIB OFF CACHE BOOL "Disable Glib dispatcher")
SET(HSMBUILD_DISPATCHER_GLIBMM ON CACHE BOOL "Enable Glibmm dispatcher")
SET(HSMBUILD_DISPATCHER_QT OFF CACHE BOOL "Disable Qt dispatcher")
SET(HSMBUILD_DISPATCHER_STD ON CACHE BOOL "Enable STD dispatcher")
installHsmcpp()

# ----------------------------------------------------------------------
# Application specific code. This is just an example it there are no restrictions to use it specifically in this way

# create folder for generated files
set(GEN_DIR ${CMAKE_BINARY_DIR}/gen)
file(MAKE_DIRECTORY ${GEN_DIR})
set(GEN_DIR_DIAGRAM ${CMAKE_BINARY_DIR}/gen_diagram)
file(MAKE_DIRECTORY ${GEN_DIR_DIAGRAM})

# generate HSM
generateHsm(GEN_07_HSM ../07_build.scxml "SwitchHsm" ${GEN_DIR} "GEN_OUT_SRC")
# generate state machine diagram (optional)
generateHsmDiagram(GEN_07_HSM_DIAGRAM ../07_build.scxml ${GEN_DIR_DIAGRAM}/07_build.plantuml)

# Define binary and dependencies
add_executable(${BINARY_NAME} ../main.cpp ${GEN_OUT_SRC})
add_dependencies(${BINARY_NAME} GEN_07_HSM)
add_dependencies(${BINARY_NAME} GEN_07_HSM_DIAGRAM)

# Add HSMCPP and GEN include directories
target_include_directories(${BINARY_NAME} PUBLIC ${HSMCPP_STD_INCLUDE}
                                                 ${HSMCPP_GLIBMM_INCLUDE}
                                                 ${CMAKE_BINARY_DIR})
# Link with HSMCPP library
message("HSMCPP_STD_INCLUDE=${HSMCPP_STD_INCLUDE}")
message("HSMCPP_GLIBMM_INCLUDE=${HSMCPP_GLIBMM_INCLUDE}")
message("HSMCPP_STD_LIB=${HSMCPP_STD_LIB}")
message("HSMCPP_GLIBMM_LIB=${HSMCPP_GLIBMM_LIB}")
message("HSMCPP_STD_CXX_FLAGS=${HSMCPP_STD_CXX_FLAGS}")
message("HSMCPP_GLIBMM_CXX_FLAGS=${HSMCPP_GLIBMM_CXX_FLAGS}")
message("HSM_DEFINITIONS_STD=${HSM_DEFINITIONS_STD}")
message("HSM_DEFINITIONS_GLIBMM=${HSM_DEFINITIONS_GLIBMM}")
target_link_libraries(${BINARY_NAME} PUBLIC ${HSMCPP_STD_LIB} ${HSMCPP_GLIBMM_LIB})
# Set CXX flags for HSMCPP library
target_compile_options(${BINARY_NAME} PRIVATE ${HSMCPP_STD_CXX_FLAGS}
                                              ${HSMCPP_GLIBMM_CXX_FLAGS}
                                              ${HSM_DEFINITIONS_STD}
                                              ${HSM_DEFINITIONS_GLIBMM})