Main Content

Programmatically Configure C++ Interface

To streamline the integration of C++ code generated from Simulink® applications, components, and subsystems with external C or C++ code, configure a customized C++ class interface. When you generate C++ code from a model, the model appears as a class, the data elements appear as class members, and the model functions appear as class methods in the generated code. Configuring a C++ class interface enables you to customize the following aspects of the generated C++ code:

  • Class information — Class name and namespace

  • Class member information — Class member access and visibility

  • Class method information — Class method names and arguments

A customized C++ class interface enables the generated classes to meet specific code standards or interface requirements so that the generated code can compile and integrate into larger architectures with minimal post-generation customization.

Programmatic Workflow Overview

The programmatic workflow uses a programmatic interface that you can call into by using the MATLAB® command line or a MATLAB script to configure a customized C++ class interface. Additionally, you can use the functions to facilitate scripting, automated testing, and developing or utilizing downstream features. The programmatic interface is composed of the following functions:

To programmatically configure a customized C++ interface, follow the outlined workflow:

Open Environment

Open the environment for configuring a customized C++ class interface:

  1. Open the model and the MATLAB command prompt. Alternatively, you can create a MATLAB configuration script.

    model='rtwdemo_cpp_workflow'
    open_system(model)
    
  2. Set model configuration parameters. These parameters configure model-wide code generation behavior. To configure parameters specific to generating a customized C++ class interface, you can use the set_param function to set these parameters:

    Configuration ParameterDescription
    Code interface packagingSelects output language for generated code. For more information, see Code interface packaging.
    Multi-instance code error diagnostic

    Specifies the severity level for diagnostics displayed when a model violates requirements for generating multi-instance code. For more information, see Multi-instance code error diagnostic.

    Remove error status field in real-time model data structure

    Specifies whether to omit the error status field from the generated real-time model data structure rtModel. For more information, see Remove error status field in real-time model data structure.

    Include model types in model class

    Specifies to include model type definitions within the class namespace of the model. For more information, see Include model types in model class.

    Interface parameters that are related, but are less commonly used:

    Configuration ParameterDescription
    Terminate function required

    Specifies whether to generate the model_terminate method. For more information, see Terminate function required.

    Combine signal/state structures

    Specifies whether to combine global block signals and global state data into one data structure in the generated code. For more information, see Combine signal/state structures.

    Generate destructor

    Specifies whether to generate a destructor for the C++ model class. For more information, see Generate destructor.

    Use dynamic memory allocation for model block instantiation

    Specifies memory allocation for model hierarchies. For more information, seeUse dynamic memory allocation for model block instantiation.

  3. To configure a customized C++ class interface for a model, create a Code Mappings object. To create a new Code Mappings object for a model, use the function coder.mapping.utils.create. If a Code Mappings object already exists for the model, the function returns the existing object.

    % Create a new Code Mappings object for a model 
    cm = coder.mapping.utils.create(model);

Configure Model as Class

Configure the class name and namespace. When you generate C++ code from a model, that model appears as a class in the generated code. To ease integration and comply with code and interface requirements, you can customize the generated class name. Optionally, you can scope the generated code and prevent symbol clashes within a project by specifying a namespace for the generated class. In modeled systems that use a model hierarchy, you can specify a different namespace for each model in the hierarchy.

The generated C++ class interface, declared in the model header file, incorporates the customized name and namespace:

// File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
    // public data and function members
   public:

    // private data and function members     
   private:

  };
}

Workflow

To programmatically configure the class name and namespace, get the Code Mappings object for your model and set the name and namespace:

  1. Get the Code Mappings object for your model. To get the object, use the function coder.mapping.api.get.

    % Get the Code Mappings object for a model 
    cm = coder.mapping.api.get(model);
    
  2. Configure the class name. To set the class name, use the function setClassName.

    % Set the class name
    setClassName(cm, 'customized_ModelClass');
    

    To verify the new class name before generating code, use the function getClassName.

    % Get the class name
    getClassName(cm);
    
  3. Configure the class namespace. To set the namespace, use the function setClassNamespace.

    % Set the class namespace
    setClassNamespace(cm, 'customized_namespace');

    To verify the new namespace before generating code, use the function getClassNamespace.

    % Get the class namespace
    getClassNamespace(cm);

