Main Content

Generate Source and Header Files with a Custom File Processing (CFP) Template

This example shows you the process of generating a simple source (.c or .cpp) and header (.h) file using the example CFP template. Then, it examines the template and the code generated by the template.

The example CFP template, matlabroot/toolbox/rtw/targets/ecoder/example_file_process.tlc, demonstrates some of the capabilities of the code template API, including

  • Generation of simple source (.c or .cpp) and header (.h) files

  • Use of buffers to generate file sections for includes, functions, and so on

  • Generation of includes, defines, into the standard generated files (for example, model.h)

  • Generation of a main program module

Generate Code with a CFP Template

This section sets up a CFP template and configures a model to use the template in code generation. The template generates (in addition to the standard model files) a source file (timestwo.c or .cpp) and a header file (timestwo.h).

Follow the steps below to become acquainted with the use of CFP templates:

  1. Copy the example CFP template, matlabroot/toolbox/rtw/targets/ecoder/example_file_process.tlc, to a folder outside of the MATLAB® folder structure (that is, not under matlabroot). If the folder is not on the MATLAB path or the TLC path, then add it to the MATLAB path. It is good practice to locate the CFP template in the same folder as your system target file, which is on the TLC path.

  2. Rename the copied example_file_process.tlc to test_example_file_process.tlc.

  3. Open test_example_file_process.tlc into the MATLAB editor.

  4. Uncomment the following line:

    %%  %assign ERTCustomFileTest = TLC_TRUE

    It now reads:

      %assign ERTCustomFileTest = TLC_TRUE

    If ERTCustomFileTest is not assigned as shown, the CFP template is ignored in code generation.

  5. Save your changes to the file. Keep test_example_file_process.tlc open, so you can refer to it later.

  6. Open the UserDefinedDataTypes model.

  7. Open the Simulink® Model Explorer. Select the active configuration set of the model, and open the Code Generation pane of the active configuration set.

  8. On the Templates tab, in the File customization template field, specify test_example_file_process.tlc. This is the file you previously edited and is now the specified CFP template for your model.

  9. On the General tab, select the Generate code only check box.

  10. Click Apply.

  11. In the model window, press Ctrl+B. During code generation, notice the following message in the Diagnostic Viewer:

    Warning:  Overriding example ert_main.c!
    

    This message is displayed because test_example_file_process.tlc generates the main program module, overriding the default action of the ERT target. This is explained in greater detail below.

  12. The UserDefinedDataTypes model is configured to generate an HTML code generation report. After code generation is complete, view the report.

    Notice that the Generated Code list contains the following files:

    • Under Main file, ert_main.c.

    • Under Other files, timestwo.c and timestwo.h.

    The files were generated by the CFP template. The next section examines the template to learn how this was done.

  13. Keep the model, the code generation report, and the test_example_file_process.tlc file open so you can refer to them in the next section.

Analysis of the Example CFP Template and Generated Code

This section examines excerpts from test_example_file_process.tlc and some of the code it generates. Refer to the comments in matlabroot/rtw/c/tlc/mw/codetemplatelib.tlc while reading the following discussion.

Generating Code Files

Source (.c or .cpp) and header (.h) files are created by calling LibCreateSourceFile, as in the following excerpts:

%assign cFile = LibCreateSourceFile("Source", "Custom", "timestwo")
...
%assign hFile = LibCreateSourceFile("Header", "Custom", "timestwo")

Subsequent code refers to the files by the file reference returned from LibCreateSourceFile.

File Sections and Buffers

The code template API lets you partition the code generated to each file into sections, tagged as Definitions, Includes, Functions, Banner, and so on. You can append code to each section as many times as required. This technique gives you a great deal of flexibility in the formatting of your custom code files.

Subsections Defined for Built-In Sections describes the available file sections and their order in the generated file.

For each section of a generated file, use %openfile and %closefile to store the text for that section in temporary buffers. Then, to write (append) the buffer contents to a file section, call LibSetSourceFileSection, passing in the desired section tag and file reference. For example, the following code uses two buffers (typesBuf and tmpBuf) to generate two sections (tagged "Includes" and "Functions") of the source file timestwo.c or .cpp (referenced as cFile):

%openfile typesBuf

#include "rtwtypes.h"

%closefile typesBuf

%<LibSetSourceFileSection(cFile,"Includes",typesBuf)>

 %openfile tmpBuf

 /* Times two function */
 real_T timestwofcn(real_T input) {
   return (input * 2.0);
}

%closefile tmpBuf

%<LibSetSourceFileSection(cFile,"Functions",tmpBuf)>

These two sections generate the entire timestwo.c or .cpp file:

#include "rtwtypes.h"

/* Times two function */
FLOAT64 timestwofcn(FLOAT64 input)
{
  return (input * 2.0);
}

Adding Code to Standard Generated Files

The timestwo.c or .cpp file generated in the previous example was independent of the standard code files generated from a model (for example, model.c or .cpp, model.h, and so on). You can use similar techniques to generate custom code within the model files. The code template API includes functions to obtain the names of the standard models files and other model-related information. The following excerpt calls LibGetMdlPubHdrBaseName to obtain the name for the model.h file. It then obtains a file reference and generates a definition in the Defines section of model.h:

%% Add a #define to the model's public header file model.h

%assign pubName = LibGetMdlPubHdrBaseName()
%assign modelH  = LibCreateSourceFile("Header", "Simulink", pubName)

%openfile tmpBuf

 #define ACCELERATION 9.81

 %closefile tmpBuf

%<LibSetSourceFileSection(modelH,"Defines",tmpBuf)>

Examine the generated UserDefinedDataTypes.h file to see the generated #define directive.

Customizing Example Main Program Module Generation

ERT-based system target files determine whether and how to generate an example main program module (ert_main.c or ert_main.cpp) based on the settings of the model configuration parameters Generate an example main program and Target operating system. You can override the default behavior and generate a main program customized for your target environment.

Two TLC files support generation of an example main program module:

  • bareboard_srmain.tlc: TLC code for generating a single-rate example main program module for a bare-board target environment. TLC function FcnSingleTaskingMain generates the code.

  • bareboard_mrmain.tlc: TLC code for generating a multirate example main program module for a bare-board target environment. TLC function FcnMultiTaskingMain generates the code.

In the example CFP template file matlabroot/toolbox/rtw/targets/ecoder/example_file_process.tlc, this code generates a single- or multitasking example main program module. The logic depends on information obtained from the code template calls to LibIsSingleRateModel and LibIsSingleTasking.

%% Create a simple main.  Files are located in MATLAB/rtw/c/tlc/mw.

 %if LibIsSingleRateModel() || LibIsSingleTasking()
   %include "bareboard_srmain.tlc"
   %<FcnSingleTaskingMain()>
 %else
   %include "bareboard_mrmain.tlc"
   %<FcnMultiTaskingMain()>
 %endif

Files bareboard_srmain.tlc and bareboard_mrmain.tlc use the code template programming interface to generate the example main program modules ert_main.c or ert_main.cpp.

By default, the code generator produces an example main program module. To disable generation of that module, set the TLC variable OverrideSampleERTMain to TLC_TRUE.

For example:

%if GenerateSampleERTMain
    %assign CompiledModel.OverrideSampleERTMain = TLC_TRUE
    %warning Overriding example ert_main.c!
%endif

Alternatively, you can implement a SelectCallback function for your target. A SelectCallback function is a MATLAB function that is triggered when you:

  • Select a target by setting the System target file configuration parameter.

  • Build the model.

Your SelectCallback clears the model configuration parameter Generate an example main program. Clearing the parameter prevents TLC variable GenerateSampleERTMain from being set to TLC_TRUE.

For information on how to create a SelectCallback function, see rtwgensettings Structure.

This code shows how to clear the Generate an example main program parameter in the context of a SelectCallback function.

slConfigUISetVal(hDlg, hSrc, 'GenerateSampleERTMain', 'off');
slConfigUISetEnabled(hDlg, hSrc, 'GenerateSampleERTMain',0);
hSrc.getConfigSet.refreshDialog;

Creation of a main program for your target environment requires customization. For example, in a bare-board environment, you need to attach rt_OneStep to a timer interrupt and customize the generated code, the generating TLC code, or both. For more information, see Guidelines for Modifying Main Program and Guidelines for Modifying rt_OneStep.

Generate a Custom Section

You can define custom tokens in a CGT file and direct generated code into an associated built-in section. This feature gives you additional control over the formatting of code within each built-in section. For example, you could add subsections to built-in sections that do not already define subsections. Custom sections must be associated with one of the built-in sections: Includes, Defines, Types, Enums, Definitions, Declarations, or Functions. To create custom sections, you must

  • Add a custom token to the code insertion section of your CGT file.

  • In your CFP file:

    • Assemble code to be generated to the custom section into a buffer.

    • Declare an association between the custom section and a built-in section, with the code template API function LibAddSourceFileCustomSection.

    • Emit code to the custom section with the code template API function LibSetSourceFileCustomSection.

The following code examples illustrate the addition of a custom token, Myincludes, to a CGT file, and the subsequent association of the custom section Myincludes with the built-in section Includes in a CFP file.

Note

If you have not already created custom CGT and CFP files for your model, copy the default template files matlabroot/toolbox/rtw/targets/ecoder/ert_code_template.cgt and matlabroot/toolbox/rtw/targets/ecoder/example_file_process.tlc to a work folder that is outside the MATLAB folder structure but on the MATLAB or TLC path, rename them (for example, add the prefix test_ to each file), and update the Templates pane of the Configuration Parameters dialog box to reference them.

First, add the token Myincludes to the code insertion section of your CGT file. For example:

%<Includes>
%<Myincludes>
%<Defines>
%<Types>
%<Enums>
%<Definitions>
%<Declarations>
%<Functions>

Next, in the CFP file, add code to generate include directives into a buffer. For example, in your copy of the example CFP file, you could insert the following section between the Includes section and the Create a simple main section:

%% Add a custom section to the model's C file model.c

%openfile tmpBuf
#include "moretables1.h"
#include "moretables2.h"
%closefile tmpBuf

%<LibAddSourceFileCustomSection(modelC,"Includes","Myincludes")>
%<LibSetSourceFileCustomSection(modelC,"Myincludes",tmpBuf)>

The LibAddSourceFileCustomSection function call declares an association between the built-in section Includes and the custom section Myincludes. Myincludes is a subsection of Includes. The LibSetSourceFileCustomSection function call directs the code in the tmpBuf buffer to the Myincludes section of the generated file. LibSetSourceFileCustomSection is syntactically identical to LibSetSourceFileSection.

In the generated code, the include directives generated to the custom section appear after other code directed to Includes.

#include "UserDefinedDataTypes.h"
#include "UserDefinedDataTypes_private.h"

/* #include "mytables.h" */
#include "moretables1.h"
#include "moretables2.h"

Note

The placement of the custom token in this example CGT file is arbitrary. By locating %<Myincludes> after %<Includes>, the CGT file specifies only that the Myincludes code appears after Includes code.

Custom Tokens

Custom tokens are automatically translated to TLC syntax as a part of the build process. To escape a token, that is to prepare it for normal TLC expansion, use the '!' character. For example, the token %<!TokenName> is expanded to %<TokenName> by the template conversion program. You can specify valid TLC code, including TLC function calls: %<!MyTLCFcn()>.

Custom tokens are not supported when you generate C++ code.