Main Content

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 be fcn.

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.

Related Topics