Main Content

Exchange Structured and Enumerated Data Between Generated and External Code

This example shows how to generate code that exchanges data with external, existing code. Construct and configure a model to match data types with the external code and to avoid duplicating type definitions and memory allocation (definition of global variables). Then, compile the generated code together with the external code into a single application.

Inspect External Code

Create the file ex_cc_algorithm.c in your current folder.

#include "ex_cc_algorithm.h"

inSigs_T inSigs;

float_32 my_alg(void)
{
    if (inSigs.err == TMP_HI) {
        return 27.5;
    }
    else if (inSigs.err == TMP_LO) {
        return inSigs.sig1 * calPrms.cal3;
    }
    else {
        return inSigs.sig2 * calPrms.cal3;
    }
}
        

The C code defines a global structure variable named inSigs. The code also defines a function, my_alg, that uses inSigs and another structure variable named calPrms.

Create the file ex_cc_algorithm.h in your current folder.

#ifndef ex_cc_algorithm_h
#define ex_cc_algorithm_h

typedef float float_32;

typedef enum {
    TMP_HI = 0,
    TMP_LO,
    NORM,
} err_T;

typedef struct inSigs_tag {
    err_T err;
    float_32 sig1;
    float_32 sig2;
} inSigs_T;

typedef struct calPrms_tag {
    float_32 cal1;
    float_32 cal2;
    float_32 cal3;
} calPrms_T;

extern calPrms_T calPrms;
extern inSigs_T inSigs;

float_32 my_alg(void);

#endif

The file defines float_32 as an alias of the C data type float. The file also defines an enumerated data type, err_T, and two structure types, inSigs_T and calPrms_T.

The function my_alg is designed to calculate a return value by using the fields of inSigs and calPrms, which are global structure variables of the types inSigs_T and calPrms_T. The function requires another algorithm to supply the signal data that inSigs stores.

This code allocates memory for inSigs, but not for calPrms. Create a model whose generated code:

  • Defines and initializes calPrms.

  • Calculates values for the fields of inSigs.

  • Reuses the type definitions (such as err_T and float_32) that the external code defines.

Create Simulink Model

  1. So that you can create enumerated and structured data in the Simulink® model, first create Simulink representations of the data types that the external code defines. Store the Simulink types in a new data dictionary named ex_cc_integ.sldd.

    Simulink.importExternalCTypes('ex_cc_algorithm.h',...
        'DataDictionary','ex_cc_integ.sldd');
    

    The data dictionary appears in your current folder.

  2. To inspect the dictionary contents in the Model Explorer, in your current folder, double-click the file, ex_cc_integ.sldd.

    The Simulink.importExternalCTypes function creates Simulink.Bus, Simulink.AliasType, and Simulink.data.dictionary.EnumTypeDefinition objects that correspond to the custom C data types from ex_cc_algorithm.h.

  3. Create a new model and save it in your current folder as ex_struct_enum_integ.

  4. Link the model to the data dictionary. On the Modeling tab, under Design, click Data Dictionary.

  5. Add algorithmic blocks that calculate the fields of inSigs.

Now that you have the algorithm model, you must:

  • Organize the output signals into a structure variable named inSigs.

  • Create the structure variable calPrms.

  • Include ex_cc_algorithm.c in the build process that compiles the code after code generation.

Configure Generated Code to Write Output Data to Existing Structure Variable

  1. Add a Bus Creator block near the existing Outport blocks. The output of a Bus Creator block is a bus signal, which you can configure to appear in the generated code as a structure.

  2. In the Bus Creator block, set these parameters:

    • Number of inputs to 3

    • Output data type to Bus: inSigs_T

    • Output as nonvirtual bus to selected

  3. Delete the three existing Outport blocks (but not the signals that enter the blocks).

  4. Connect the three remaining signal lines to the inputs of the Bus Creator block.

  5. Add an Outport block after the Bus Creator block. Connect the output of the Bus Creator to the Outport.

  6. In the Outport block, set the Data type parameter to Bus: inSigs_T.

  7. On the Modeling tab, click Model Data Editor.

  8. On the Inports/Outports tab, for the Inport blocks labeled In2 and In3, change Data Type from Inherit: auto to float_32.

  9. Change the Change View drop-down list from Design to Code.

  10. For the Outport block, set Signal Name to inSigs.

  11. Set Storage Class to ImportFromFile.

  12. Set Header File to ex_cc_algorithm.h.

  13. Inspect the Signals tab.

  14. In the model, select the output signal of the Multiport Switch block.

  15. In the Model Data Editor, for the selected signal, set Name to err.

  16. Set the name of the output signal of the Gain block to sig1.

  17. Set the name of the output signal of the Gain1 block to sig2.

