Generate Preprocessor Conditionals for Variant Systems
Define Variant Controls
For variant systems, 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.
Open the Model Explorer. Select the base workspace. Alternatively, you can create a
Simulink.Parameter
in data dictionary.In the Model Explorer, select Add > Simulink Parameter. Specify a name for the new parameter.
Use the function
Simulink.VariantManager.findVariantControlVars
to find and convert MATLAB variables used in variant control expressions intoSimulink.Parameter
objects. For an example, see Convert Variant Control Variables into Simulink.Parameter Objects.On the
Simulink.Parameter
property dialog box, specify the Value and Data type.Select one of these Storage class values.
Define
ImportedDefine(Custom)
CompilerFlag(Custom)
A storage class created using the Custom Storage Class Designer. Your storage class must have the Data initialization parameter set to
Macro
and the Data scope parameter set toImported
. See Control Data Representation by Configuring Storage Class Properties for more information.
Specify the value of the variant control. If the storage class is
ImportedDefine(Custom)
, do the following:Specify the Header File parameter as an external header file in the Custom Attributes section of the
Simulink.Parameter
property dialog box.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 > Code information > Defines parameter to add a list of variant controls (macro definitions) to the compiler command line. For example, for variant controlVSSMODE
, 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
Open the Configuration Parameters dialog box.
Select the Code Generation pane, and set System target file as
ert.tlc
.In the Report pane, select Create code generation report.
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.
In the Variant Subsystem, Variant Source, or Variant Sink block parameter dialog boxes, set the Variant activation time parameter to
code compile
.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 totrue
, 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 controls such that only one variant control evaluates to
true
. The generated code includes a test of the variant controls 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.
For Variant Subsystems, the
model_private.h
file contains conditional parameter definitions. For example, if the value of a Constant block is aSimulink.Parameter
with anImportedDefine
custom storage class, and the Constant block is in a Variant Subsystem, the conditional definition of theSimulink.Parameter
is in themodel_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_preproc_subsys
, which opens the model PreprocessorConditionalsUsingVariantSubsystem
and prepares it for this example.
prepare_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 value of the variant control variable, VSSMODE
, which is a Simulink.Parameter
object in the base workspace. The parameter object uses the custom storage class Define
and is configured to appear in the generated code as a C-code macro in macros.h
.
Change Name of Generated Header File Through Model Explorer
In this example, change the name of the generated header file from macros.h
to variant_controls.h
.
On the Modeling tab, select Model Explorer.
In the Model Hierarchy pane, expand Simulink Root
and select Base Workspace
. The Contents pane displays all the objects in the base workspace.
Select VSSMODE
and then in the Simulink.Parameter:VSSMODE pane, click the Code Generation tab.
In the HeaderFile parameter, specify the name of the file as variant_controls.h
.
Alternatively, you can change the file name programmatically, by using this command. For more information on Simulink.CoderInfo
, see Simulink.CoderInfo
.
Simulink.CoderInfo.CustomAttributes.HeaderFile = 'variant_controls.h';
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. Copy the demodata
package into your current folder as myPackage
.
copyfile('demodata','+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
object VSSMODE
with myPackage.Parameter
object. 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.