Main Content

Access Signal, State, and Parameter Data During Execution

As you iteratively develop a model, you capture output signal and state data that model execution generates. You also tune parameter values during execution to observe results on the outputs. You can then base your design decisions upon analysis of these outputs. To access this signal, state, and parameter data in a rapid prototyping environment, you can configure the generated code to store the data in addressable memory.

By default, optimization settings make the generated code more efficient by eliminating unnecessary signal storage and inlining the numeric values of block parameters. To generate code that instead allocates addressable memory for this data, you can disable the optimizations or specify code generation settings for individual data items.

Explore Example Model

Run a script that prepares the model ConfigurationRapidPrototypingInterface for this example.

prepare_configurationRapidPrototypingInterface

This data is configured for code generation:

  • Parameters UPPER, LOWER, K1, Table1, and Table2

  • Signals In1, In2, In3, In4, and Out1

  • States X (delay) and mode (data store memory write)

Open the example model, ConfigurationRapidPrototypingInterface.

ConfigurationRapidPrototypingInterface

The model loads numeric MATLAB® variables into the model workspace. The workspace variables set some block parameters in the model. However, the Gain block in the model uses the literal value 2.

Disable Optimizations

1. In the model, clear the model configuration parameter Signal storage reuse. When you clear this optimization and other optimizations such as Eliminate superfluous local variables (expression folding), the generated code allocates memory for signal lines. Clearing Signal storage reuse disables most of the other optimizations.

set_param('ConfigurationRapidPrototypingInterface','OptimizeBlockIOStorage','off')

2. Set the model configuration parameter Default parameter behavior to Tunable. When set to Tunable, this configuration parameter causes the generated code to allocate memory for block parameters and workspace variables.

set_param('ConfigurationRapidPrototypingInterface','DefaultParameterBehavior','Tunable')

3. Generate code.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of build procedure for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets:

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

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

4. In the code generation report, view the file ConfigurationRapidPrototypingInterface.h. This header file defines a structure type that contains signal data. The structure contains fields that each represent a signal line in the model. For example, the output signal of the Gain block, whose name is Gain, appears as the field Gain.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.h');
coder.example.extractLines(file,'/* Block signals (default storage) */',...
    'B_ConfigurationRapidPrototypingInterface_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real_T Delay;                        /* '<Root>/Delay' */
  real_T Table2;                       /* '<Root>/Table2' */
  real_T Table1;                       /* '<Root>/Table1' */
  real_T Gain;                         /* '<Root>/Gain' */
  boolean_T RelOp1;                    /* '<Root>/RelOp1' */
  boolean_T RelOp2;                    /* '<Root>/RelOp2' */
  boolean_T LogOp;                     /* '<Root>/LogOp' */
  boolean_T DataStoreRead;             /* '<Root>/Data Store Read' */
} B_ConfigurationRapidPrototypi_T;

/* Block states (default storage) for system '<Root>' */
typedef struct {
  real_T X;                            /* '<Root>/Delay' */
} DW_ConfigurationRapidPrototyp_T;

/* External inputs (root inport signals with default storage) */
typedef struct {
  real_T In1;                          /* '<Root>/In1' */
  real_T input2;                       /* '<Root>/In2' */
  real_T In3;                          /* '<Root>/In3' */
  real_T In4;                          /* '<Root>/In4' */
} ExtU_ConfigurationRapidProtot_T;

/* Parameters (default storage) */
struct P_ConfigurationRapidPrototypi_T_ {
  Table1_Type Table1;                  /* Variable: Table1
                                        * Referenced by: '<Root>/Table1'
                                        */
  Table2_Type Table2;                  /* Variable: Table2
                                        * Referenced by: '<Root>/Table2'
                                        */
  real_T LOWER;                        /* Variable: LOWER
                                        * Referenced by: '<Root>/Constant2'
                                        */
  real_T UPPER;                        /* Variable: UPPER
                                        * Referenced by: '<Root>/Constant1'
                                        */
  real_T Gain_Gain;                    /* Expression: 2
                                        * Referenced by: '<Root>/Gain'
                                        */
  real_T Delay_InitialCondition;       /* Expression: 0
                                        * Referenced by: '<Root>/Delay'
                                        */
  uint32_T Table2_maxIndex[2];         /* Computed Parameter: Table2_maxIndex
                                        * Referenced by: '<Root>/Table2'
                                        */
  boolean_T DataStoreMemory_InitialValue;
                             /* Computed Parameter: DataStoreMemory_InitialValue
                              * Referenced by: '<Root>/Data Store Memory'
                              */
};

/* Real-time Model Data Structure */
struct tag_RTM_ConfigurationRapidPro_T {
  const char_T *errorStatus;
};

/* Block parameters (default storage) */
extern P_ConfigurationRapidPrototypi_T ConfigurationRapidPrototyping_P;

/* Block signals (default storage) */
extern B_ConfigurationRapidPrototypi_T ConfigurationRapidPrototyping_B;

/* Block states (default storage) */
extern DW_ConfigurationRapidPrototyp_T ConfigurationRapidPrototypin_DW;

/* External inputs (root inport signals with default storage) */
extern ExtU_ConfigurationRapidProtot_T ConfigurationRapidPrototyping_U;

/*
 * Exported States
 *
 * Note: Exported states are block states with an exported global
 * storage class designation.  Code generation will declare the memory for these
 * states and exports their symbols.
 *
 */
extern boolean_T mode;                 /* '<Root>/Data Store Memory' */

/* Model entry point functions */
extern void ConfigurationRapidPrototypingInterface_initialize(void);
extern void ConfigurationRapidPrototypingInterface_step(void);
extern void ConfigurationRapidPrototypingInterface_terminate(void);

/* Exported data declaration */

/* Data with Exported storage */
extern real_T output;                  /* '<Root>/Out1' */

/* Real-time Model object */
extern RT_MODEL_ConfigurationRapidPr_T *const ConfigurationRapidPrototypin_M;

/*-
 * The generated code includes comments that allow you to trace directly
 * back to the appropriate location in the model.  The basic format
 * is <system>/block_name, where system is the system number (uniquely
 * assigned by Simulink) and block_name is the name of the block.
 *
 * Use the MATLAB hilite_system command to trace the generated code back
 * to the model.  For example,
 *
 * hilite_system('<S3>')    - opens system 3
 * hilite_system('<S3>/Kp') - opens and selects block Kp which resides in S3
 *
 * Here is the system hierarchy for this model
 *
 * '<Root>' : 'ConfigurationRapidPrototypingInterface'
 */
#endif                           /* ConfigurationRapidPrototypingInterface_h_ */

The file defines a structure type that contains block parameter data. For example, the Gain parameter of the Gain block appears as the field Gain_Gain. The other fields of the structure represent other block parameters and workspace variables from the model, including initial conditions for signals and states.

coder.example.extractLines(file,'/* Parameters (default storage) */',...
    '/* Real-time Model Data Structure */',1,0)
/* Parameters (default storage) */
struct P_ConfigurationRapidPrototypi_T_ {
  Table1_Type Table1;                  /* Variable: Table1
                                        * Referenced by: '<Root>/Table1'
                                        */
  Table2_Type Table2;                  /* Variable: Table2
                                        * Referenced by: '<Root>/Table2'
                                        */
  real_T LOWER;                        /* Variable: LOWER
                                        * Referenced by: '<Root>/Constant2'
                                        */
  real_T UPPER;                        /* Variable: UPPER
                                        * Referenced by: '<Root>/Constant1'
                                        */
  real_T Gain_Gain;                    /* Expression: 2
                                        * Referenced by: '<Root>/Gain'
                                        */
  real_T Delay_InitialCondition;       /* Expression: 0
                                        * Referenced by: '<Root>/Delay'
                                        */
  uint32_T Table2_maxIndex[2];         /* Computed Parameter: Table2_maxIndex
                                        * Referenced by: '<Root>/Table2'
                                        */
  boolean_T DataStoreMemory_InitialValue;
                             /* Computed Parameter: DataStoreMemory_InitialValue
                              * Referenced by: '<Root>/Data Store Memory'
                              */
};

5. View the file ConfigurationRapidPrototypingInterface_data.c. This source file allocates global memory for a parameter structure and initializes the field values based on the parameter values in the model.

6. View the source file ConfigurationRapidPrototypingInterface.c. The code allocates global memory for a structure variable that contains signal data.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.c');
coder.example.extractLines(file,'/* Block signals (default storage) */',...
    'B_ConfigurationRapidPrototypingInterface_T ConfigurationRapidPrototypingInterface_B;',1,1)
/* Block signals (default storage) */
B_ConfigurationRapidPrototypi_T ConfigurationRapidPrototyping_B;

/* Block states (default storage) */
DW_ConfigurationRapidPrototyp_T ConfigurationRapidPrototypin_DW;

/* External inputs (root inport signals with default storage) */
ExtU_ConfigurationRapidProtot_T ConfigurationRapidPrototyping_U;

/* Real-time model */
static RT_MODEL_ConfigurationRapidPr_T ConfigurationRapidPrototypin_M_;
RT_MODEL_ConfigurationRapidPr_T *const ConfigurationRapidPrototypin_M =
  &ConfigurationRapidPrototypin_M_;

