Main Content

Generate Preprocessor Conditionals for Variant Systems

Define Variant Controls

For variant systems, conditional expressions called variant controls determine which variant choice is active. You can specify a variant control as a condition expression, a Simulink.Variant object specifying a condition expression, a MATLAB® variable, or a Simulink.Parameter object. This example shows how to define variant controls as Simulink.Parameter objects.

  1. Open the Model Explorer. Select the base workspace.

  2. In the Model Explorer, select Add > Simulink Parameter. Specify a name for the new parameter.

  3. Use the function Simulink.VariantManager.findVariantControlVars to find and convert MATLAB variables used in variant control expressions into Simulink.Parameter objects. For an example, see Convert Variant Control Variables into Simulink.Parameter Objects.

  4. On the Simulink.Parameter property dialog box, specify the Value and Data type.

  5. Select one of these Storage class values.

  6. Specify the value of the variant control. If the storage class is ImportedDefine(Custom), do the following:

    1. Specify the Header File parameter as an external header file in the Custom Attributes section of the Simulink.Parameter property dialog box.

    2. Enter the values of the variant controls in the external header file.

      Note

      The generated code refers to a variant control as a user-defined macro. The generated code does not contain the value of the macro. The value of the variant control determines the active variant in the compiled code.

      If the variant control is a CompilerFlag custom storage class, the value of the variant control is set at compile time. Use the Configuration Parameters > Code Generation > Custom Code > Additional build information > Defines parameter to add a list of variant controls (macro definitions) to the compiler command line. For example, for variant control VSSMODE, in the text field for the Defines parameter, enter:

      -DVSSMODE=1

      If you want to modify the value of the variant control after generating a makefile, use a makefile option when compiling your code. For example, at a command line outside of MATLAB, enter:

      makecommand -f model.mk DEFINES_CUSTOM="-DVSSMODE=1"

Note

You can define the variant controls using Simulink.Parameter object of enumerated type. This approach provides meaningful names and improves the readability of the conditions. The generated code includes preprocessor conditionals to check that the variant condition contains valid values of the enumerated type.

Configure Model for Generating Preprocessor Conditional Directives

  1. Open the Configuration Parameters dialog box.

  2. Select the Code Generation pane, and set System target file as ert.tlc.

  3. In the Report pane, select Create code generation report.

  4. In the Configuration Parameters dialog box, clear the Ignore custom storage classes parameter. In order to generate preprocessor conditionals, you must use custom storage classes.

  5. In the Variant Subsystem, Variant Source, or Variant Sink block parameter dialog boxes, set the Variant activation time parameter to code compile.

  6. Generate code.

Special Considerations for Generating Preprocessor Conditionals

  • The port numbers and names for each child variant subsystem must belong to a subset of the port numbers and names of the parent Variant Subsystem block.

  • The code generation process checks that there is at least one active variant by using the variant control values stored in the base workspace. The variant control that evaluates to true becomes the active variant. If none of the variant controls evaluates to true, the default variant, if specified, becomes the active variant. The code generation process issues an error if an active variant does not exist.

  • Implement the condition expressions of the variant objects such that only one evaluates to true. The generated code includes a test of the variant objects to determine that there is only one active variant. If this test fails, your code will not compile.

  • If you comment out child subsystems listed in the Variant Choices table in the Variant Subsystem block parameter dialog box, the code generator does not generate code for the commented out subsystems.

  • If the sample time for a default variant differs from that of the other variant choices, the #else preprocessor conditional is not generated for the default variant. Instead, an #if !(<variant conditions>) is generated.

  • For Variant Subsystems, the model_private.h file contains conditional parameter definitions. For example, if the value of a Constant block is a Simulink.Parameter with an ImportedDefine custom storage class, and the Constant block is in a Variant Subsystem, the conditional definition of the Simulink.Parameter is in the model_private.h file.

Generate Variant Control Macros in Same Header File

This example shows how to aggregate multiple variant control macros (#define) into the same generated header file. This aggregation makes it easier for you to manage the complexities inherent in a system with multiple interacting variant conditions.

Explore Example Model

Run the script prepare_rtwdemo_preproc_subsys, which opens the model rtwdemo_preprocessor_subsys and prepares it for this example.

run(fullfile(matlabroot,'examples','ecoder','main','prepare_rtwdemo_preproc_subsys'));

The model contains two Variant Subsystem blocks.

Navigate inside the variant subsystems. The subsystems each have a linear and a nonlinear algorithm variant.

At the root level of the model, open the block dialog box of the variant subsystem labeled LeftController. The algorithm variants in the subsystem activate based on the states of two Simulink.Variant objects, LINEAR and NONLINEAR, in the base workspace.

The state of each object depends on the values of two variant control variables, MODE_A and MODE_B, which are Simulink.Parameter objects in the base workspace. The parameter objects use the custom storage class Define and are configured to appear in the generated code as C-code macros in macros.h.

Change Name of Generated Header File Through Model Data Editor

In this example, change the name of the generated header file from macros.h to variant_controls.h. You must change the file name in each parameter object.

In the model, select Modeling > Model Data Editor.

In the Model Data Editor, select the Parameters tab.

Click the Show/refresh additional information button.

Set the Change view drop-down list to Code.

In the Filter contents box, enter MODE. The Model Data Editor shows two rows that correspond to the parameter objects.

Select both rows. Then, for one of the rows, use the Header File column to change the header file name from macros.h to variant_controls.h. The Model Data Editor applies the change to both rows.

Reduce Maintenance Effort by Creating Custom Storage Class

To change the name of the header file, you must change the configuration of each parameter object. You can use the Model Data Editor to perform batch editing, but when you add a new variant control variable (parameter object), you must remember to specify the name of the header file for that object. Also, the Model Data Editor shows the parameter objects used by only one model at a time.

Instead, you can create a custom storage class and specify the name of the header file only once: In the definition of the custom storage class.

Set your current folder to a writable location.

At the command prompt, copy the built-in SimulinkDemos package into your current folder as myPackage.

copyfile(fullfile(matlabroot,...
    'toolbox','simulink','simdemos','dataclasses','+SimulinkDemos'),...
    '+myPackage','f')

Navigate inside the +myPackage folder to the file Parameter.m and open the file.

Uncomment the methods section that defines the method setupCoderInfo. In the call to the function useLocalCustomStorageClasses, replace 'packageName' with 'myPackage'. When you finish, the section appears as follows:

  methods
    function setupCoderInfo(h)
      % Use custom storage classes from this package
      useLocalCustomStorageClasses(h, 'myPackage');
    end
  end % methods

Save and close the file.

Set your current folder to the folder that contains the package myPackage.

Open the Custom Storage Class Designer.

cscdesigner('myPackage')

Select the custom storage class Define.

Click Copy. A new custom storage class, Define_1, appears. Select this new custom storage class.

Set Name to VariantControlVar.

Set Header file to Specify. In the text box, enter variant_controls.h.

Click Apply, Save, and OK.

At the command prompt, replace the Simulink.Parameter objects MODE_A and MODE_B with myPackage.Parameter objects. Apply the new custom storage class VariantControlVar.

MODE_A = myPackage.Parameter;
MODE_A.Value = 1;
MODE_A.DataType = 'int32';
MODE_A.CoderInfo.StorageClass = 'Custom';
MODE_A.CoderInfo.CustomStorageClass = 'VariantControlVar';

MODE_B = myPackage.Parameter;
MODE_B.Value = 1;
MODE_B.DataType = 'int32';
MODE_B.CoderInfo.StorageClass = 'Custom';
MODE_B.CoderInfo.CustomStorageClass = 'VariantControlVar';

Now, to indicate that a parameter object represents a variant control variable, you can apply the custom storage class VariantControlVar. To change the name of the header file, use the Custom Storage Class Designer.

Related Topics