Configure Model Data Elements as Class Members

Configure the visibility and access of class members. When you generate C++ code from a model, Simulink data elements appear as class members in the generated code. To adjust the encapsulation of the class data to meet code standards, security, or performance requirements, you can customize the visibility and access of the generated class members. Simulink data elements can be grouped into the following categories of modeling elements:

Model Element CategoryDescription
Inports

Root-level data input ports of a model, such as Inport and In Bus Element blocks. For more information, see Inport.

Outports

Root-level data output ports of a model, such as Outport and Out Bus Element blocks. For more information, see Outport.

Model parameter arguments

Workspace variables that appear as instance (nonstatic) class data members.

Model parameters

Workspace variables that are shared across instances of the model class that are generated as static class data members.

Signals, states, and internal data

Data elements that are internal to a model, such as block output signals, discrete block states, data stores, and zero-crossing signals.

For each model element category, you can configure the data visibility to control the access modifier (access specifier) of the generated class members. Each option and its impact on the generated C++ class interface, declared in the model header file, is outlined:

Data Visibility OptionsDescription
public

If you configure data elements as public, they appear as public members of the generated class:

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
  
    // example inport
    ExtU rtU;

    // example outport
    ExtY rtY;
  
    // example block signals and states
    DW rtDW;
     
   private:
    … 
  };
}

protected

If you configure data elements as protected, they appear as protected members of the generated class:

File: rtwdemo_cpp_workflow.h

// Class declaration for model example_model
namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:

   protected:

    // example inport
    ExtU rtU;

    // example outport
    ExtY rtY;
  
    // example block signals and states
    DW rtDW;   

   private:
    … 
  };
}
private

If you configure elements as private, they appear as private members of the generated class:

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
    
   private:
    // example inport
    ExtU rtU;

    // example outport
    ExtY rtY;
  
    // example block signals and states
    DW rtDW;
  };
}
Individual arguments (Model parameter arguments only)

If you configure data elements as Individual arguments, the elements do not appear as members of the class, but are instead defined outside the class and passed as arguments to class methods:

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:

   // model step function
   void step1(real_T rty_engineState,
     const real_T modelParameterArgument);
    
   private:
    … 
  };
}

After you set the data visibility of a model element category, you can configure the data access method to determine how the get and set methods are generated for the data elements. This configuration controls how application code can view and modify the class member data. Each option and its impact on the generated C++ class interface, declared in the model header file, is outlined:

Member Access Method OptionsDescription
Method

If you configure inports as Method, a set method appears for each inport. If you configure outports as Method, a get method appears for each outport in the model. If you configure the other model element categories as Method, an aggregate structure-based get and set method appears for the data element category.

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
   // example inport
   void setInport(real_T localArgInput);

   // example outport
   real_T getOutport() const;

   // example of model parameter arguments configured with
   // ‘DataAccess’ ‘Direct'
   real_T const & getInstP() const;

   // example of model parameter arguments configured with
   // ‘DataAccess’ ‘Pointer’
   // real_T const * getInstP() const;

   // example Block parameters get and set methods
   const rtwdemo_cppclass_workflowModelClass::rtwdemo_cppclass_workflow_P &
     getBlockParameters() const;
 
   void setBlockParameters(const rtwdemo_cppclass_workflow_P
     *prtwdemo_cppclass_workflowrtrtP);

   // example Block states get and set methods
  const rtwdemo_cppclass_workflowModelClass::rtwdemo_cppclass_workflow_DW &
    getDWork() const;
 
  void setDWork(const rtwdemo_cppclass_workflow_DW
                *prtwdemo_cppclass_workflowrtDW);
    
   private:
    … 
  };
}
Inlined method

