Skip to content

pbosetti/gv2fsm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Graphviz to Finite State Machine generator

This is a C++ version of the former Ruby-based tool: https://github.com/pbosetti/gv_fsm.

Build

CMake toolset:

cmake -Bbuild
cmake --build build
cmake --install build

Pre-compiled binaries

Refer to the releases. Available for macOS (Universal binaries) and for Linux (22.04 and later).

Usage

First, you have to create a Graphviz .dot file describing the state machine. Use directed edges for transition and follow these conventions:

  • States are represented by nodes. Node labels are taken as name of functions called within a state.
  • If the state label is missing, the function is generated with the signature state_t do_<statename>(state_data_t *data)
  • All persistent state data have to be put in the data object (typically a C struct)
  • state_data_t is typedef as void: either cast it within each state and transition function, or edit the typedef at the beginning of the header.
  • Transitions may have associated functions: if an edge (transition) label is missing, no transition function is generated. If it is present, then the label becomes the name of the function; if the lable is the # character, the function is generated with the signature void <source_state>_to_<dest_state>()

The .dot file can be used for generating C/C++ files with the command:

gv2fsm scheme.dot

This generates a header file (by default with the name scheme.h, use the -s switch for changing it) and the source file (scheme.c). Typically, you have then to provide the implementation of state and transition functions by only editing the scheme.c file.

The main interface to the FSM in C is the run_state function. See at the end of the generated source file for example usage.

Arduino support

If you need an FSM for your Arduino, you can generate it with the command option --ino: this will generate a .h and a .cpp files, omitting all instructions that are not available on the Arduino (e.g. the syslog calls, which are replaced with Serial.print calls). Load these files in the IDE, require the header from the main .ino file, and call the FSM manager function from within the main loop() function.

C++ support

Gem version 0.4 introduces a new CLI option that enables the generation of C++17 code. This is done by adding the --cpp option to the command line.

The generated code is easier to use than the C version:

  • It's implemented as a header-only template class, split in two files (where <fsm> is your chosen output name):
    • <fsm>.hpp is the class header, which you typically don't have to change
    • <fsm>_impl.hpp is the implementation header, where the actual state and transition functions are implemented (by you!)
    • You only want to #include "<fsm>.hpp" in your code
  • the FiniteStateMachine header-only class is a template class that accepts the state data type as template parameter
  • almost all the boilerplate code is hidden in the FiniteStateMachine class header file, including state change checks. Under normal circumstances, you do not need to edit this file
  • the source file only has a list of state functions and transition functions, which --- on the contrary of the C version --- are bare functions, since the state change checks are done by the FiniteStateMachine class
  • in accord to the above, it is easier to update the FSM scheme and regenerate only the implementation header, then manually update the source file with the new/changed/deleted state and transition functions
  • the generated state functions return the special state FSM::UNIMPLEMENTED, which triggers an exception in the FiniteStateMachine class. This is useful for debugging, since it is easy to spot which state has not been implemented yet
  • the FiniteStateMachine class has a run method that runs the FSM until the exit state (identified as the only sink state in the graph) is reached. This method also accepts a lambda or a std::function object that is called at each iteration, and can be used for logging or other purposes
  • the FiniteStateMachine::set_timing_function method allows to set a function that is called at each iteration for timing purposes

SIGINT support

gv2fsm supports SIGINT signal management:

gv2fsm fsm.dot -k stop

That defines a handler function and installs it as active signal handler for SIGINT in the source node of the FSM. Then, in every stable state (i.e. a state having a transition to itself), it adds a condition to switch to the final state specified by the CLI option (stop in the example above) whenever the SIGINT signal has been received.

Please note that the transition is triggered by the global variable _exit_request: when it becomes true, all stable states transition to the specified state on the next iteration. Also, note that non-stable states are not affected by this mechanism.

If the target state is not a sink (i.e. it has some further exit states), then a warning is produced during code generation, but the code is generated nonetheless.

This option is not compatible with the --ino option, since signals are not available on that platform.

Example

See the sm.dot file as FSM example, and the generated files example.{c,h}. In this example, the same function stay is generated from both transitions from idle to idle and from running to running. Also, the name of the transition from setup to running is automatically generated (as setup_to_running). The files arduino.{cpp,h} are the corresponding examples generated for the Arduino platform.

Example graph

About

Graphviz to Finite State Machine generator, C++ version

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors