Skip to Main Content Skip to Search
Home |   Australia  Choose Country  |  Contact Us  |  Cart Store 
Create Account | Log In
Products & Services Industries Academia Support User Community Company

 

Newsletters - MATLAB Digest

Integrating Custom C-Code using Stateflow 2.0

by Vijay Raghavan

Have you ever needed to incorporate custom C-code into Stateflow diagrams to take advantage of legacy code that augments the simulation capabilities of Simulink and Stateflow? Have you ever needed to define and include custom global variables that can be shared by both Stateflow generated code and your custom code? This article introduces you to the new features of Stateflow 2.0 for custom C-code integration. One of the key advantages to using Simulink and Stateflow is the tremendous ease with which you can integrate custom C-code into your simulations. We begin by describing the organization of generated code from Stateflow 2.0 and then explain how custom-code is incorporated into Stateflow generated code. The examples in this article are available in the integration.zip file.

1. Introduction

An efficient incremental code generation scheme was implemented in Stateflow 2.0, which allows for a better integration of custom C-code. Let us consider an example in order to explain this new scheme. Suppose we have a Simulink model named mymodel.mdl which contains two Stateflow blocks named chart1 and chart2. In Stateflow notation, we have a "machine" named mymodel that parents two "charts" named chart1 and chart2 respectively. All the generated code for mymodel.mdl gets compiled into an S-function DLL named mymodel_sfun.dll on PC platforms and mymodel_sfun.$mexext$ on UNIX, where $mexext$ is sol2 on Solaris, mexsg on SGI, mexlx on linux, etc.

2. Organization of the generated code for the Simulation (sfun) target

Since we are going to generate multiple files per model, the generated files are written to a subdirectory named sfprj/build/mymodel/sfun/src in the current directory. (This directory path may change in the future, and we advise you not to write any scripts that rely on this directory structure.) In addition, do not keep any of your custom source files in these directories. The code generated for the simulation target "sfun" is organized into the following files:
  1. mymodel_sfun.h (Machine Header File)
    This file contains:
  2. all the defined global variables needed for the generated code
  3. type definition of the state machine-specific data structure that holds machine parented local data
  4. external declarations of any state machine-specific global variables and functions
  5. custom code strings specified via the Target Options dialog box
  6. mymodel_sfun.c (Machine Source File)
    This file contains:
    • all the machine parented event broadcast functions
  7. Simulink interface code
  8. This file #includes:
    • the machine header file
    • all the chart header files (described below)
    • mymodel_sfun_registry.c
      The machine registry file that contains Simulink interface code.
    • mymodel_sfun_c1.h
      This is the chart header file for chart chart1. This file contains type definitions of the chart-specific data structures that hold chart parented local data and states. Note: Every chart is assigned a unique number at creation time by Stateflow. This number is used as a suffix for the chart source and chart header file names for every chart (e.g., chart#, where # is 1, 2, 3, etc.).
    • mymodel_sfun_c1.c
      This is the chart source file for chart1. This chart source file #includes the machine header file and the corresponding chart header file.
      It contains:
    • chart parented data initialization code
    • chart execution code (state entry, during exit etc.)
    • chart-specific Simulink interface code.
    • mymodel_sfun_c2.h and mymodel_sfun_c2.c
      These are the chart header and source files for chart2.
    • Platform/compiler specific makefiles
      On UNIX platforms, Stateflow generates a gmake compatible makefile named mymodel_sfun.mku that is used to compile all the generated code into an executable. On PC platforms, an ANSI C compiler-specific makefile is generated based on your C-MEX setup. We currently support four compilers:
    • Microsoft Visual C++ 4.2, 5.0, 6.0
    • Watcom 10.6, 11.0
    • Borland 5.0
    • Lcc-win32, a bundled ANSI C-compiler which is shipped with Stateflow 2.0
    • If your installed compiler is Microsoft Visual C++, we generate:

    • a MSVC compatible makefile named mymodel_sfun.mak
    • a symbol definition file named mymodel_sfun.def (required for building S-function DLLs)

If your installed compiler is Watcom, we generate:

  1. a Watcom compatible makefile named mymodel_sfun.wmk

If your installed compiler is Borland, we generate:

  1. a Borland compatible makefile named mymodel_sfun.bmk
  2. a symbol definition file named mymodel_sfun.def (required for building S-function DLLs)

If you have chosen lcc-win32, a bundled ANSI C compiler shipped with Stateflow 2.0, we generate:

  1. an lcc compatible makefile named mymodel_sfun.lmk

In addition, we generate another support file needed for the make process named mymodel_sfun.mol.

3. The New Target Options for Custom Code Integration

The new Target Options dialog box in Stateflow 2.0 provides the following options for specifying custom code to be built into a simulation target. You can open this dialog box by clicking on the "Target Options" button on the Target Builder dialog box. The Target Builder dialog box for S-Functions or Real-Time Workshop (RTW) targets can be accessed via the Tools menu options "Open Simulation Target" and "Open RTW Target" on the Stateflow chart editor. In the following sections, we briefly explain these new options and provide examples on how to make effective use of them.

Custom code included at the top of generated code. The text in this dialog box is custom C code that is included at the top of a generated header file. This header file is included at the top of all generated source code files. In other words, all generated code sees code specified by this option. Use this option to include header files that declare custom functions and global data used by generated code. You could also include a set of #define constants that can be used in the charts.

Custom include directory paths. The text input in this dialog box is a space-separated list of paths of directories containing custom header files to be included either directly (see first option above) or indirectly in the compiled target.

Custom source files. The text in this dialog box contains a space-separated list of source files to be compiled and linked into the target. These C source files can contain your custom functions that can be called from within Stateflow diagrams.

Custom initialization code. The input in this dialog box contains code statements that are executed once at the start of simulation. You can use this initialization code to invoke functions that allocate memory or perform other initializations of your custom code.

Custom termination code. The text in this dialog box is the code statements that are executed at the end of simulation. You can use this code to invoke functions that free memory allocated by custom code or perform other cleanup tasks.

For instructions on how to find these target options for the Simulation Target, please refer to the section "Configuring a Target" in the online documentation for Stateflow 2.0 included in the MATLAB HelpDesk.

4. Custom Code Example 1:

We begin with a simple example, called example1.mdl, where we use TRUE and FALSE instead of 1 and 0 in the actions of a Stateflow diagram for better readability. The Simulink model, example1.mdl, inlcuding the Stateflow chart, chart1, is depicted below.


Click to enlarge images

It contains a single Stateflow diagram with two states A and B and one input from Simulink named input_data which can be set to 0 or 1 by flipping the manual switch during simulation. This is a simple example where we use two macros named TRUE and FALSE in the Stateflow diagram, instead of 1 and 0, to move between states. Note that TRUE and FALSE are not defined as Stateflow data objects. The Custom Code property of the Simulation Target for this model contains the following text:


This text is included at the top of the generated Machine Header file, example1_sfun.h, which is included by all the generated code; hence, we can use these macros TRUE and FALSE in all charts belonging to this model.

5. Custom Code Example 2:

In this example, we describe how to access global variables and functions defined in your custom code from Stateflow diagrams. You need the following files for this example:

  1. example2.mdl
  2. example2_src.c
  3. example2_hdr.h

Download these and save them all in the same directory.

The custom header file example2_hdr.h contains the following code:
#ifndef EXAMPLE2_HDR_H
#define EXAMPLE2_HDR_H
/* The above is an include guard that makes sure that */
/* this header file is included only once. extern */
/* declaration of the global variable. It is */
/* "defined" in the source file example2_src.c */


extern int myglobal;


/* extern declaration of the custom function */
/* defined in the source file example2_src.c*/


extern int my_function(int var1, double var2);


/* Constant definitions shared by the */
/* Stateflow generated code and custom-code */
#define TRUE 1
#define FALSE 0
#define MAYBE 2
#endif /*EXAMPLE2_HDR_H */

The custom source file example2_src.c contains the following code:
#include "example2_hdr.h"
/* Definition of the global variable */
int myglobal=0;
int my_function(int var1, double var2)
{
if(myglobal<10) {
  myglobal++;
  return(FALSE);
}else if(myglobal<15) {
  myglobal--;
  return(TRUE);
}
return(MAYBE);
}

For the purposes of illustration, this Simulink model contains only a single Stateflow chart with two states A and B. This chart has three data objects defined: input data named input_data, local data named local_data, and output data named output_data. Notice that we are calling the custom function my_function with arguments that are the Stateflow local data and input data and the output is the chart's output. We are also accessing the global variable myglobal in the state entry and during action to display it.


Click to enlarge images

In the following sections, we describe what needs to be entered in various Target properties and what these entries mean.

5.1. Custom Code Included at the top of the generated code:

The Custom Code property of the Simulation target "sfun", includes only the following text:

Since this custom code is included in each of the generated C source files, all the macros, the typedefs defined in example2_hdr.h, are available to the generated code for all the charts. Therefore, using TRUE and FALSE in the actions or conditions in a chart will not result in parsing or compilation errors. Since this code is included in multiple source files that get linked into a single binary, there are some limitations on what can and cannot be included using the Custom Code property.

Examples of code that should not be included through Custom Code property:
You should not include global variable definitions or function bodies through this property. That is, including a line such as:

int x;
or
void myfun(void)
{
/* some stuff */
}

would cause linking errors since these symbols get defined multiple times in the source files of the generated code.

Examples of code that can be included:
You can include extern declarations of variables or functions. That is:

extern int x;
extern void myfun(void);

5.2. Custom Source Files

The Custom Source Files property reads:

The generated makefile will contain this source file so that it is compiled along with all the generated code from Stateflow into a single S-function, making all the functions defined in this source file available to all charts. Note that we did not specify the full-path for this file. This means that the generated makefile looks for it in the directory where the model example2.mdl exists. If you want to include a file which is in a subdirectory relative to the directory of the model, you could specify it using the relative path name notation:

.\subdirectory\myfile.c

You could also specify the absolute full path name, such as d:\directory\subdirectory\myfile.c, but this is not recommended since you have to manually change this property to point to new locations if you move your files and the model. Using relative path names will shield you from the complexity of managing the path names as they change.

You can use forward slashes (/) or backward slashes (\) as file separators irrespective of whether you are on UNIX or PC. The makefile generator will parse these strings and return the path names with the correct platform-specific file-separators. If you want to specify more than one source file, you can do so by separating them with either commas, spaces, or new lines.

IMPORTANT: If you make a change in one of your custom source files or custom include files, and simulate the model again, Stateflow will not rebuild the S-function for the model unless you have made changes to the charts. In order to force the rebuild of the S-function to incorporate the latest versions of your custom source files or include files, you could do one of the following:change one of the charts slightly to force a rebuild

  • go to the Simulation Target properties dialog box and choose the
  • Rebuild All" option

5.3. Custom Include Directory Paths

The Custom Include Directory Paths property reads:

This dialog box contains a single period (.) indicating that all the header files included via the Custom Code property and the custom source files exist in the directory where the model file example2.mdl resides. If you want the makefile to look for included header files in a subdirectory relative to the directory of the model, you could specify it using the relative path name notation:

.\subdirectory

You could also specify the absolute full path name, such as d:\directory\subdirectory, but again this is not recommended because if you move your files and the model from this location, you have to manually change this property.

This dialog box uses the same conventions for slashes and file separators as in the section on Custom Source Files.

In this example, we could have left this property blank, since the directories containing the custom-source files are searched by default for included header files. However, this property is useful if the custom-source files and the included custom header files are in different directories or there are no custom source files and yet we need to include some custom-header files through the Custom Code property of the target.

6. Converting Models containing Custom Code from previous versions of Stateflow

The previous versions of Stateflow (prior to 2.0) used to generate code for the entire model containing multiple charts in a single source file. Hence, the restrictions on what could or could not be included in the Custom Code property in Stateflow 2.0 (described in Section 4.1 above) do not apply in prior versions. The new code generation scheme in Stateflow 2.0 generates multiple source and header files making it possible to generate intelligent incremental code that is essential to building large models with numerous charts. If you have models developed by pre-2.0 versions of Stateflow (i.e., Stateflow versions 1.0, 1.05, 1.06, or 1.07) which have custom code containing global variable definitions and function definitions, you have to convert them manually to work with Stateflow 2.0.

Suppose you had the following text in the Custom Code property of the target:
#define TRUE 1
#define FALSE 0


int x; double y=1.2;
void myfun(void)
{
/* some stuff */
}

where you defined a global variable named x and a function named myfun to be accessed by the generated code. Since this code is included by multiple C source files generated by Stateflow 2.0, the compilation would fail because the symbols x and myfun are defined multiple times.

In order to convert this model to be Stateflow 2.0 compliant, you could follow these steps:

  1. Create a new header file, myheader.h, and keep all the #define macros and extern declarations for global variables and functions. It is also a good practice to have include guards (shown below). For this example, the header file contains:
  2. #ifndef MYHEADER_H
    #define MYHEADER_H

    /* The above is an include guard that */
    /* makes sure that this headerfile */
    /* is included only once. */

    #define TRUE 1
    #define FALSE 0

    extern int x;
    extern double y;

    extern void myfun(void);

    #endif /*MYHEADER_H*/

  3. Create a new source file, mysrc.c, and keep the global variable definitions and functions in it. For this example , the source file contains:
  4. #include "myheader.h"

    int x;
    double y=1.2;

    void myfun(void)
    {
    /* some stuff */
    }

  5. Add the following text to the Simulation target property "Custom Code included at the top of the generated code"

  6. #include "myheader.h"

  7. If you keep these two files, myheader.h and mysrc.c, in the same directory as the model file, then specify the following in the Simulation target property "Custom Source Files":

  8. mysrc.c

  9. If you wish to keep these two files in other directories, refer to sections 5.2 and 5.3 on how to specify the relative of full-path names appropriately for Custom Source Files and Custom Include Directories.
Contact sales
E-mail this page
Print this page
Subscribe to newsletters