If you configure inports as Inlined method, a set method defined in its declaration appears for each inport. If you configure outports as Inlined method, a get method defined in its declaration appears for each outport in the model. If you configure the other model element categories as Inlined method, an aggregate structure-based get and set method defined in its declaration appears for the data element category.

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
   // example inport set method
   void setkeyState(real_T localArgInput)
   {
     rtU.keyState = localArgInput;
   }
 
   // example outport get method
   const real_T* getengineState() const
   {
     return rtY.engineState;
   }

   // example Block parameters get and set method
   const rtwdemo_cppclass_workflowModelClass::rtwdemo_cppclass_workflow_P &
     getBlockParameters() const
   {
     return rtwdemo_cppclass_workflowrtrtP;
   }
 
   void setBlockParameters(const rtwdemo_cppclass_workflow_P
     *prtwdemo_cppclass_workflowrtrtP)
   {
     rtwdemo_cppclass_workflowrtrtP = *prtwdemo_cppclass_workflowrtrtP;
   }

  // example Block states get and set methods
   const rtwdemo_cppclass_workflowModelClass::rtwdemo_cppclass_workflow_DW &
     getDWork() const
   {
     return rtwdemo_cppclass_workflowrtDW;
   }
 
   void setDWork(const rtwdemo_cppclass_workflow_DW
                 *prtwdemo_cppclass_workflowrtDW)
   {
     rtwdemo_cppclass_workflowrtDW = *prtwdemo_cppclass_workflowrtDW;
   }
     
   private:
    … 
  };
}
Structure-based method

If you configure the inports as Structure-based method, the inports appear as an aggregate structure-based set method for the model element category. If you configure the outports as Structure-based method, the outports appear as aggregate structure-based get method for the model element category. This configuration option does not apply to the other model element categories.

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
    // public data and function members
   public:
   // example inport
   void setExternalInputs(const ExtU_demoMethodScheduledModel_T 
      * pExtU_demoMethodScheduledModel_T);
 
   // example outport 
   const myNamespace::myModelClass::ExtY_demoMethodScheduledModel_T
      & getExternalOutputs() const;

    // Other model element categories may not be configured as ‘Structure-based method’
        
   private:
    … 
  };
}
Inlined structure-based method

If you configure the inports as Structure-based method, the inports appear as aggregate structure-based set method defined in its declaration for the model element category. If you configure the outports to Structure-based method, the outports appear as aggregate structure-based get method defined in their declaration for the model element category. This configuration option does not apply to the other model element categories.

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
   // example inport
   void setExternalInputs(const ExtU_demoMethodScheduledModel_T
      * pExtU_demoMethodScheduledModel_T)
   {
      demoMethodScheduledModelWithR_U = *pExtU_demoMethodScheduledModel_T;
   }
 
    // example outport
   const myNamespace::myModelClass::ExtY_demoMethodScheduledModel_T
      & getExternalOutputs() const
   {
      return demoMethodScheduledModelWithR_Y;
   }
   // Other model element categories may not be configured as ‘Inlined structure-based method’
    
   private:
    … 
  };
}
None

If you configure the access of a model element category as None, get and set methods do not appear in the generated class and data can be accessed directly by application code.

File: rtwdemo_cpp_workflow.h

  // External inputs (root inport signals with default storage)
  struct ExtU {
    real_T keyState;                   // '<Root>/keyState'
  };
 
  // External outputs (root outports fed by signals with default storage)
  struct ExtY {
    real_T engineState[3];             // '<Root>/engineState'
    real_T cycleTime;                  // '<Root>/cycleTime'
  };

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
   // External inputs
   ExtU rtU;
 
   // External outputs
   ExtY rtY;
        
   private:
    … 
  };
}

For each model element category, valid data visibility and member access method combinations are outlined:

Model Element CategoryData VisibilityMember Access Method
Inportsprivate

Method

Inlined method

Structure-based method

Inlined structure-based method

public

None

Method

Inlined method

Structure-based method

Inlined structure-based method

Outportsprivate

Method

Inlined method

Structure-based method

Inlined structure-based method

public

None

Method

Inlined method

Structure-based method

Inlined structure-based method

