This is a Ruby gem and executable for generating a stub for a Finite State Machine in C/C++ from a scheme written in Graphviz language.
DISCLAIMER: You need Ruby for running it, but it runs as a command line executable that transparently uses Ruby for generating C/C++ source code. So you do not need to know/like Ruby in order to use it:
Simply:
[sudo] gem install gv_fsm
Warning: if you are using rvm or similar tools, the executable is installed in the rvm hidden folders: find where it is with gem environment
be sure to have the path for EXECUTABLE DIRECTORY it in your path!
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 asvoid
: 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 signaturevoid <source_state>_to_<dest_state>()
The .dot file can be used for generating C/C++ files with the command:
gv_fsm 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.
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.
GV_FSM version 0.4.0 introduces a new mechanism to trigger state changes from outside the FSM using events.
The event_data_t
typedef, like state_data_t
, can be used to pass custom data when a new event is triggered.
Two functions are generated by default to trigger a new event or check if one is already fired. To change state when the event is triggered an explicit check has to be made inside of a state function, for example:
if (is_event_triggered())
next_state = STATE_NEXT;
Important
Only one event at a time can be fired.
GV_FSM version 0.3.0 introduces a new CLI option that enables the generation of code that support SIGINT signal management:
gv_fsm fsm.dot -k stop
It 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.
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.