/* Model step function */
void ConfigurationRapidPrototypingInterface_step(void)
{
  /* RelationalOperator: '<Root>/RelOp1' incorporates:
   *  Constant: '<Root>/Constant1'
   *  Inport: '<Root>/In1'
   */
  ConfigurationRapidPrototyping_B.RelOp1 = (ConfigurationRapidPrototyping_U.In1 >
    ConfigurationRapidPrototyping_P.UPPER);

  /* RelationalOperator: '<Root>/RelOp2' incorporates:
   *  Constant: '<Root>/Constant2'
   *  Inport: '<Root>/In1'
   */
  ConfigurationRapidPrototyping_B.RelOp2 = (ConfigurationRapidPrototyping_U.In1 <
    ConfigurationRapidPrototyping_P.LOWER);

  /* Logic: '<Root>/LogOp' */
  ConfigurationRapidPrototyping_B.LogOp =
    (ConfigurationRapidPrototyping_B.RelOp1 ||
     ConfigurationRapidPrototyping_B.RelOp2);

  /* DataStoreWrite: '<Root>/Data Store Write' */
  mode = ConfigurationRapidPrototyping_B.LogOp;

  /* DataStoreRead: '<Root>/Data Store Read' */
  ConfigurationRapidPrototyping_B.DataStoreRead = mode;

  /* UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototyping_B.Delay = ConfigurationRapidPrototypin_DW.X;

  /* Switch: '<Root>/Switch' */
  if (ConfigurationRapidPrototyping_B.DataStoreRead) {
    /* Lookup_n-D: '<Root>/Table1' incorporates:
     *  Inport: '<Root>/In2'
     */
    ConfigurationRapidPrototyping_B.Table1 = look1_binlc
      (ConfigurationRapidPrototyping_U.input2,
       ConfigurationRapidPrototyping_P.Table1.BP,
       ConfigurationRapidPrototyping_P.Table1.Table, 10U);

    /* Gain: '<Root>/Gain' */
    ConfigurationRapidPrototyping_B.Gain =
      ConfigurationRapidPrototyping_P.Gain_Gain *
      ConfigurationRapidPrototyping_B.Table1;

    /* Outport: '<Root>/Out1' */
    output = ConfigurationRapidPrototyping_B.Gain;
  } else {
    /* Outport: '<Root>/Out1' */
    output = ConfigurationRapidPrototyping_B.Delay;
  }

  /* End of Switch: '<Root>/Switch' */

  /* Lookup_n-D: '<Root>/Table2' incorporates:
   *  Inport: '<Root>/In3'
   *  Inport: '<Root>/In4'
   */
  ConfigurationRapidPrototyping_B.Table2 = look2_binlc
    (ConfigurationRapidPrototyping_U.In3, ConfigurationRapidPrototyping_U.In4,
     ConfigurationRapidPrototyping_P.Table2.BP1,
     ConfigurationRapidPrototyping_P.Table2.BP2,
     ConfigurationRapidPrototyping_P.Table2.Table,
     ConfigurationRapidPrototyping_P.Table2_maxIndex, 3U);

  /* Update for UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototypin_DW.X = ConfigurationRapidPrototyping_B.Table2;
}

/* Model initialize function */
void ConfigurationRapidPrototypingInterface_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(ConfigurationRapidPrototypin_M, (NULL));

  /* block I/O */
  (void) memset(((void *) &ConfigurationRapidPrototyping_B), 0,
                sizeof(B_ConfigurationRapidPrototypi_T));

  /* Storage classes */
  output = 0.0;

  /* states (dwork) */
  (void) memset((void *)&ConfigurationRapidPrototypin_DW, 0,
                sizeof(DW_ConfigurationRapidPrototyp_T));

  /* exported global states */
  mode = false;

  /* external inputs */
  (void)memset(&ConfigurationRapidPrototyping_U, 0, sizeof
               (ExtU_ConfigurationRapidProtot_T));

  /* Start for DataStoreMemory: '<Root>/Data Store Memory' */
  mode = ConfigurationRapidPrototyping_P.DataStoreMemory_InitialValue;

  /* InitializeConditions for UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototypin_DW.X =
    ConfigurationRapidPrototyping_P.Delay_InitialCondition;
}

/* Model terminate function */
void ConfigurationRapidPrototypingInterface_terminate(void)
{
  /* (no terminate code required) */
}

The code algorithm in the model step function calculates the signal values. It then assigns these values to the fields of the signal structure. To perform the calculations, the algorithm uses the parameter values from the fields of the parameter structure.

Exclude Data Items from Optimizations

When you want to select code generation optimizations such as Signal storage reuse, you can preserve individual data items from the optimizations. The generated code then allocates addressable memory for the items.

Select the optimizations that you previously cleared.

set_param('ConfigurationRapidPrototypingInterface','OptimizeBlockIOStorage','on')
set_param('ConfigurationRapidPrototypingInterface','LocalBlockOutputs','on')
set_param('ConfigurationRapidPrototypingInterface','DefaultParameterBehavior','Inlined')

1. In the C Code tab, select Code Interface > Individual Element Code Mappings.

2. In the Code Mappings editor, inspect the Signals/States tab.

3. In the model, select the output signal of the Gain block.

4. Pause on the ellipsis that appears above or below the signal line to open the action bar. Click the Add Signal button. In the Code Mappings editor, the Signals node expands and lists the signal that you added.

cm = coder.mapping.api.get('ConfigurationRapidPrototypingInterface');
gain_ports = get_param('ConfigurationRapidPrototypingInterface/Gain','PortHandles');
gain_outPort = gain_ports.Outport;
addSignal(cm,gain_outPort);

5. Apply the default storage class for Outports to the signal by setting Storage Class to Model default.

setSignal(cm,gain_outPort,'StorageClass','Model default','Identifier','Gain');

6. In the model, select the Gain block.

7. In the Property Inspector, set the gain value to the model workspace parameter object K1.

8. In the Code Mappings editor, on the Parameters tab, expand Model Parameters.

9. Select parameter K1. Apply a storage class other than Auto by setting Storage class. For example, use the storage class Model default. By using Model default, K1 acquires the default storage class specified for model parameters, Default, and appears as a field of the global parameters structure.

set_param('ConfigurationRapidPrototypingInterface/Gain','Gain','K1');
setModelParameter(cm,'K1','StorageClass','Model default');

10. Generate code.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of build procedure for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets:

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

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

11. In the code generation report, view the file ConfigurationRapidPrototypingInterface.h. The structure that contains signal data now defines only one field, Gain, which represents the test-pointed output of the Gain block.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.h');
coder.example.extractLines(file,'/* Block signals (default storage) */',...
    'B_ConfigurationRapidPrototypingInterface_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real_T Gain;                         /* '<Root>/Gain' */
} B_ConfigurationRapidPrototypi_T;

/* Block states (default storage) for system '<Root>' */
typedef struct {
  real_T X;                            /* '<Root>/Delay' */
} DW_ConfigurationRapidPrototyp_T;

/* External inputs (root inport signals with default storage) */
typedef struct {
  real_T In1;                          /* '<Root>/In1' */
  real_T input2;                       /* '<Root>/In2' */
  real_T In3;                          /* '<Root>/In3' */
  real_T In4;                          /* '<Root>/In4' */
} ExtU_ConfigurationRapidProtot_T;

/* Parameters (default storage) */
struct P_ConfigurationRapidPrototypi_T_ {
  int8_T K1;                           /* Variable: K1
                                        * Referenced by: '<Root>/Gain'
                                        */
};

/* Real-time Model Data Structure */
struct tag_RTM_ConfigurationRapidPro_T {
  const char_T *errorStatus;
};

/* Block parameters (default storage) */
extern P_ConfigurationRapidPrototypi_T ConfigurationRapidPrototyping_P;

/* Block signals (default storage) */
extern B_ConfigurationRapidPrototypi_T ConfigurationRapidPrototyping_B;

/* Block states (default storage) */
extern DW_ConfigurationRapidPrototyp_T ConfigurationRapidPrototypin_DW;

/* External inputs (root inport signals with default storage) */
extern ExtU_ConfigurationRapidProtot_T ConfigurationRapidPrototyping_U;

/*
 * Exported States
 *
 * Note: Exported states are block states with an exported global
 * storage class designation.  Code generation will declare the memory for these
 * states and exports their symbols.
 *
 */
extern boolean_T mode;                 /* '<Root>/Data Store Memory' */

/* Model entry point functions */
extern void ConfigurationRapidPrototypingInterface_initialize(void);
extern void ConfigurationRapidPrototypingInterface_step(void);
extern void ConfigurationRapidPrototypingInterface_terminate(void);

/* Exported data declaration */

/* Data with Exported storage */
extern real_T output;                  /* '<Root>/Out1' */

/* Real-time Model object */
extern RT_MODEL_ConfigurationRapidPr_T *const ConfigurationRapidPrototypin_M;

/*-
 * The generated code includes comments that allow you to trace directly
 * back to the appropriate location in the model.  The basic format
 * is <system>/block_name, where system is the system number (uniquely
 * assigned by Simulink) and block_name is the name of the block.
 *
 * Use the MATLAB hilite_system command to trace the generated code back
 * to the model.  For example,
 *
 * hilite_system('<S3>')    - opens system 3
 * hilite_system('<S3>/Kp') - opens and selects block Kp which resides in S3
 *
 * Here is the system hierarchy for this model
 *
 * '<Root>' : 'ConfigurationRapidPrototypingInterface'
 */
#endif                           /* ConfigurationRapidPrototypingInterface_h_ */

The structure that contains block parameter data defines one field, K1, which represents the parameter object K1.

coder.example.extractLines(file,'/* Parameters (default storage) */',...
    '/* Real-time Model Data Structure */',1,0)
/* Parameters (default storage) */
struct P_ConfigurationRapidPrototypi_T_ {
  int8_T K1;                           /* Variable: K1
                                        * Referenced by: '<Root>/Gain'
                                        */
};

Access Data Through Generated Interfaces

You can configure the generated code to contain extra code and files so that you can access model data through standardized interfaces. For example, use the C API to log signal data and tune parameters during execution.

Copy this custom source code into a file named ex_myHandCode.c in your current folder.

#include "ex_myHandHdr.h"
 
#define paramIdx 0 /* Index of the target parameter, 
determined by inspecting the array of structures generated by the C API. */
#define sigIdx 0 /* Index of the target signal, 
determined by inspecting the array of structures generated by the C API. */
 
void tuneFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr)
{
    /* Take action with the parameter value only at 
       the beginning of simulation and at the 5-second mark. */
    if (*tPtr == 0 || *tPtr == 5) {
        
        /* Local variables to store information extracted from 
           the model mapping information (mmi). */
        void** dataAddrMap;
        const rtwCAPI_DataTypeMap *dataTypeMap;
        const rtwCAPI_ModelParameters *params;
        int_T addrIdx;
        uint16_T dTypeIdx;
        uint8_T slDataType;
        
        /* Use built-in C API macros to extract information. */
        dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
        dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
        params = rtwCAPI_GetModelParameters(mmi);
        addrIdx = rtwCAPI_GetModelParameterAddrIdx(params,paramIdx);
        dTypeIdx =  rtwCAPI_GetModelParameterDataTypeIdx(params,paramIdx);
        slDataType = rtwCAPI_GetDataTypeSLId(dataTypeMap, dTypeIdx);
        
        /* Handle data types 'double' and 'int8'. */
        switch (slDataType) {
            
            case SS_DOUBLE: {
                real_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                /* At the 5-second mark, increment the parameter value by 1. */
                if (*tPtr == 5) {
                    (*dataAddress)++;
                }
                printf("Parameter value is %f\n", *dataAddress);
                break;
            }
            
            case SS_INT8: {
                int8_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                if (*tPtr == 5) {
                    (*dataAddress)++;
                }
                printf("Parameter value is %i\n", *dataAddress);
                break;
            }
        }
    }
}
 
void logFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr)
{
    /* Take action with the signal value only when 
       the simulation time is an integer value. */
    if (*tPtr-(int_T)*tPtr == 0) {
        
        /* Local variables to store information extracted from 
           the model mapping information (mmi). */
        void** dataAddrMap;
        const rtwCAPI_DataTypeMap *dataTypeMap;
        const rtwCAPI_Signals *sigs;
        int_T addrIdx;
        uint16_T dTypeIdx;
        uint8_T slDataType;
        
        /* Use built-in C API macros to extract information. */
        dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
        dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
        sigs = rtwCAPI_GetSignals(mmi);
        addrIdx = rtwCAPI_GetSignalAddrIdx(sigs,sigIdx);
        dTypeIdx =  rtwCAPI_GetSignalDataTypeIdx(sigs,sigIdx);
        slDataType = rtwCAPI_GetDataTypeSLId(dataTypeMap, dTypeIdx);
        
        /* Handle data types 'double' and 'single'. */
        switch (slDataType) {
            
            case SS_DOUBLE: {
                real_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                printf("Signal value is %f\n", *dataAddress);
                break;
            }
            
            case SS_SINGLE: {
                real32_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                printf("Signal value is %f\n", *dataAddress);
                break;
            }
        }
    }
}

2. Copy this custom header code into a file named ex_myHandHdr.h in your current folder.