Model parameter argumentsIndividual arguments

None

private

Method

Inlined method

Model parametersprivate

None

Method

Inlined method

public

None

Method

Inlined method

Signals, states, and internal dataprivate

None

Method

Inlined method

public

None

Method

Inlined method

Workflow

To programmatically configure class member visibility and access, get the Code Mappings object for the model and set the data access and visibility properties:

  1. Get the Code Mappings object for the model. To get the object, use the function coder.mapping.api.get.

    % Get the Code Mappings object
    cm = coder.mapping.api.get(model);
  2. Configure the visibility. To set the data visibility of a category of Simulink data elements in the generated code, use the function setData. When you use the setData function, specify the Code Mappings object, model element category, data visibility property, and data visibility option. Valid data visibility options vary depending on the model element category.

    % Set the data visibility of Simulink model data elements by category 
    % setData(Code Mappings object, model element category, 'DataVisibility', data visibility option)
    setData(cm, 'Outports', 'DataVisibility', 'private');
    

    To verify the data visibility setting before generating code, use the function getData:

    % Get the data visibility of Simulink model data elements by category 
    % getData(code mappings object, model element category, 'DataVisibility')
    getData(cm, 'Outports', 'DataVisibility');
    
  3. Configure the access. To set the member access method of a category of Simulink data elements in the generated code, use the function setData. When you use the setData function, specify the Code Mappings object, model element category, member access method property, and member access method option. Valid member access method options vary depending on the model element category and selected data visibility option.

    % Set the access of Simulink model data elements by category 
    % setData(Code Mappings object, model element category,... 
    % 'MemberAccessMethod', member access method option)
    setData(cm, 'Inports', 'MemberAccessMethod', 'Method');

    To verify the member access method setting before generating code, use the function getData:

    % Get the visibility of Simulink model data elements by category 
    % getData(code mappings- C++ object, model element category, 'MemberAccessMethod')
    getData(cm, 'Inports', 'MemberAccessMethod');
    

Configure Model Functions as Class Methods

Configure the class method names and arguments. When you generate C++ code from a model, model functions appear as class methods in the generated code. To integrate with external code or interface requirements, you can customize the name of the generated class methods. Additionally, for base-rate periodic functions and Simulink Functions, you can configure the name, order, and identifier of the generated arguments.

The generated class methods are referred to as entry-point methods and are locations in code where a transfer of program control (execution) occurs. Entry-point methods vary depending on the type of Simulink model and can be grouped into the following types:

Model TypeType of Model FunctionDescriptionName of Model FunctionExpected Method Name
Export-Function ModelsExported functionThe exported function for a subsystem.ExportedFunction:slIdentifier, where slIdentifier is the name of the function-call Inport block in the modelfunction-call-inport-block-name or signal-label (if specified)
Simulink FunctionThe exported function for a Simulink Function block.Simulink Function:slIdentifier, where slIdentifier is the name of the Simulink Function block in the modelfunction-name for a global Simulink Function block or model_function-name for a scoped Simulink Function block
Export-Function or Rate-based ModelsInitialize function

Initialization code for a model. At the start of the application code, call the function once. Do not use this function to reset the real-time model data structure (rtM).

Initializemodel_initialize
Partition functionFor a model partition, output and update code. Model configuration parameter Single output/update function is selected (the default).Partition:slIdentifier, where slIdentifier is a partition that was created explicitly from a block in the model and shown in the Simulink® Schedule Editor (for example, P1)model_stepn, where n uniquely identifies the function generated for one of the model sample periods
Periodic multitasking functionFor blocks in a rate-based model configured for multitasking, output and update code. The code generator produces a function for each sample period. Model configuration parameter Single output/update function is selected (the default).Periodic:slIdentifier, where slIdentifier is an annotation that corresponds to the sample time period for a periodic or continuous rate of a multitasking model (for example, D1)model_stepn, where n uniquely identifies the function generated for one of the model sample periods
Periodic single-tasking functionFor blocks in a rate-based model configured for single-tasking, output and update code. Model configuration parameter Single output/update function is selected (the default).Periodicmodel_step
Reset function

If the model includes a Reset Function block, reset code generated. To reset conditions or state, call the function from the application code.

Reset:slIdentifier, where slIdentifier is the name of the reset function in the modelmodel_reset-function-name
Terminate function

Code for turning off a system. For ERT-based models, you can suppress generation of this function by clearing the model configuration parameter Terminate function required (set by default).

Terminatemodel_terminate

The generated C++ class interface, declared in the model header file, incorporates the function name and argument customizations in the generated entry-point methods:

File: rtwdemo_cpp_workflow.h

namespace CustomizedNamespace
{
  class customized_ModelClass {
   public:
    // model initialize function- customized name
   void customized_initialize();

    // model step function- customized name & arguments
   void customized_step(customArg1, const* customArg2);

    // model terminate function- customized name
   void customized_terminate();

    // Constructor
   customized_ModelClass();

    // Destructor
   ~customized_ModelClass();
 
   private:
  … 
  };
}

Workflow

To programmatically configure class method names and arguments, get the Code Mappings object for the model and set the function properties:

  1. Get the Code Mappings object for the model. To get the object, use the function coder.mapping.api.get.

    % Get the Code Mappings object
    cm = coder.mapping.api.get(model);
  2. To view the available entry-point methods for the model, use the function find. When you use the find function, specify the Code Mappings object and the function category you would like to view for the model. Valid function category options are the following:

    • Functions

    • PeriodicFunctions

    • PartitionFunctions

    • ExportedFunctions

    • ResetFunctions

    • SimulinkFunctions

    % View entry-point methods for a model by category 
    % This example shows how to view the entry-point functions for a model
    % find(Code Mappings object, function category')
    find(cm, 'Functions');
  3. Configure method names. To configure the method name of an entry-point method, use the function setFunction. When you use the setFunction function, specify the Code Mappings object, model function name, the method name property, and the custom name. Valid model function names are specified in the following way:

    • Initialize — Initialize function.

    • Terminate — Terminate function.

    • Periodic:slIdentifier — Periodic function (implicit task), where slIdentifier is the annotation (for example, D1) corresponding to the sample time period. Periodic is sufficient for a single-tasking periodic function.

    • Partition:slIdentifier — Partition function (explicit task), where slIdentifier is the partition name in Schedule Editor.

    • Reset:slIdentifier — Reset function where slIdentifier is name of the reset function in model.

    • ExportedFunction:slIdentifier — Exported function where slIdentifier is the name of function-call inport block.

    • ExportedFunction:slIdentifier — Simulink function where slIdentifier is the name of Simulink function in model.

    % Set the name of individual entry-point methods 
    % This examples shows how to customize the name of a periodic function
    % setFunction(Code Mappings object, model function, 'MethodName', custom name)
    setFunction(cm, 'Periodic', 'MethodName', 'custom_Periodic');
    

    To verify the method name before generating code, use the function getFunction:

    % Get method name 
    % getFunction(code mappings object, model function, 'MethodName')
    getData(cm, 'Periodic', 'MethodName');
    
  4. Configure method arguments. For base-rate periodic functions and Simulink Functions, you can use the function setFunction to configure the generated method arguments. When you use the setFunction function, specify the Code Mappings object, model function name, the arguments property, and the method prototype. Valid model function names are specified in the following way:

    • Initialize — Initialize function.

    • Terminate — Terminate function.

    • Periodic:slIdentifier — Periodic function (implicit task), where slIdentifier is the annotation (for example, D1) corresponding to the sample time period. Periodic is sufficient for a single-tasking periodic function.

    • Partition:slIdentifier — Partition function (explicit task), where slIdentifier is the partition name in Schedule Editor.

    • Reset:slIdentifier — Reset function where slIdentifier is name of the reset function in model.

    • ExportedFunction:slIdentifier — Exported function where slIdentifier is the name of function-call inport block.

    • ExportedFunction:slIdentifier — Simulink function where slIdentifier is the name of Simulink function in model.

    Valid identifier options for parameters are the following:

    Identifier OptionPreview
    Value (Inports only)myPeriodic(argInport)
    Const Reference (Inports only)myPeriodic(const & argInport)
    Pointer to ConstmyPeriodic(const * argInport)
    PointermyPeriodic(* argInport)
    Const Pointer to constmyPeriodic(const * const argInport)

    In the below example, the periodic function, foo, is configured to generate a method where y is the return argument and its parameter u1 is passed as a scalar and u2 is passed as a constant pointer:

    % Configure method arguments 
    % setFunction(Code Mappings object, function, 'Arguments', function prototype)
    setFunction(cm, 'Periodic:foo', 'Arguments', 'y=(u1, const *u2)');

    To verify the method arguments before generating code, use the function getFunction:

    % Get method name 
    % getFunction(Code Mappings object, model function, 'Arguments')
    getData(cm, 'Periodic:foo', 'Arguments');
    

Generate C++ Class Interface

Generate the customized C++ class interface by generating code from the model. To verify your customized C++ class interface configurations, build the model and view the generated class, class member, and class method representations.

  1. Generate code. To generate a C++ class interface, build the model with the command slbuild.

    slbuild example_model
  2. View code. To view the generated code, open the model in the Embedded Coder® app.

    open example_model
    To open the Code view, on the C++ Code tab, click View Code. The generated code appears beside the model in the model workspace.

  3. Iterate. If the generated interface does not meet code requirements, make configuration adjustments until requirements are satisfied.

If the generated code representation does not meet your requirements, reconfigure the interface and generate code again until code generations requirements are satisfied. For guidance on understanding the generated code, see Analyze the Generated Code Interface.

Considerations and Limitations

  • Instance-Specific Parameter Support — You can use model parameter arguments to configure workspace variables that have been specified as arguments. You can configure these arguments as private members of your class or as individual arguments defined outside the class. To configure within the class, you can set the data visibility setting to private and configure the generation of the get and set methods. Optionally, you can configure the class member values as defined within the class (setData(cm,'ModelParameterArguments','DataAccess','Direct')) or passed-by-reference through the class constructor (setData(cm,'ModelParameterArguments','DataAccess','Pointer')). The data access setting is supported for top model builds. For reference model builds, the code is generated as references in the model class. To configure instance-specific parameters outside the class, set the data visibility to individual arguments.

    Instance-specific parameter limitations include:

    • MATLAB variables marked as model arguments are not able to be configured as private class members.

    • Model parameter arguments are not supported by right-click builds.

  • Interface Code Generation Behavior — The I/O arguments style of step method specification supports single-rate models and multirate single-tasking models. Multirate multitasking models are not supported. Additionally, the C++ encapsulation interface is not the default, the value is ignored for the Pass fixed-size scalar root inputs by value for code generation parameter.

  • Stateflow® considerations — If you have a Stateflow license, for a Stateflow chart that resides in a root model configured to use the I/O arguments step method function specification, and that uses a model root inport value or calls a subsystem that uses a model root inport value, do one of the following to generate code:

    • In the Stateflow chart, clear the Execute (enter) Chart At Initialization check box.

    • Insert a Simulink Signal Conversion block immediately after the root inport. In the Signal Conversion block parameters dialog box, select Exclude this block from 'Block reduction' optimization.

  • Simscape™ Considerations — If a model root inport value connects to a Simscape block, insert a Simulink Signal Conversion block between the root inport and the Simscape conversion block. In the Signal Conversion block parameters dialog box, select Exclude this block from 'Block reduction' optimization.

  • Reference Model Considerations — When building a referenced model that is configured to generate a C++ class interface:

    • Do not use a C++ class interface in cases when a referenced model cannot have a combined output/update function. Cases include a model that has a continuous sample time or saves states.

    • Do not use virtual buses as inputs or outputs to the referenced model when the referenced model uses the I/O arguments step method. When bus signals cross referenced model boundaries, either use nonvirtual buses or use the Default step method.

See Also

| | | | | | | | | | |

Related Examples

More About