Conditionalize Export Function Calls in Code using Variant Blocks
This example explains how to generate code for export-function models containing variant blocks. Export-function models are Simulink® models that generate code for independent functions that you can integrate with an external environment or scheduler. With variant blocks, you can include multiple implementations of an independent function in the generated code.
This example uses a Variant Subsystem block that contains Function-Call Subsystem blocks, a type of conditional subsystem, to create an export-function model. During simulation, the variant conditions assigned to the Variant Subsystem block propagate to the connected blocks, determining the active variant choice. The variant conditions that propagate to the function-call subsystems apply to all the ports of the subsystems. For more information on export-function models, see Export-Function Models Overview.
When you use conditionally executed subsystems as variant choices:
All variant choices within a Variant Subsystem block must have control port blocks of the same type. For example, you cannot use different types of control port blocks, such as enabled subsystems and function-call subsystems, within the same Variant Subsystem block.
The control port on the Variant Subsystem block and the corresponding control ports on its variant choices must have the same name. For example, if the name of the control port on the Variant Subsystem is
fcn
, then the name of the corresponding control ports on all its variant choices must also befcn
.
When using conditional subsystems as variant choices in a Variant Subsystem block, any properties set on its input, output, and control ports are ignored during simulation and code generation.
Prerequisites
We recommend completing the Propagate Variant Conditions to Control Execution of Conditional Subsystems example to learn more about how to use variant blocks with conditional subsystems.
Explore the Model
Open the slexVariantSubsystemExportFunction
model.
model = "slexVariantSubsystemExportFunction";
open_system(model)
The Variant Subsystem block VariantFcnCall
contains Function-Call Subsystem blocks, Linear
and Nonlinear
, as its variant choices. The Linear
block has the variant condition VSSMODE == 0
and the Nonlinear
block has the variant condition VSSMODE == 1
. The input port fcn
of VariantFcnCall
corresponds to the control input ports on the variant choice blocks. During simulation, the VariantFcnCall
block gets the variant condition of the signal connected to the fcn
port. The variant condition assigned to the block then propagates to the blocks connected to its input and output ports.
When you simulate the model, the logical OR
of variant conditions from the variant choices, VSSMODE == 0
|| VSSMODE == 1
, propagates to the VariantFcnCall
block and its ports. During simulation, if VSSMODE == 0
evaluates to true
, the Linear
block runs each time fcn
receives a function-call event. If VSSMODE == 1
evaluates to true
, the Nonlinear
block runs each time fcn
receives a function-call event.
sim(model);
To explore how the variant conditions from a Variant Subsystem block propagate to other conditional subsystems such as enabled subsystems, simulate the slexVariantSubsystemEnableChoice
model and observe the results. For more information on enabled subsystems, see Using Enabled Subsystems.
Generate Code for Export-Function Model
When you generate code from this model, the root-level function-call block fcn
generates a void-void function. To generate code:
1. In the Apps tab of the toolstrip, navigate to Embedded Coder.
2. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window.
slbuild(model);
### Starting build procedure for: slexVariantSubsystemExportFunction ### Successful completion of build procedure for: slexVariantSubsystemExportFunction Build Summary Top model targets: Model Build Reason Status Build Duration ===================================================================================================================================== slexVariantSubsystemExportFunction Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 9.7479s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 10.499s
3. Locate and select Code Interface Report from the left pane. Observe that the Function name is the name of the output signal from the block. If there is no signal name, then the function name is the name of the block. In this example, the function name fcn
is derived from the block name.
4. Locate and select the slexVariantSubsystemExportFunction.c
file from the left pane. Because the Variant activation time parameter of VariantFcnCall
is set to code compile
, the definition of the function fcn
contains the C preprocessor conditionals #if
and #endif
. The code for the Linear
and Nonlinear
variant choices are guarded by the corresponding variant conditions, allowing for conditional compilation based on specific variant choices. For more information, see Compile Code Conditionally for Variations of Component Represented Using Variant Block.
You can change the setting of the Variant activation time parameter to customize the generated code to include code only for the Linear
or Nonlinear
block. Also, you can choose to generate a code that guards the Linear
and Nonlinear
choices in if
conditional statements, enabling conditional execution of startup routines based on specific variant choices as described in Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
For more information on variant activation time, see Activate Variant During Different Stages of Simulation and Code Generation Workflow.
cfile=fullfile(pwd, "slexVariantSubsystemExportFunction_ert_rtw", "slexVariantSubsystemExportFunction.c"); coder.example.extractLines(cfile, "/* Model step", "/* Model initialize", 1, 0);
/* Model step function */ void fcn(void) { #if VSSMODE == 0 /* RootInportFunctionCallGenerator generated from: '<Root>/fcn' */ /* Outputs for Function Call SubSystem: '<S1>/Linear' */ /* DiscreteFilter: '<S2>/Discrete Filter' incorporates: * Inport: '<Root>/In1' */ rtY.Out1 = rtU.In1 - 0.5 * rtDWork.DiscreteFilter_states_a; /* Update for DiscreteFilter: '<S2>/Discrete Filter' */ rtDWork.DiscreteFilter_states_a = rtY.Out1; /* End of Outputs for SubSystem: '<S1>/Linear' */ #elif VSSMODE == 1 /* Outputs for Function Call SubSystem: '<S1>/Nonlinear' */ /* DiscreteFilter: '<S2>/Discrete Filter' incorporates: * DiscreteFilter: '<S3>/Discrete Filter' * Inport: '<Root>/In1' * Lookup_n-D: '<S3>/Lookup Table' */ rtY.Out1 = look1_binlxpw(rtU.In1, rtConstP.LookupTable_bp01Data, rtConstP.LookupTable_tableData, 4U) - 0.5 * rtDWork.DiscreteFilter_states; /* Update for DiscreteFilter: '<S3>/Discrete Filter' */ rtDWork.DiscreteFilter_states = rtY.Out1; /* End of Outputs for SubSystem: '<S1>/Nonlinear' */ #endif /* End of Outputs for RootInportFunctionCallGenerator generated from: '<Root>/fcn' */ }
You can also have a similar modeling pattern with a multi-point entry function using Model blocks. In this example, the inputs fcln1
, fcln2
, and fcln3
are routed through a Variant Subsystem block Model
that uses the Model blocks as variant choices.
Guard Export Function Definition in Generated Code
To guard the whole definition of the export function fcn
, connect a Variant Source block that has one input and one output to the fcn
port. Specify the variant condition of the Variant Source block as inputFcn == 1
and set the Variant activation time parameter to code compile
.
1. Open the slexVariantSubsystemExportFunction.c
file. The definition of the export function fcn
is guarded with the variant condition inputFcn == 1
.
#if inputFcn == 1 void fcn(void) { ... } #endif
2. Open the ert_main.c
file. The function call is also guarded with the variant condition inputFcn == 1
.
void sample_usage_fcn(void) { #if inpFcn == 1 fcn(); #endif
To explore how to create export-function models for function-call subsystems connected to Variant Source blocks, simulate the slexVariantExportedFcn
model and observe the results.