Main Content

Represent Variant Conditions of Enumerated Type in Generated Code

You can generate code from a Simulink® model using variant control variables with values of Simulink-supported enumeration types. Enumerated types improve code readability because the condition values in control expressions are represented as meaningful names instead of integers. For more information on enumeration types, see Use Enumerated Data in Simulink Models. In this section, you will learn:

  • How to generate C code from a model with variant conditions using enumerated types.

  • How the enumerated values in variant conditions are represented in the generated code.

Use Enumerated Type Derived From Built-In Integer Type

This section explains how to generate C code from a Simulink model with variant condition values of enumerated type derived from the built-in integer type int32.

Open the slexVariantSubsystems model.

model = "slexVariantSubsystems";
open_system(model)

In this model, the Controller block specifies two potential variants, the Linear controller and Nonlinear controller subsystems. The control expression for the Linear controller subsystem is V == ControllerChoice.Linear. The control expression for the Nonlinear controller subsystem is V == ControllerChoice.NonLinear.

blockPath = "slexVariantSubsystems/Controller";
lCtrlPath = model+"/Controller/Linear Controller";
nlCtrlPath = model+"/Controller/Nonlinear Controller";
set_param(lCtrlPath,"VariantControl","V == ControllerChoice.Linear");
set_param(nlCtrlPath,"VariantControl","V == ControllerChoice.Nonlinear");

Here, ControllerChoice is an integer-based enumeration class derived from the built-in data type, int32. The class is defined in the ControllerChoice.m file. The class has two enumeration values, Linear and Nonlinear. These enumerated values have underlying integer values 0 and 1.

type ControllerChoice.m
classdef ControllerChoice < int32
    enumeration
        Linear (0),
        Nonlinear (1),
    end
    %All the methods below can be optionally used to configure
    %the enumeration in the generated code
    methods (Static = true)
        %% Description of the enumeration
        function retVal = getDescription()
            retVal = 'Controller...';
        end
        %% Default value of the enumeration
        function retVal = getDefaultValue()
            retVal = ControllerChoice.Linear;
        end
        %% Specify whether the generated code imports/exports the definition
        %% of the enum used in the variant control expression
        function retVal = getDataScope()
            retVal = 'Exported';
        end
        
        %% Get the header file to import from/export to the definition of the
        %% enumeration in the generated code
        function retVal = getHeaderFile()
            retVal = 'Controller.h';
        end
    end
    
end

Switch Between Variant Choices and Generate Code

1. Click Simulation > Run and see the variant conditions propagate to the blocks. By default, the model use the Linear controller subsystem for simulations.

V = ControllerChoice.Linear;
sim(model);

2. To modify the active choice, set the value of V to ControllerChoice.Nonlinear, then simulate the model again. The model use the Nonlinear controller subsystem during simulation.

V = ControllerChoice.Nonlinear;
sim(model);

3. To generate code that chooses between variants using if and else if conditional statements, specify the Variant activation time of the Controller block to startup.

set_param(blockPath,"VariantActivationTime","startup");

4. Specify the system target configuration file as grt.tlc.

set_param(model, "SystemTargetFile","grt.tlc");

5. In the Apps tab of the toolstrip, navigate to Simulink Coder. For detailed information on settings to generate code, see Generate Code Using Simulink Coder.

6. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window.

slbuild(model);
### Starting build procedure for: slexVariantSubsystems
### Successful completion of build procedure for: slexVariantSubsystems

Build Summary

Top model targets:

Model                  Build Reason                                         Status                        Build Duration
========================================================================================================================
slexVariantSubsystems  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 17.217s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 20.899s

7. In the C Code tab, select Open Report.

8. In the slexVariantSubsystems.c file, the variable slex_V_VariantControlExpression stores the value of the variant control variable V. Its value is set to Nonlinear, which means that the Nonlinear Controller variant choice is the default active variant choice when you execute the code.

cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "slexVariantSubsystems.c");
coder.example.extractLines(cfile, "/* Normal MATLAB Variables with Startup variant activation time */", "/* Block states (default storage) */", 1, 0);
/* Normal MATLAB Variables with Startup variant activation time */
ControllerChoice slex_V_VariantControlExpression = Nonlinear;

9. The code also includes the variant choices Linear and NonLinear guarded by if and else if conditional statements. These conditional statements enable you to conditionally execute startup routines based on the variant condition that evaluates to true. For more information, Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.

