MATLAB Examples

Integrate C Function Whose Arguments Are Pointers to Structures

This example shows how to use the Legacy Code Tool to integrate a C function whose arguments are pointers to structures.

In Simulink®, create a Simulink.Bus object to represent a structure type. Use bus signals in a model to represent structured signals and states. Create MATLAB structures in a workspace or in a block parameter dialog box to represent parameter structures.

For basic information about bus signals, see docid:simulink_ug.bvevlbu. For basic information about parameter structures, see docid:simulink_ug.bsg3dn0-1. To create bus objects, see docid:simulink_ug.brin2jr-1.

Contents

Explore External Code

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

#include "ex_myTypes_LCT.h"

void myFcn(sigStructType *in, paramStructType *params, sigStructType *out)
{
    out->sig1 = in->sig1 * params->param1;
    out->sig2 = in->sig2 * params->param2 + params->param3;
}

The arguments of the function myFcn are pointers to structures. The function accepts an input signal argument, a parameter argument, and an output signal argument.

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

#ifndef _MY_TYPES_H_
#define _MY_TYPES_H_

typedef struct {
  double sig1;
  double sig2;
} sigStructType;

typedef struct {
  double param1;
  double param2;
  double param3;
} paramStructType;

#endif

The file defines the signal and parameter structure types that myFcn uses.

Create Bus Objects to Represent Structure Types in Simulink

At the command prompt, use the function Simulink.importExternalCTypes to generate bus objects in the base workspace.

Simulink.importExternalCTypes('ex_myTypes_LCT.h');

The bus objects correspond to the struct types that ex_myTypes_LCT.h defines.

Create Block to Execute External Code

Create a structure variable, def, to store the specifications for an S-function that calls the external code. Use the function legacy_code to create the structure and set default values.

def = legacy_code('initialize');

Set the name of the S-function to sfun_ex_mySrc_LCT.

def.SFunctionName = 'sfun_ex_mySrc_LCT';

Identify the external source and header files by their file names.

def.SourceFiles = {'ex_mySrc_LCT.c'};
def.HeaderFiles = {'ex_myTypes_LCT.h'};

Specify the prototype of the output function, which the model calls every simulation step, by copying the prototype of the external function myFcn. Set the names of the arguments to u1, p1, and y1 to represent the input argument, the parameter argument, and the output argument. Use the syntax [1] to specify that each argument is a pointer.

def.OutputFcnSpec = ['void myFcn(sigStructType u1[1], ',...
    'paramStructType p1[1], sigStructType y1[1])'];

Use the function legacy_code to create the S-function and the corresponding C MEX executable from the specification, def. Specify the option 'generate_for_sim' to prepare the S-function for normal and accelerated simulations.

legacy_code('generate_for_sim',def);
### Start Compiling sfun_ex_mySrc_LCT
    mex('-I/private/tmp/Bdoc17b_685977_71560/publish_examples9/tp3637ffe0/ex12763634', '-c', '-outdir', '/private/tmp/Bdoc17b_685977_71560/publish_examples9/tpa6bbec21_92dc_4277_a45e_7dd353d03738', '/private/tmp/Bdoc17b_685977_71560/publish_examples9/tp3637ffe0/ex12763634/ex_mySrc_LCT.c')
Building with 'Xcode with Clang'.
MEX completed successfully.
    mex('sfun_ex_mySrc_LCT.c', '-I/private/tmp/Bdoc17b_685977_71560/publish_examples9/tp3637ffe0/ex12763634', '/private/tmp/Bdoc17b_685977_71560/publish_examples9/tpa6bbec21_92dc_4277_a45e_7dd353d03738/ex_mySrc_LCT.o')
Building with 'Xcode with Clang'.
/private/tmp/Bdoc17b_685977_71560/publish_examples9/tp3637ffe0/ex12763634/sfun_ex_mySrc_LCT.c:417:9: warning: implicit declaration of function 'myFcn' is invalid in C99 [-Wimplicit-function-declaration]
        myFcn(__u1BUS, __p1BUS, __y1BUS);
        ^
1 warning generated.

MEX completed successfully.
### Finish Compiling sfun_ex_mySrc_LCT
### Exit

Create a masked S-Function block that calls the S-function during simulation.

legacy_code('slblock_generate', def);

The block appears in a new model.

To use the S-Function block in your model, create a bus signal of type sigStructType to use as the block input. The block output is also a bus signal. The block mask accepts a parameter, P1. To set the value of the parameter, use a MATLAB structure whose fields match those of the structure type paramStructType.

Verify Execution of External Code

Create a harness model that verifies the execution of the external code during simulation.

For an example, view the model ex_lct_struct.

open_system('ex_lct_struct')

In the Constant block dialog box, the Constant value parameter is set to a structure whose fields match those of the structure type sigStructType. On the Signal Attributes tab, Output data type is set to the bus object sigStructType.

The S-Function block calls the S-function sfun_ex_mySrc_LCT that you created. The output of the block enters a Bus Selector block, which extracts the signal elements sig1 and sig2.

The S-Function block accepts a parameter through the mask dialog box. Create a MATLAB structure structParam to use as the value of the parameter.

structParam = struct;
structParam.param1 = 15;
structParam.param2 = 20;
structParam.param3 = 5;

Optionally, use a Simulink.Parameter object to contain the structure. If you use a parameter object, you can set the data type of the structure by using the bus object paramStructType.

structParam = Simulink.Parameter(structParam);
structParam.DataType = 'Bus: paramStructType';

In the mask dialog box, set P1 to structParam.

set_param('ex_lct_struct/sfun_ex_mySrc_LCT','SParameter1','structParam')

Simulate the model. The Scope blocks show that the S-Function block calls the external function myFcn.

open_system('ex_lct_struct/Scope')
open_system('ex_lct_struct/Scope1')
sim('ex_lct_struct')