#include <stdio.h>
#include <string.h>
#include <math.h>
/* Include rtw_modelmap.h for definitions of C API macros. */
#include "rtw_modelmap.h"
#include "builtin_typeid_types.h"
#include "rtwtypes.h"
void tuneFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr);
void logFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr);

These files use the C API to access signal and parameter data in the code that you generate from the example model.

3. Set model configuration parameters Include headers and Source files to #include "ex_myHandHdr.h" and ex_myHandCode.c, respectively.

set_param('ConfigurationRapidPrototypingInterface','CustomHeaderCode','#include "ex_myHandHdr.h"')
set_param('ConfigurationRapidPrototypingInterface','CustomSource','ex_myHandCode.c')

4. Select model configuration parameter MAT-file Logging. The generated executable runs only until the simulation stop time (which you set in the model configuration parameters).

set_param('ConfigurationRapidPrototypingInterface','MatFileLogging','on')

5. Select C API model configuration parameters parameters, signals, states, and root-level I/O.

set_param('ConfigurationRapidPrototypingInterface','RTWCAPIParams','on')
set_param('ConfigurationRapidPrototypingInterface','RTWCAPISignals','on')
set_param('ConfigurationRapidPrototypingInterface','RTWCAPIStates','on')
set_param('ConfigurationRapidPrototypingInterface','RTWCAPIRootIO','on')