coder.example.extractLines(cfile, "/* Outputs for Atomic SubSystem: '<Root>/Controller' */", "/* End of Outputs for SubSystem: '<S1>/Nonlinear Controller' */", 1, 1);
  /* Outputs for Atomic SubSystem: '<Root>/Controller' */
  if (slex_V_VariantControlExpression == Linear) {
    /* Outputs for Atomic SubSystem: '<S1>/Linear Controller' */
    /* Update for DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn' */
    denAccum = (sine2 - 0.09 *
                slexVariantSubsystems_DW.DiscreteTransferFcn_states[0]) - 0.5 *
      slexVariantSubsystems_DW.DiscreteTransferFcn_states[1];

    /* Sum: '<S2>/Add' incorporates:
     *  DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn'
     */
    rtb_VariantMergeForOutportOut1 = ((0.7 *
      slexVariantSubsystems_DW.DiscreteTransferFcn_states[1] +
      slexVariantSubsystems_DW.DiscreteTransferFcn_states[0]) + rtb_sine1) +
      rtb_sine3;

    /* Update for DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn' */
    slexVariantSubsystems_DW.DiscreteTransferFcn_states[1] =
      slexVariantSubsystems_DW.DiscreteTransferFcn_states[0];
    slexVariantSubsystems_DW.DiscreteTransferFcn_states[0] = denAccum;

    /* End of Outputs for SubSystem: '<S1>/Linear Controller' */
    /* End of Outputs for SubSystem: '<Root>/Controller' */
  } else if (slex_V_VariantControlExpression == Nonlinear) {
    /* Outputs for Atomic SubSystem: '<S1>/Nonlinear Controller' */
    /* Sum: '<S3>/Add' incorporates:
     *  Lookup_n-D: '<S3>/1-D Lookup Table'
     *  Sin: '<Root>/sine2'
     */
    rtb_VariantMergeForOutportOut1 = (rtb_sine1 + look1_binlxpw(sine2,
      slexVariantSubsystems_ConstP.uDLookupTable_bp01Data,
      slexVariantSubsystems_ConstP.uDLookupTable_tableData, 10U)) + rtb_sine3;

10. To view the definitions of Linear and Nonlinear choices, open the Controller.h file. The choices are defined using #define macros.

cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "Controller.h");
coder.example.extractLines(cfile, "#ifndef Controller_h_", "/* Controller_h_ */", 1, 1);
#ifndef Controller_h_
#define Controller_h_
#include "rtwtypes.h"

typedef int32_T ControllerChoice;

/* enum ControllerChoice */
#define Linear                         (0)                       /* Default value */
#define Nonlinear                      (1)
#endif                                 /* Controller_h_ */

If you are using Embedded Coder® with an ERT-based system target file, for example, ert.tlc, and you want to generate a code that encloses the Linear and Nonlinear variant choices in preprocessor conditionals #if and #elif, specify the Variant activation time parameter of the Controller block to code compile. These conditions enable you to conditionally compile variant choices as described in Compile Code Conditionally for Variations of Component Represented Using Variant Block.

Use In-Memory Enumerated Type Derived From Simulink.defineIntEnumType

This section explains how to generate code from a model having variant control variables of enumerated type derived from Simulink.defineIntEnumType.

1. Open the slexVariantSubsystems model.

open_system(model)

2. Define an in-memory enumeration class Controller using the Simulink.defineIntEnumType function. The class has two enumeration values, LinearChoice and NonlinearChoice. These enumerated values have underlying integer values 0 and 1.

Simulink.defineIntEnumType('Controller',...
{'LinearChoice','NonlinearChoice'}, [0;1],'Description','Controller',...
'DefaultValue','LinearChoice','HeaderFile','Controller.h','DataScope',...
'Exported');

Specify the control expression for the Linear controller subsystem as V == Controller.LinearChoice and the control expression for the Nonlinear controller subsystem as V == Controller.NonLinearChoice.

set_param(lCtrlPath,"VariantControl","V == Controller.LinearChoice");
set_param(nlCtrlPath,"VariantControl","V == Controller.NonlinearChoice");

2. Set the value of V to Controller.NonlinearChoice.

V = Controller.NonlinearChoice;

3. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window.

slbuild(model);
### Starting build procedure for: slexVariantSubsystems
### Successful completion of build procedure for: slexVariantSubsystems

Build Summary

Top model targets:

Model                  Build Reason                     Status                        Build Duration
====================================================================================================
slexVariantSubsystems  Generated code was out of date.  Code generated and compiled.  0h 0m 8.3629s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 9.3208s

The variable slex_V_VariantControlExpression stores the value of the variant control variable V, as the above example also shows.

cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "slexVariantSubsystems.c");
coder.example.extractLines(cfile, "/* Normal MATLAB Variables with Startup variant activation time */", "/* Block states (default storage) */", 1, 0);
/* Normal MATLAB Variables with Startup variant activation time */
Controller slex_V_VariantControlExpression = NonlinearChoice;

The LinearChoice and NonlinearChoice choices are defined as enumeration in the Controller.h file.

cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "Controller.h");
coder.example.extractLines(cfile, "#ifndef Controller_h_", "/* Controller_h_ */", 1, 1);
#ifndef Controller_h_
#define Controller_h_
#include "rtwtypes.h"

typedef enum {
  LinearChoice = 0,                    /* Default value */
  NonlinearChoice
} Controller;

Note

For variant blocks with the startup activation time, only enumerations that are defined using these techniques are supported:

  • Using the function Simulink.defineIntEnumType.

  • By subclassing built-in integer data types int8, int16, int32, uint8, or uint16, or by subclassing Simulink.IntEnumType. These enumerations are also supported when permanently stored in a Simulink data dictionary. See Enumerations in Data Dictionary.

See Also