When you finish, the model stores output signal data (such as the signals err and sig1) in the fields of a structure variable named inSigs.

Because you set Storage Class to ImportFromFile, the generated code does not allocate memory for inSigs.

Configure Generated Code to Define Parameter Data

Configure the generated code to define the global structure variable, calPrms, that the external code needs.

  1. In the Model Explorer Model Hierarchy pane, under the dictionary node ex_cc_integ, select the Design Data node.

  2. In the Contents pane, select the Simulink.Bus object calPrms_T.

  3. In the Dialog pane (the right pane), click Launch Bus Editor.

  4. In the Bus Editor, in the left pane, select calPrms_T.

  5. On the Bus Editor toolbar, click the Create/Edit a Simulink.Parameter Object from a Bus Object button.

  6. In the MATLAB Editor, copy the generated MATLAB code and run the code at the command prompt. The code creates a Simulink.Parameter object in the base workspace.

  7. In the Model Explorer Model Hierarchy pane, select Base Workspace.

  8. Use the Model Explorer to move the parameter object, calPrms_T_Param, from the base workspace to the Design Data section of the data dictionary.

  9. With the data dictionary selected, in the Contents pane, rename the parameter object as calPrms.

  10. In the Model Data Editor, select the Parameters tab.

  11. Set the Change view drop-down list to Design.

  12. For the Gain block, replace the value 13.8900013 with calPrms.cal1.

  13. In the other Gain block, use calPrms.cal2.

  14. While editing the value of the other Gain block, next to calPrms.cal2, click the action button and select calPrms > Open.

  15. In the calPrms property dialog box, next to the Value box, click the action button and select Open Variable Editor.

  16. Use the Variable Editor to set the field values in the parameter object.

    • For the fields cal1 and cal2, use the numeric values that the Gain blocks in the model previously used.

    • For cal3, use a nonzero number such as 15.2299995.

    When you finish, close the Variable Editor.

  17. In the property dialog box, set Storage class to ExportedGlobal. Click OK.

  18. Use the Model Explorer to save the changes that you made to the dictionary.

Generate, Compile, and Inspect Code

  1. Configure the model to include ex_cc_algorithm.c in the build process. Set Configuration Parameters > Code Generation > Custom Code > Additional build information > Source files to ex_cc_algorithm.c.

  2. Generate code from the model.

  3. Inspect the generated file ex_struct_enum_integ.c. The file defines and initializes calPrms.

    /* Exported block parameters */
    calPrms_T calPrms = {
      13.8900013F,
      0.998300076F,
      15.23F
    } ;                                    /* Variable: calPrms
    

    The generated algorithm in the model step function defines a local variable for buffering the value of the signal err.

    err_T rtb_err;
    

    The algorithm then calculates and stores data in the fields of inSig.

    inSigs.err = rtb_err;
    inSigs.sig1 = (rtU.In2 + rtDW.DiscreteTimeIntegrator_DSTATE) * calPrms.cal1;
    inSigs.sig2 = (real32_T)(calPrms.cal2 * rtDW.DiscreteTimeIntegrator_DSTATE);
    

Replace Data Type Names Throughout Model

To generate code that uses float_32 instead of the default, real32_T, instead of manually specifying the data types of block output signals and bus elements, you can use data type replacement (Configuration Parameters > Code Generation > Data Type Replacement). For more information, see Replace and Rename Data Types to Conform to Coding Standards.

See Also

Related Topics