6. Load the Custom Code block library.

custcode

7. Add a System Outputs block to the model.

add_block('custcode/System Outputs','ConfigurationRapidPrototypingInterface/System Outputs')

8. In the System Outputs block dialog box, set System Outputs Function Execution Code to this code:

{
ConfigurationRapidPrototypingInterface_U.input2++;
rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(ConfigurationRapidPrototypingInterface_M).mmi);
tuneFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));
}

9. In the block dialog box, set System Outputs Function Exit Code to this code:

{
rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(ConfigurationRapidPrototypingInterface_M).mmi);
logFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));
}

Alternatively, to configure the System Outputs block, at the command prompt, use these commands:

temp.TLCFile = 'custcode';
temp.Location = 'System Outputs Function';
temp.Middle = sprintf(['{\nConfigurationRapidPrototyping_U.input2++;'...
    '\nrtwCAPI_ModelMappingInfo *MMI = '...
    '&(rtmGetDataMapInfo(ConfigurationRapidPrototypingInterface_M).mmi);'...
    '\ntuneFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));\n}']);
temp.Bottom = sprintf(['{\nrtwCAPI_ModelMappingInfo *MMI = '...
    '&(rtmGetDataMapInfo(ConfigurationRapidPrototypingInterface_M).mmi);'...
    '\nlogFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));\n}']);
set_param('ConfigurationRapidPrototypingInterface/System Outputs','RTWdata',temp)

10. Generate code.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of build procedure for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets:

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

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

11. In the code generation report, view the interface file ConfigurationRapidPrototypingInterface_capi.c. This file initializes the arrays of structures that you can use to interact with data items through the C API. For example, in the array of structures rtBlockSignals, the first structure (index 0) describes the test-pointed output signal of the Gain block in the model.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface_capi.c');
coder.example.extractLines(file,'/* Block output signal information */',...
    '/* Individual block tuning',1,0)
/* Block output signal information */
static const rtwCAPI_Signals rtBlockSignals[] = {
  /* addrMapIndex, sysNum, blockPath,
   * signalName, portNumber, dataTypeIndex, dimIndex, fxpIndex, sTimeIndex
   */
  { 0, 0, TARGET_STRING("ConfigurationRapidPrototypingInterface/Gain"),
    TARGET_STRING(""), 0, 0, 0, 0, 0 },

  {
    0, 0, (NULL), (NULL), 0, 0, 0, 0, 0
  }
};

The fields of the structure, such as addrMapIndex, indicate indices into other arrays of structures, such as rtDataAddrMap, that describe the characteristics of the signal. These characteristics include the address of the signal data (a pointer to the data), the numeric data type, and the dimensions of the signal.

12. In the file ConfigurationRapidPrototypingInterface.c, view the code algorithm in the model step function. The algorithm first executes the code that you specified in the System Outputs block.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.c');
coder.example.extractLines(file,'/* user code (Output function Body) */',...
    '/* Logic: ''<Root>/LogOp'' incorporates:',1,0)
  /* user code (Output function Body) */

  /* System '<Root>' */
  {
    ConfigurationRapidPrototyping_U.input2++;
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (ConfigurationRapidPrototypingInterface_M).mmi);
    tuneFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));
  }

  /* DataStoreWrite: '<Root>/Data Store Write' incorporates:
   *  Constant: '<Root>/Constant1'
   *  Constant: '<Root>/Constant2'
   *  Inport: '<Root>/In1'
   *  Logic: '<Root>/LogOp'
   *  RelationalOperator: '<Root>/RelOp1'
   *  RelationalOperator: '<Root>/RelOp2'
   */
  mode = ((ConfigurationRapidPrototyping_U.In1 > 10.0) ||
          (ConfigurationRapidPrototyping_U.In1 < -10.0));

  /* Gain: '<Root>/Gain' incorporates:
   *  Inport: '<Root>/In2'
   *  Lookup_n-D: '<Root>/Table1'
   */
  ConfigurationRapidPrototyping_B.Gain = (real_T)
    ConfigurationRapidPrototyping_P.K1 * look1_binlc
    (ConfigurationRapidPrototyping_U.input2, rtCP_Table1_bp01Data,
     rtCP_Table1_tableData, 10U);

  /* Switch: '<Root>/Switch' incorporates:
   *  DataStoreRead: '<Root>/Data Store Read'
   */
  if (mode) {
    /* Outport: '<Root>/Out1' */
    output = ConfigurationRapidPrototyping_B.Gain;
  } else {
    /* Outport: '<Root>/Out1' incorporates:
     *  UnitDelay: '<Root>/Delay'
     */
    output = ConfigurationRapidPrototypin_DW.X;
  }

  /* End of Switch: '<Root>/Switch' */

  /* Lookup_n-D: '<Root>/Table2' incorporates:
   *  Inport: '<Root>/In3'
   *  Inport: '<Root>/In4'
   */
  rtb_Table2 = look2_binlc(ConfigurationRapidPrototyping_U.In3,
    ConfigurationRapidPrototyping_U.In4, rtCP_Table2_bp01Data,
    rtCP_Table2_bp02Data, rtCP_Table2_tableData, rtCP_Table2_maxIndex, 3U);

  /* user code (Output function Trailer) */

  /* System '<Root>' */
  {
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (ConfigurationRapidPrototypingInterface_M).mmi);
    logFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));
  }

  /* Update for UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototypin_DW.X = rtb_Table2;

  /* Matfile logging */
  rt_UpdateTXYLogVars(ConfigurationRapidPrototypin_M->rtwLogInfo,
                      (&ConfigurationRapidPrototypin_M->Timing.taskTime0));

  /* signal main to stop simulation */
  {                                    /* Sample time: [1.0s, 0.0s] */
    if ((rtmGetTFinal(ConfigurationRapidPrototypin_M)!=-1) &&
        !((rtmGetTFinal(ConfigurationRapidPrototypin_M)-
           ConfigurationRapidPrototypin_M->Timing.taskTime0) >
          ConfigurationRapidPrototypin_M->Timing.taskTime0 * (DBL_EPSILON))) {
      rtmSetErrorStatus(ConfigurationRapidPrototypin_M, "Simulation finished");
    }
  }

  /* Update absolute time for base rate */
  /* The "clockTick0" counts the number of times the code of this task has
   * been executed. The absolute time is the multiplication of "clockTick0"
   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
   * overflow during the application lifespan selected.
   * Timer of this task consists of two 32 bit unsigned integers.
   * The two integers represent the low bits Timing.clockTick0 and the high bits
   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
   */
  if (!(++ConfigurationRapidPrototypin_M->Timing.clockTick0)) {
    ++ConfigurationRapidPrototypin_M->Timing.clockTickH0;
  }

  ConfigurationRapidPrototypin_M->Timing.taskTime0 =
    ConfigurationRapidPrototypin_M->Timing.clockTick0 *
    ConfigurationRapidPrototypin_M->Timing.stepSize0 +
    ConfigurationRapidPrototypin_M->Timing.clockTickH0 *
    ConfigurationRapidPrototypin_M->Timing.stepSize0 * 4294967296.0;
}

/* Model initialize function */
void ConfigurationRapidPrototypingInterface_initialize(void)
{
  /* Registration code */

  /* initialize non-finites */
  rt_InitInfAndNaN(sizeof(real_T));

  /* initialize real-time model */
  (void) memset((void *)ConfigurationRapidPrototypin_M, 0,
                sizeof(RT_MODEL_ConfigurationRapidPr_T));
  rtmSetTFinal(ConfigurationRapidPrototypin_M, 10.0);
  ConfigurationRapidPrototypin_M->Timing.stepSize0 = 1.0;

  /* Setup for data logging */
  {
    static RTWLogInfo rt_DataLoggingInfo;
    rt_DataLoggingInfo.loggingInterval = (NULL);
    ConfigurationRapidPrototypin_M->rtwLogInfo = &rt_DataLoggingInfo;
  }

  /* Setup for data logging */
  {
    rtliSetLogXSignalInfo(ConfigurationRapidPrototypin_M->rtwLogInfo, (NULL));
    rtliSetLogXSignalPtrs(ConfigurationRapidPrototypin_M->rtwLogInfo, (NULL));
    rtliSetLogT(ConfigurationRapidPrototypin_M->rtwLogInfo, "");
    rtliSetLogX(ConfigurationRapidPrototypin_M->rtwLogInfo, "");
    rtliSetLogXFinal(ConfigurationRapidPrototypin_M->rtwLogInfo, "");
    rtliSetLogVarNameModifier(ConfigurationRapidPrototypin_M->rtwLogInfo, "rt_");
    rtliSetLogFormat(ConfigurationRapidPrototypin_M->rtwLogInfo, 0);
    rtliSetLogMaxRows(ConfigurationRapidPrototypin_M->rtwLogInfo, 1000);
    rtliSetLogDecimation(ConfigurationRapidPrototypin_M->rtwLogInfo, 1);
    rtliSetLogY(ConfigurationRapidPrototypin_M->rtwLogInfo, "");
    rtliSetLogYSignalInfo(ConfigurationRapidPrototypin_M->rtwLogInfo, (NULL));
    rtliSetLogYSignalPtrs(ConfigurationRapidPrototypin_M->rtwLogInfo, (NULL));
  }

  /* block I/O */
  (void) memset(((void *) &ConfigurationRapidPrototyping_B), 0,
                sizeof(B_ConfigurationRapidPrototypi_T));

  /* Storage classes */
  output = 0.0;

  /* states (dwork) */
  (void) memset((void *)&ConfigurationRapidPrototypin_DW, 0,
                sizeof(DW_ConfigurationRapidPrototyp_T));

  /* exported global states */
  mode = false;

  /* external inputs */
  (void)memset(&ConfigurationRapidPrototyping_U, 0, sizeof
               (ExtU_ConfigurationRapidProtot_T));

  /* Initialize DataMapInfo substructure containing ModelMap for C API */
  ConfigurationRapidPrototypingInterface_InitializeDataMapInfo();

  /* Matfile logging */
  rt_StartDataLoggingWithStartTime(ConfigurationRapidPrototypin_M->rtwLogInfo,
    0.0, rtmGetTFinal(ConfigurationRapidPrototypin_M),
    ConfigurationRapidPrototypin_M->Timing.stepSize0, (&rtmGetErrorStatus
    (ConfigurationRapidPrototypin_M)));

  /* Start for DataStoreMemory: '<Root>/Data Store Memory' */
  mode = false;

  /* InitializeConditions for UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototypin_DW.X = 0.0;
}

/* Model terminate function */
void ConfigurationRapidPrototypingInterface_terminate(void)
{
  /* (no terminate code required) */
}

This code first perturbs the input signal input2 by incrementing the value of the signal each time the step function executes. The code then uses the built-in macro rtmGetDataMapInfo to extract model mapping information from the model data structure ConfigurationRapidPrototypingInterface_M. The pointer MMI points to the extracted mapping information, which allows the functions tuneFcn and logFcn to access the information contained in the arrays of structures that the C API file ConfigurationRapidPrototypingInterface_capi.c defines.

13. View the function tuneFcn in the file ex_myHandCode.c. This function uses the C API (through the model mapping information mmi) and a pointer to the simulation time to print the value of the parameter K1 at specific times during code execution. When the simulation time reaches 5 seconds, the function changes the parameter value in memory. By using a switch case block, the function can access the parameter data whether the data type is int8 or double.

14. View the code algorithm in the model step function again. Near the end of the function, the algorithm executes the code that you specified in the System Outputs block. This code calls the function logFcn.

coder.example.extractLines(file,'/* user code (Output function Trailer) */',...
    '/* Matfile logging */',1,0)
  /* user code (Output function Trailer) */

  /* System '<Root>' */
  {
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (ConfigurationRapidPrototypingInterface_M).mmi);
    logFcn(MMI, rtmGetTPtr(ConfigurationRapidPrototypingInterface_M));
  }

  /* Update for UnitDelay: '<Root>/Delay' */
  ConfigurationRapidPrototypin_DW.X = rtb_Table2;

15. View the function logFcn in the file ex_myHandCode.c. The function uses the C API to print the value of the test-pointed signal. The function can access the signal data whether the data type is single or double.

16. At the command prompt, run the generated executable ConfigurationRapidPrototypingInterface.exe.

system('ConfigurationRapidPrototypingInterface')

The parameter and signal values appear in the Command Window output.

For more information about data interfaces, including the C API, see Generated Code Interfacing.

See Also

| | |

Related Topics