Statecharts can get large and in these cases you may want to modularize the behavior and split it into two or more separate but interacting state machines. Modularization of complex reactive behavior facilitates maintainability, reuse, and team work. This example shows how multiple interacting statecharts can be used to build an application. It integrates the statechart on the level of the generated C code and thus makes use of the capabilities of the deep C integration. The application example is the coffee machine that you may already know from our other example projects. If you are not familiar with the 'Deep C Integration' feature of the YAKINDU Statechart Tools then you may consider to take a look at the 'Coffee Machine (C)' example first. In difference to the design of the original coffee maker statechart model, the behavior of this example is described by six statecharts. One statechart for the general functions of the coffee maker like handling user input, power save mode, or executing selected recipes. The other five statecharts define the processing for each recipe as an independent statechart.
There are five statcharts that define the processing of the different recipes that the coffee maker provides. Thus, these are named ProcessCappucino, ProcessCoffee etc.. Based on the user input the main statechart CoffeeMachine selects one of the recipe processing state machines. Interacting with these state machines is possible by directly accessing the generated state machine C API. For the example we choose a more generic approach. The sc_statemachine module defines a generic state machine wrapper. Instances of this wrapper refer to a state machine and provide general functions to enter, exit, and execute the wrapped state machine. Thus, by using the wrapper the main state machine just has a dependency on the wrapper and no direct dependency on the different recipe state machines.
So lets take a look how the coffee machine model is defined. Most things happen in the state Process Recipe. When this state is entered, the statchart gets a recipe processing state machine from the array recipeProcessors using an index which is based on the user input. This array is an array of state machine wrappers (sc_statemachine_t). At that point the selected state machine is used as a sub state machine of the Process Recipe state. This is done by assigning the selected recipe machine to the recipeProc state machine pointer variable and directly activating it by calling the sc_enter function. As the state machine has cycle based execution semantics the recipe state machine is directly executed with each cycle using the always / sc_runCycle(recipeProc) local reaction. When the recipe processing has completed it enters a final state. The Process Recipe state is then exited and also an exit is called on the recipe processing machine.
The example is implemented as a simple command line tool. It makes use of POSIX threads. So you need a compiler tool chain and a 'pthread' library to build an run the example.
The source code artifacts are all located in the 'src' folder. File names that include 'coffee' or 'cm_' include application specific implementations and those with 'sc_' prefix are generic parts that belong to the state machine infrastructure. This also includes state machine wrapper that is defined in the 'sc_statemachine' module. If you want to use this in your project then simply copy it.
As mentioned above you need a compiler toolchain and the 'pthread' libraries. If you have a Linux or Mac OS Xsystem you likely have everything installed. If you run Windows than we propose to install cygwin tools (https://www.cygwin.com).
This project is preconfigured for Windows with cygwin. If you use another system:
In the 'Debug' or 'Release' folder you will find an executable 'coffee_machine_pro.exe' (even on Linux and Mac OS X). Right-click on this and choose: